diff options
-rw-r--r-- | dhall/tests/common/mod.rs | 5 | ||||
-rw-r--r-- | dhall_core/src/core.rs | 67 | ||||
-rw-r--r-- | dhall_core/src/parser.rs | 22 | ||||
-rw-r--r-- | dhall_parser/src/dhall.pest.visibility | 1 |
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 |