summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock69
-rw-r--r--dhall/Cargo.toml3
-rw-r--r--dhall/src/binary.rs18
-rw-r--r--dhall/src/normalize.rs4
-rw-r--r--dhall/tests/macros.rs8
-rw-r--r--dhall/tests/tests.rs10
-rw-r--r--dhall_core/src/core.rs140
-rw-r--r--dhall_core/src/parser.rs43
-rw-r--r--dhall_parser/src/dhall.pest.visibility2
9 files changed, 254 insertions, 43 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 0c18bc6..6e218fb 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -18,6 +18,14 @@ dependencies = [
]
[[package]]
+name = "ansi_term"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "arrayref"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -47,6 +55,15 @@ version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "ctor"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.15.27 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "dhall"
version = "0.1.0"
dependencies = [
@@ -55,6 +72,7 @@ dependencies = [
"dhall_generator 0.1.0",
"itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lalrpop-util 0.16.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_cbor 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"term-painter 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -90,6 +108,11 @@ dependencies = [
]
[[package]]
+name = "difference"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "digest"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -162,6 +185,14 @@ dependencies = [
]
[[package]]
+name = "output_vt100"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "pest"
version = "2.1.0"
source = "git+https://github.com/pest-parser/pest#70b5ae08eb71c73077bdc29827f2939ea8d7a4a5"
@@ -208,6 +239,17 @@ dependencies = [
]
[[package]]
+name = "pretty_assertions"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ctor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "output_vt100 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "proc-macro2"
version = "0.4.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -307,17 +349,39 @@ version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "winapi"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "winapi-build"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
[metadata]
"checksum abnf 0.1.1 (git+https://github.com/Nadrieril/abnf)" = "<none>"
+"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
"checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee"
"checksum block-buffer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a076c298b9ecdb530ed9d967e74a6027d6a7478924520acddcddc24c1c8ab3ab"
"checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40"
"checksum bytecount 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be0fdd54b507df8f22012890aadd099979befdba27713c767993f8380112ca7c"
"checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb"
+"checksum ctor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9a43db2bba5cafdc6aa068c892a518e477ee0df3705e53ec70247a9ff93546d5"
+"checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
"checksum digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "03b072242a8cbaf9c145665af9d250c59af3b958f83ed6824e13533cf76d5b90"
"checksum either 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c67353c641dc847124ea1902d69bd753dee9bb3beff9aa3662ecf86c971d1fac"
"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
@@ -329,11 +393,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum maplit 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08cbb6b4fef96b6d77bfc40ec491b1690c779e77b05cd9f07f787ed376fd4c43"
"checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39"
"checksum nom 4.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4836e9d6036552017e107edc598c97b2dee245161ff1b1ad4af215004774b354"
+"checksum output_vt100 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53cdc5b785b7a58c5aad8216b3dfa114df64b0b06ae6e1501cef91df2fbdf8f9"
"checksum pest 2.1.0 (git+https://github.com/pest-parser/pest)" = "<none>"
"checksum pest 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "54f0c72a98d8ab3c99560bfd16df8059cc10e1f9a8e83e6e3b97718dd766e9c3"
"checksum pest_generator 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "63120576c4efd69615b5537d3d052257328a4ca82876771d6944424ccfd9f646"
"checksum pest_meta 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f5a3492a4ed208ffc247adcdcc7ba2a95be3104f58877d0d02f0df39bf3efb5e"
"checksum pretty 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f60c0d9f6fc88ecdd245d90c1920ff76a430ab34303fc778d33b1d0a4c3bf6d3"
+"checksum pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f81e1644e1b54f5a68959a29aa86cde704219254669da328ecfdf6a1f09d427"
"checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915"
"checksum quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1"
"checksum serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)" = "92514fb95f900c9b5126e32d020f5c6d40564c27a5ea6d1d7d9f157a96623560"
@@ -348,4 +414,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
+"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
+"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
diff --git a/dhall/Cargo.toml b/dhall/Cargo.toml
index 12622f8..fd462b1 100644
--- a/dhall/Cargo.toml
+++ b/dhall/Cargo.toml
@@ -15,3 +15,6 @@ term-painter = "0.2.3"
serde_cbor = "0.9.0"
dhall_core = { path = "../dhall_core" }
dhall_generator = { path = "../dhall_generator" }
+
+[dev-dependencies]
+pretty_assertions = "0.6.1"
diff --git a/dhall/src/binary.rs b/dhall/src/binary.rs
index 0f09987..6d0f1e9 100644
--- a/dhall/src/binary.rs
+++ b/dhall/src/binary.rs
@@ -160,9 +160,21 @@ fn cbor_value_to_dhall(data: &cbor::Value) -> Result<ParsedExpr, DecodeError> {
[U64(15), U64(x)] => Ok(NaturalLit(*x as Natural)),
[U64(16), U64(x)] => Ok(IntegerLit(*x as Integer)),
[U64(16), I64(x)] => Ok(IntegerLit(*x as Integer)),
- [U64(18), String(first), _rest..] => {
- // TODO: interpolated string
- Ok(TextLit(first.clone()))
+ [U64(18), String(first), rest..] => {
+ Ok(TextLit(InterpolatedText::from((
+ first.clone(),
+ rest.iter()
+ .tuples()
+ .map(|(x, y)| {
+ let x = cbor_value_to_dhall(&x)?;
+ let y = match y {
+ String(s) => s.clone(),
+ _ => Err(DecodeError::WrongFormatError)?,
+ };
+ Ok((x, y))
+ })
+ .collect::<Result<_, _>>()?,
+ ))))
}
[U64(25), bindings..] => {
let mut tuples = bindings.iter().tuples();
diff --git a/dhall/src/normalize.rs b/dhall/src/normalize.rs
index 50a1625..5003ccd 100644
--- a/dhall/src/normalize.rs
+++ b/dhall/src/normalize.rs
@@ -42,7 +42,7 @@ where
(NaturalEven, NaturalLit(n)) => BoolLit(n % 2 == 0),
(NaturalOdd, NaturalLit(n)) => BoolLit(n % 2 != 0),
(NaturalToInteger, NaturalLit(n)) => IntegerLit(n as isize),
- (NaturalShow, NaturalLit(n)) => TextLit(n.to_string()),
+ (NaturalShow, NaturalLit(n)) => TextLit(n.to_string().into()),
(b, App(f, x)) => match (b, normalize_whnf(&f), x) {
// fold/build fusion for `Natural`
@@ -202,7 +202,7 @@ where
(BoolNE, BoolLit(x), BoolLit(y)) => BoolLit(x != y),
(NaturalPlus, NaturalLit(x), NaturalLit(y)) => NaturalLit(x + y),
(NaturalTimes, NaturalLit(x), NaturalLit(y)) => NaturalLit(x * y),
- (TextAppend, TextLit(x), TextLit(y)) => TextLit(x + &y),
+ (TextAppend, TextLit(x), TextLit(y)) => TextLit(x + y),
(ListAppend, ListLit(t1, xs), ListLit(t2, ys)) => {
// Drop type annotation if the result is nonempty
let t = if xs.is_empty() && ys.is_empty() {
diff --git a/dhall/tests/macros.rs b/dhall/tests/macros.rs
index 1d90e87..4109f84 100644
--- a/dhall/tests/macros.rs
+++ b/dhall/tests/macros.rs
@@ -1,5 +1,7 @@
+use pretty_assertions::assert_eq as assert_eq_pretty;
+
#[macro_export]
-macro_rules! assert_eq_ {
+macro_rules! assert_eq_display {
($left:expr, $right:expr) => {{
match (&$left, &$right) {
(left_val, right_val) => {
@@ -104,7 +106,7 @@ pub fn run_test(base_path: &str, feature: Feature, expected: ExpectedResult) {
let expected = dhall::binary::decode(&data).unwrap();
let expected = dhall::imports::panic_imports(&expected);
- assert_eq!(expr, expected);
+ assert_eq_pretty!(expr, expected);
}
(Feature::Parser, ExpectedResult::Failure) => {
let file_path = base_path.to_owned() + ".dhall";
@@ -120,7 +122,7 @@ pub fn run_test(base_path: &str, feature: Feature, expected: ExpectedResult) {
let expr = read_dhall_file(&expr_file_path).unwrap();
let expected = read_dhall_file(&expected_file_path).unwrap();
- assert_eq_!(
+ assert_eq_display!(
normalize::<_, X, _>(&expr),
normalize::<_, X, _>(&expected)
);
diff --git a/dhall/tests/tests.rs b/dhall/tests/tests.rs
index 51df149..24e8aa4 100644
--- a/dhall/tests/tests.rs
+++ b/dhall/tests/tests.rs
@@ -179,15 +179,15 @@ make_spec_test!(parser, spec_parser_success_builtins, "parser/success/builtins")
make_spec_test!(parser, spec_parser_success_doubleQuotedString, "parser/success/doubleQuotedString");
// make_spec_test!(parser, spec_parser_success_environmentVariables, "parser/success/environmentVariables");
// make_spec_test!(parser, spec_parser_success_escapedDoubleQuotedString, "parser/success/escapedDoubleQuotedString");
-// make_spec_test!(parser, spec_parser_success_escapedSingleQuotedString, "parser/success/escapedSingleQuotedString");
+make_spec_test!(parser, spec_parser_success_escapedSingleQuotedString, "parser/success/escapedSingleQuotedString");
make_spec_test!(parser, spec_parser_success_fields, "parser/success/fields");
make_spec_test!(parser, spec_parser_success_forall, "parser/success/forall");
make_spec_test!(parser, spec_parser_success_functionType, "parser/success/functionType");
make_spec_test!(parser, spec_parser_success_identifier, "parser/success/identifier");
make_spec_test!(parser, spec_parser_success_ifThenElse, "parser/success/ifThenElse");
// make_spec_test!(parser, spec_parser_success_importAlt, "parser/success/importAlt");
-// make_spec_test!(parser, spec_parser_success_interpolatedDoubleQuotedString, "parser/success/interpolatedDoubleQuotedString");
-// make_spec_test!(parser, spec_parser_success_interpolatedSingleQuotedString, "parser/success/interpolatedSingleQuotedString");
+make_spec_test!(parser, spec_parser_success_interpolatedDoubleQuotedString, "parser/success/interpolatedDoubleQuotedString");
+make_spec_test!(parser, spec_parser_success_interpolatedSingleQuotedString, "parser/success/interpolatedSingleQuotedString");
make_spec_test!(parser, spec_parser_success_label, "parser/success/label");
make_spec_test!(parser, spec_parser_success_lambda, "parser/success/lambda");
// make_spec_test!(parser, spec_parser_success_largeExpression, "parser/success/largeExpression");
@@ -206,9 +206,9 @@ make_spec_test!(parser, spec_parser_success_operators, "parser/success/operators
// make_spec_test!(parser, spec_parser_success_quotedPaths, "parser/success/quotedPaths");
make_spec_test!(parser, spec_parser_success_record, "parser/success/record");
make_spec_test!(parser, spec_parser_success_reservedPrefix, "parser/success/reservedPrefix");
-// make_spec_test!(parser, spec_parser_success_singleQuotedString, "parser/success/singleQuotedString");
+make_spec_test!(parser, spec_parser_success_singleQuotedString, "parser/success/singleQuotedString");
make_spec_test!(parser, spec_parser_success_sort, "parser/success/sort");
-// make_spec_test!(parser, spec_parser_success_template, "parser/success/template");
+make_spec_test!(parser, spec_parser_success_template, "parser/success/template");
make_spec_test!(parser, spec_parser_success_unicodeComment, "parser/success/unicodeComment");
make_spec_test!(parser, spec_parser_success_unicodeDoubleQuotedString, "parser/success/unicodeDoubleQuotedString");
// make_spec_test!(parser, spec_parser_success_unicodePaths, "parser/success/unicodePaths");
diff --git a/dhall_core/src/core.rs b/dhall_core/src/core.rs
index b3ba142..8ce9715 100644
--- a/dhall_core/src/core.rs
+++ b/dhall_core/src/core.rs
@@ -1,6 +1,8 @@
#![allow(non_snake_case)]
use std::collections::BTreeMap;
use std::fmt::{self, Display};
+use std::iter::FromIterator;
+use std::ops::Add;
use std::path::PathBuf;
use std::rc::Rc;
@@ -171,6 +173,112 @@ pub enum BinOp {
ListAppend,
}
+#[derive(Debug, Clone, PartialEq)]
+pub struct InterpolatedText<Note, Embed> {
+ head: String,
+ tail: Vec<(Expr<Note, Embed>, String)>,
+}
+
+impl<N, E> From<(String, Vec<(Expr<N, E>, String)>)>
+ for InterpolatedText<N, E>
+{
+ fn from(x: (String, Vec<(Expr<N, E>, String)>)) -> Self {
+ InterpolatedText {
+ head: x.0,
+ tail: x.1,
+ }
+ }
+}
+
+impl<N, E> From<String> for InterpolatedText<N, E> {
+ fn from(s: String) -> Self {
+ InterpolatedText {
+ head: s,
+ tail: vec![],
+ }
+ }
+}
+
+// TODO: merge both when we move to Rc<>
+// This one is needed when parsing, because we need to own the Expr
+pub enum OwnedInterpolatedTextContents<'a, Note, Embed> {
+ Text(&'a str),
+ Expr(Expr<Note, Embed>),
+}
+
+// This one is needed everywhere else, because we don't want Clone traits bounds
+// everywhere
+pub enum BorrowedInterpolatedTextContents<'a, Note, Embed> {
+ Text(&'a str),
+ Expr(&'a Expr<Note, Embed>),
+}
+
+impl<'a, N: Clone + 'a, E: Clone + 'a> BorrowedInterpolatedTextContents<'a, N, E> {
+ pub fn to_owned(self) -> OwnedInterpolatedTextContents<'a, N, E> {
+ match self {
+ BorrowedInterpolatedTextContents::Text(s) => OwnedInterpolatedTextContents::Text(s),
+ BorrowedInterpolatedTextContents::Expr(e) => OwnedInterpolatedTextContents::Expr(e.clone()),
+ }
+ }
+}
+
+impl<N, E> InterpolatedText<N, E> {
+ pub fn map<N2, E2, F>(&self, mut f: F) -> InterpolatedText<N2, E2>
+ where
+ F: FnMut(&Expr<N, E>) -> Expr<N2, E2>,
+ {
+ InterpolatedText {
+ head: self.head.clone(),
+ tail: self.tail.iter().map(|(e, s)| (f(e), s.clone())).collect(),
+ }
+ }
+
+ pub fn iter(&self) -> impl Iterator<Item = BorrowedInterpolatedTextContents<N, E>> {
+ use std::iter::once;
+ once(BorrowedInterpolatedTextContents::Text(self.head.as_ref())).chain(
+ self.tail.iter().flat_map(|(e, s)| {
+ once(BorrowedInterpolatedTextContents::Expr(e))
+ .chain(once(BorrowedInterpolatedTextContents::Text(s)))
+ }),
+ )
+ }
+}
+
+impl<'a, N: Clone + 'a, E: Clone + 'a>
+ FromIterator<OwnedInterpolatedTextContents<'a, N, E>>
+ for InterpolatedText<N, E>
+{
+ fn from_iter<T>(iter: T) -> Self
+ where
+ T: IntoIterator<Item = OwnedInterpolatedTextContents<'a, N, E>>,
+ {
+ let mut res = InterpolatedText {
+ head: "".to_owned(),
+ tail: vec![],
+ };
+ // let mut empty_string = "".to_owned();
+ let mut crnt_str = &mut res.head;
+ for x in iter.into_iter() {
+ match x {
+ OwnedInterpolatedTextContents::Text(s) => crnt_str.push_str(s),
+ OwnedInterpolatedTextContents::Expr(e) => {
+ // crnt_str = &mut empty_string;
+ res.tail.push((e.clone(), "".to_owned()));
+ crnt_str = &mut res.tail.last_mut().unwrap().1;
+ }
+ }
+ }
+ res
+ }
+}
+
+impl<N: Clone, E: Clone> Add for InterpolatedText<N, E> {
+ type Output = InterpolatedText<N, E>;
+ fn add(self, rhs: InterpolatedText<N, E>) -> Self::Output {
+ self.iter().chain(rhs.iter()).map(BorrowedInterpolatedTextContents::to_owned).collect()
+ }
+}
+
/// Syntax tree for expressions
#[derive(Debug, Clone, PartialEq)]
pub enum Expr<Note, Embed> {
@@ -215,7 +323,7 @@ pub enum Expr<Note, Embed> {
/// `DoubleLit n ~ n`
DoubleLit(Double),
/// `TextLit t ~ t`
- TextLit(Builder),
+ TextLit(InterpolatedText<Note, Embed>),
/// `ListLit t [x, y, z] ~ [x, y, z] : List t`
ListLit(Option<Box<Expr<Note, Embed>>>, Vec<Expr<Note, Embed>>),
/// `OptionalLit t [e] ~ [e] : Optional t`
@@ -358,13 +466,6 @@ impl<S, A> Expr<S, A> {
_ => None,
}
}
-
- pub fn text_lit(&self) -> Option<String> {
- match *self {
- Expr::TextLit(ref t) => Some(t.clone()), // FIXME?
- _ => None,
- }
- }
}
impl<S: Clone, A: Clone> Expr<S, Expr<S, A>> {
@@ -570,7 +671,21 @@ impl<S, A: Display> Expr<S, A> {
a.fmt(f)
}
&DoubleLit(a) => a.fmt(f),
- &TextLit(ref a) => <String as fmt::Debug>::fmt(a, f), // FIXME Format with Haskell escapes
+ &TextLit(ref a) => {
+ for x in a.iter() {
+ match x {
+ BorrowedInterpolatedTextContents::Text(a) => {
+ <str as fmt::Debug>::fmt(a, f)?
+ } // TODO Format escapes properly
+ BorrowedInterpolatedTextContents::Expr(e) => {
+ f.write_str("${")?;
+ e.fmt(f)?;
+ f.write_str("}")?;
+ }
+ }
+ }
+ Ok(())
+ }
&Record(ref a) if a.is_empty() => f.write_str("{}"),
&Record(ref a) => fmt_list("{ ", " }", a, f, |(k, t), f| {
write!(f, "{} : {}", k, t)
@@ -724,7 +839,6 @@ where
Expr::App(bx(f.into()), bx(x.into()))
}
-pub type Builder = String;
pub type Double = f64;
pub type Int = isize;
pub type Integer = isize;
@@ -788,7 +902,7 @@ where
NaturalLit(n) => NaturalLit(n),
IntegerLit(n) => IntegerLit(n),
DoubleLit(n) => DoubleLit(n),
- TextLit(ref t) => TextLit(t.clone()),
+ TextLit(ref t) => TextLit(t.map(|e| map(e))),
BinOp(o, ref x, ref y) => BinOp(o, bxmap(x), bxmap(y)),
ListLit(ref t, ref es) => {
let es = es.iter().map(&map).collect();
@@ -972,7 +1086,7 @@ pub fn shift<S, T, A: Clone>(d: isize, v: &V, e: &Expr<S, A>) -> Expr<T, A> {
NaturalLit(a) => NaturalLit(*a),
IntegerLit(a) => IntegerLit(*a),
DoubleLit(a) => DoubleLit(*a),
- TextLit(a) => TextLit(a.clone()),
+ TextLit(a) => TextLit(a.map(|e| shift(d, v, e))),
ListLit(t, es) => ListLit(
t.as_ref().map(|t| bx(shift(d, v, t))),
es.iter().map(|e| shift(d, v, e)).collect(),
@@ -1075,7 +1189,7 @@ where
NaturalLit(a) => NaturalLit(*a),
IntegerLit(a) => IntegerLit(*a),
DoubleLit(a) => DoubleLit(*a),
- TextLit(a) => TextLit(a.clone()),
+ TextLit(a) => TextLit(a.map(|b| subst(v, e, b))),
ListLit(a, b) => {
let a2 = a.as_ref().map(|a| bx(subst(v, e, a)));
let b2 = b.iter().map(|be| subst(v, e, be)).collect();
diff --git a/dhall_core/src/parser.rs b/dhall_core/src/parser.rs
index 57dd151..ddf3f8f 100644
--- a/dhall_core/src/parser.rs
+++ b/dhall_core/src/parser.rs
@@ -14,6 +14,8 @@ use crate::core::*;
// are here and hopefully you can figure out how they work.
pub type ParsedExpr = Expr<X, Import>;
+pub type ParsedText = InterpolatedText<X, Import>;
+pub type ParsedTextContents<'a> = OwnedInterpolatedTextContents<'a, X, Import>;
pub type BoxExpr = Box<ParsedExpr>;
pub type ParseError = pest::error::Error<Rule>;
@@ -426,17 +428,25 @@ named!(raw_str<&'a str>; captured_str!(s) => s);
named!(label<Label>; captured_str!(s) => Label::from(s.trim().to_owned()));
-// TODO: parse escapes and interpolation
-rule!(double_quote_literal<String>;
- children!(strs*: raw_str) => {
- strs.collect()
+rule!(double_quote_literal<ParsedText>;
+ children!(chunks*: double_quote_chunk) => {
+ chunks.collect()
}
);
-rule!(single_quote_literal<String>;
+// TODO: parse escapes
+rule!(double_quote_chunk<ParsedTextContents<'a>>;
+ children!(c: interpolation) => {
+ OwnedInterpolatedTextContents::Expr(*c)
+ },
+ captured_str!(s) => {
+ OwnedInterpolatedTextContents::Text(s)
+ },
+);
+
+rule!(single_quote_literal<ParsedText>;
children!(eol: raw_str, contents: single_quote_continue) => {
- contents.push(eol);
- contents.into_iter().rev().collect()
+ contents.into_iter().rev().collect::<ParsedText>()
}
);
rule!(escaped_quote_pair<&'a str>;
@@ -445,21 +455,22 @@ rule!(escaped_quote_pair<&'a str>;
rule!(escaped_interpolation<&'a str>;
children!() => "${"
);
+rule!(interpolation<BoxExpr>;
+ children!(e: expression) => e
+);
-rule!(single_quote_continue<Vec<&'a str>>;
- // TODO: handle interpolation
- // children!(c: expression, rest: single_quote_continue) => {
- // rest.push(c); rest
- // },
+rule!(single_quote_continue<Vec<ParsedTextContents<'a>>>;
+ children!(c: interpolation, rest: single_quote_continue) => {
+ rest.push(OwnedInterpolatedTextContents::Expr(*c)); rest
+ },
children!(c: escaped_quote_pair, rest: single_quote_continue) => {
- rest.push(c); rest
+ rest.push(OwnedInterpolatedTextContents::Text(c)); rest
},
children!(c: escaped_interpolation, rest: single_quote_continue) => {
- rest.push(c); rest
+ rest.push(OwnedInterpolatedTextContents::Text(c)); rest
},
- // capture interpolation as string
children!(c: raw_str, rest: single_quote_continue) => {
- rest.push(c); rest
+ rest.push(OwnedInterpolatedTextContents::Text(c)); rest
},
children!() => {
vec![]
diff --git a/dhall_parser/src/dhall.pest.visibility b/dhall_parser/src/dhall.pest.visibility
index 5dcaa19..8c0e67d 100644
--- a/dhall_parser/src/dhall.pest.visibility
+++ b/dhall_parser/src/dhall.pest.visibility
@@ -21,7 +21,7 @@ simple_label
quoted_label
label_raw
label
-# double_quote_chunk
+double_quote_chunk
double_quote_literal
single_quote_continue
single_quote_literal