summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dhall/tests/common/mod.rs5
-rw-r--r--dhall_core/src/core.rs67
-rw-r--r--dhall_core/src/parser.rs22
-rw-r--r--dhall_parser/src/dhall.pest.visibility1
4 files changed, 74 insertions, 21 deletions
diff --git a/dhall/tests/common/mod.rs b/dhall/tests/common/mod.rs
index d18b4bf..a24125e 100644
--- a/dhall/tests/common/mod.rs
+++ b/dhall/tests/common/mod.rs
@@ -89,6 +89,11 @@ pub fn run_test(base_path: &str, feature: Feature) {
let expected = dhall::imports::panic_imports(&expected);
assert_eq_pretty!(expr, expected);
+
+ // Round-trip pretty-printer
+ let expr = parser::parse_expr(&expr.to_string()).unwrap();
+ let expr = dhall::imports::panic_imports(&expr);
+ assert_eq!(expr, expected);
}
ParserFailure => {
let file_path = base_path + ".dhall";
diff --git a/dhall_core/src/core.rs b/dhall_core/src/core.rs
index 722506b..32f9c85 100644
--- a/dhall_core/src/core.rs
+++ b/dhall_core/src/core.rs
@@ -534,7 +534,7 @@ impl<S, A: Display> Expr<S, A> {
&Let(ref a, None, ref c, ref d) => {
write!(f, "let {} = ", a)?;
c.fmt(f)?;
- write!(f, ") → ")?;
+ write!(f, " in ")?;
d.fmt_b(f)
}
&Let(ref a, Some(ref b), ref c, ref d) => {
@@ -542,7 +542,7 @@ impl<S, A: Display> Expr<S, A> {
b.fmt(f)?;
write!(f, " = ")?;
c.fmt(f)?;
- write!(f, ") → ")?;
+ write!(f, " in ")?;
d.fmt_b(f)
}
&EmptyListLit(ref t) => {
@@ -550,17 +550,20 @@ impl<S, A: Display> Expr<S, A> {
t.fmt_e(f)
}
&NEListLit(ref es) => {
- fmt_list("[", "]", es, f, |e, f| e.fmt(f))
+ fmt_list("[", ", ", "]", es, f, |e, f| e.fmt(f))
}
&OptionalLit(ref t, ref es) => {
match es {
None => {
- write!(f, "None ")?;
+ // TODO: use None when parsing fixed
+ write!(f, "[] : Optional ")?;
t.as_ref().unwrap().fmt_e(f)?;
}
Some(e) => {
- write!(f, "Some ")?;
+ // TODO: use Some when parsing fixed
+ write!(f, "[ ")?;
e.fmt_e(f)?;
+ write!(f, " ]")?;
if let Some(t) = t {
write!(f, " : Optional ")?;
t.fmt_e(f)?;
@@ -594,6 +597,7 @@ impl<S, A: Display> Expr<S, A> {
match self {
// FIXME precedence
&BinOp(op, ref a, ref b) => {
+ write!(f, "(")?;
a.fmt_d(f)?;
write!(
f,
@@ -603,17 +607,18 @@ impl<S, A: Display> Expr<S, A> {
TextAppend => "++",
NaturalPlus => "+",
BoolAnd => "&&",
- Combine => "^",
+ Combine => "/\\",
NaturalTimes => "*",
BoolEQ => "==",
BoolNE => "!=",
- CombineTypes => "//\\",
+ CombineTypes => "//\\\\",
ImportAlt => "?",
Prefer => "//",
ListAppend => "#",
}
)?;
- b.fmt_c(f)
+ b.fmt_c(f)?;
+ write!(f, ")")
}
&Note(_, ref b) => b.fmt_c(f),
a => a.fmt_d(f),
@@ -656,37 +661,58 @@ impl<S, A: Display> Expr<S, A> {
&Builtin(v) => v.fmt(f),
&BoolLit(true) => f.write_str("True"),
&BoolLit(false) => f.write_str("False"),
- &IntegerLit(a) => a.fmt(f),
- &NaturalLit(a) => {
+ &NaturalLit(a) => a.fmt(f),
+ &IntegerLit(a) if *a >= 0 => {
f.write_str("+")?;
a.fmt(f)
}
+ &IntegerLit(a) => a.fmt(f),
&DoubleLit(a) => a.fmt(f),
&TextLit(ref a) => {
+ f.write_str("\"")?;
for x in a.iter() {
match x {
InterpolatedTextContents::Text(a) => {
- <str as fmt::Debug>::fmt(a, f)?
- } // TODO Format escapes properly
+ // TODO Format all escapes properly
+ f.write_str(
+ &a.replace("\n", "\\n")
+ .replace("\t", "\\t")
+ .replace("\r", "\\r")
+ .replace("\"", "\\\""),
+ )?;
+ }
InterpolatedTextContents::Expr(e) => {
- f.write_str("${")?;
+ f.write_str("${ ")?;
e.fmt(f)?;
- f.write_str("}")?;
+ f.write_str(" }")?;
}
}
}
+ f.write_str("\"")?;
Ok(())
}
&Record(ref a) if a.is_empty() => f.write_str("{}"),
- &Record(ref a) => fmt_list("{ ", " }", a, f, |(k, t), f| {
+ &Record(ref a) => fmt_list("{ ", ", ", " }", a, f, |(k, t), f| {
write!(f, "{} : {}", k, t)
}),
&RecordLit(ref a) if a.is_empty() => f.write_str("{=}"),
- &RecordLit(ref a) => fmt_list("{ ", " }", a, f, |(k, v), f| {
- write!(f, "{} = {}", k, v)
+ &RecordLit(ref a) => {
+ fmt_list("{ ", ", ", " }", a, f, |(k, v), f| {
+ write!(f, "{} = {}", k, v)
+ })
+ }
+ &Union(ref a) => fmt_list("< ", " | ", " >", a, f, |(k, v), f| {
+ write!(f, "{} : {}", k, v)
}),
- &Union(ref _a) => f.write_str("Union"),
- &UnionLit(ref _a, ref _b, ref _c) => f.write_str("UnionLit"),
+ &UnionLit(ref a, ref b, ref c) => {
+ f.write_str("< ")?;
+ write!(f, "{} = {}", a, b)?;
+ for (k, v) in c {
+ f.write_str(" | ")?;
+ write!(f, "{} : {}", k, v)?;
+ }
+ f.write_str(" >")
+ }
&Embed(ref a) => a.fmt(f),
&Note(_, ref b) => b.fmt_f(f),
a => write!(f, "({})", a),
@@ -696,6 +722,7 @@ impl<S, A: Display> Expr<S, A> {
fn fmt_list<T, I, F>(
open: &str,
+ sep: &str,
close: &str,
it: I,
f: &mut fmt::Formatter,
@@ -708,7 +735,7 @@ where
f.write_str(open)?;
for (i, x) in it.into_iter().enumerate() {
if i > 0 {
- f.write_str(", ")?;
+ f.write_str(sep)?;
}
func(x, f)?;
}
diff --git a/dhall_core/src/parser.rs b/dhall_core/src/parser.rs
index 6809aa2..6f84abe 100644
--- a/dhall_core/src/parser.rs
+++ b/dhall_core/src/parser.rs
@@ -435,15 +435,35 @@ rule!(double_quote_literal<ParsedText>;
}
);
-// TODO: parse escapes
rule!(double_quote_chunk<ParsedTextContents<'a>>;
children!(c: interpolation) => {
InterpolatedTextContents::Expr(c)
},
+ children!(s: double_quote_escaped) => {
+ InterpolatedTextContents::Text(s)
+ },
captured_str!(s) => {
InterpolatedTextContents::Text(s)
},
);
+rule!(double_quote_escaped<&'a str>;
+ // TODO: parse all escapes
+ captured_str!(s) => {
+ match s {
+ "\"" => "\"",
+ "$" => "$",
+ "\\" => "\\",
+ "/" => "/",
+ // "b" => "\b",
+ // "f" => "\f",
+ "n" => "\n",
+ "r" => "\r",
+ "t" => "\t",
+ // "uXXXX"
+ _ => unimplemented!(),
+ }
+ }
+);
rule!(single_quote_literal<ParsedText>;
children!(eol: raw_str, contents: single_quote_continue) => {
diff --git a/dhall_parser/src/dhall.pest.visibility b/dhall_parser/src/dhall.pest.visibility
index 8c0e67d..5913d91 100644
--- a/dhall_parser/src/dhall.pest.visibility
+++ b/dhall_parser/src/dhall.pest.visibility
@@ -22,6 +22,7 @@ quoted_label
label_raw
label
double_quote_chunk
+double_quote_escaped
double_quote_literal
single_quote_continue
single_quote_literal