Repository: gluon-lang/gluon
Pull request #309 (2017-07-05 20:08:53)

Format fixes
Partial fix for #307 . Still work to do to handle comments properly but this should be a nice improvement


Patch:
diff --git a/TUTORIAL.md b/TUTORIAL.md
index 609d01e3..0d9a9fd4 100644
--- a/TUTORIAL.md
+++ b/TUTORIAL.md
@@ -333,7 +333,7 @@ let module =
     let id x = x
     in
     type MyInt = Int
-    in { id, pi = 3.14 }
+    in { MyInt, id, pi = 3.14 }
 in
 module.id module.pi
 ```
diff --git a/base/src/pretty_print.rs b/base/src/pretty_print.rs
index dc3ff323..df8edbb6 100644
--- a/base/src/pretty_print.rs
+++ b/base/src/pretty_print.rs
@@ -3,10 +3,10 @@ use std::iter::{once, repeat};
 use itertools::{Either, Itertools};
 use pretty::{Arena, DocAllocator, DocBuilder};
 
-use ast::{Expr, Comment, CommentType, is_operator_char, Literal, Pattern, SpannedExpr,
-          SpannedPattern, ValueBinding};
+use ast::{Expr, Comment, CommentType, is_operator_char, Pattern, SpannedExpr, SpannedPattern,
+          ValueBinding};
 use kind::Kind;
-use pos::{BytePos, Line, Span};
+use pos::{BytePos, Span};
 use source::Source;
 use types::{Prec, Type, pretty_print as pretty_type};
 
@@ -164,7 +164,13 @@ where
 
 macro_rules! newlines_iter {
     ($self_: ident, $iterable: expr) => {
-        $iterable.into_iter().tuple_windows().map(|(prev, next)| $self_.newlines(prev.end, next.start))
+        $iterable.into_iter().tuple_windows().map(|(prev, next)| $self_.comments(Span::new(prev.end, next.start)))
+    }
+}
+
+macro_rules! rev_newlines_iter {
+    ($self_: ident, $iterable: expr) => {
+        $iterable.into_iter().tuple_windows().map(|(prev, next)| $self_.rev_comments(Span::new(prev.end, next.start)))
     }
 }
 
@@ -194,26 +200,78 @@ impl<'a> ExprPrinter<'a> {
             .collect()
     }
 
+    fn space(&'a self, span: Span<BytePos>) -> DocBuilder<'a, Arena<'a>> {
+        self.whitespace(span, self.arena.space())
+    }
+
+    fn whitespace(
+        &'a self,
+        span: Span<BytePos>,
+        default: DocBuilder<'a, Arena<'a>>,
+    ) -> DocBuilder<'a, Arena<'a>> {
+        let arena = &self.arena;
+        let (doc, count) = self.comments_count(span);
+        if doc.1 == arena.nil().1 {
+            default
+        } else if count == 0 {
+            // No comments, only newlines from the iterator
+            doc
+        } else {
+            arena.space().append(doc).append(arena.space())
+        }
+    }
+
+    fn comments(&'a self, span: Span<BytePos>) -> DocBuilder<'a, Arena<'a>> {
+        self.comments_count(span).0
+    }
+    fn comments_count(&'a self, span: Span<BytePos>) -> (DocBuilder<'a, Arena<'a>>, usize) {
+        let arena = &self.arena;
+        let mut comments = 0;
+        let doc = arena.concat(self.source.comments_between(span).map(
+            |comment| if comment.is_empty() {
+                arena.newline()
+            } else {
+                comments += 1;
+                if comment.starts_with("//") {
+                    arena.text(comment).append(arena.newline())
+                } else {
+                    arena.text(comment)
+                }
+            },
+        ));
+        (doc, comments)
+    }
 
-    fn newlines(&'a self, prev: BytePos, next: BytePos) -> DocBuilder<'a, Arena<'a>> {
+    fn rev_comments(&'a self, span: Span<BytePos>) -> DocBuilder<'a, Arena<'a>> {
         let arena = &self.arena;
-        let prev_line = self.source.line_number_at_byte(prev);
-        let next_line = self.source.line_number_at_byte(next);
-        // Record expressions
-        let empty_lines = (prev_line.to_usize()..next_line.to_usize())
-            .map(|l| {
-                self.source.line(Line::from(l)).unwrap().1.trim().is_empty()
+        self.source
+            .comments_between(span)
+            .rev()
+            .map(|comment| {
+                chain![arena;
+                            if comment.is_empty() {
+                                arena.nil()
+                            } else {
+                                arena.text("// ").append(comment)
+                            },
+                            arena.newline()
+                        ]
             })
-            .count();
-        arena.concat(repeat(arena.newline()).take(empty_lines))
+            .fold(arena.nil(), |acc, doc| doc.append(acc))
     }
 
     pub fn pretty_expr<Id>(&'a self, expr: &'a SpannedExpr<Id>) -> DocBuilder<'a, Arena<'a>>
     where
         Id: AsRef<str>,
     {
-        self.pretty_expr_(BytePos::from(0), expr)
+        self.pretty_expr_(BytePos::from(0), expr).append(
+            self.comments(Span::new(
+                expr.span.end,
+                BytePos::from(self.source.src().len()),
+            )),
+        )
     }
+
     pub fn pretty_expr_<Id>(
         &'a self,
         previous_end: BytePos,
@@ -226,14 +284,17 @@ impl<'a> ExprPrinter<'a> {
 
         let pretty = |next: &'a SpannedExpr<_>| self.pretty_expr_(next.span.start, next);
 
+        let comments = self.comments(Span::new(previous_end, expr.span.start));
         let doc = match expr.value {
             Expr::App(ref func, ref args) => {
+                let arg_iter = once(&**func).chain(args).tuple_windows().map(
+                    |(prev, arg)| {
+                        self.space(Span::new(prev.span.end, arg.span.start))
+                            .append(pretty(arg))
+                    },
+                );
                 pretty(func)
-                    .append(
-                        arena
-                            .concat(args.iter().map(|arg| arena.space().append(pretty(arg))))
-                            .nest(INDENT),
-                    )
+                    .append(arena.concat(arg_iter).nest(INDENT))
                     .group()
             }
             Expr::Array(ref array) => {
@@ -324,18 +385,13 @@ impl<'a> ExprPrinter<'a> {
                     arena.concat(prefixes.zip(binds).map(|(prefix, bind)| {
                         binding(prefix, bind)
                     }).interleave(newlines_iter!(self, binds.iter().map(|bind| bind.span())))),
-                    self.newlines(binds.last().unwrap().expr.span.end, body.span.start),
-                    pretty(body).group()
+                    self.pretty_expr_(binds.last().unwrap().span().end, body).group()
                 ]
             }
-            Expr::Literal(ref literal) => {
-                match *literal {
-                    Literal::Byte(b) => arena.text(format!("b{}", b)),
-                    Literal::Char(c) => arena.text(format!("{:?}", c)),
-                    Literal::Float(f) => arena.text(format!("{:.1}", f)),
-                    Literal::Int(i) => arena.text(format!("{}", i)),
-                    Literal::String(ref s) => arena.text(format!("{:?}", s)),
-                }
+            Expr::Literal(_) => {
+                arena.text(
+                    &self.source.src()[expr.span.start.to_usize()..expr.span.end.to_usize()],
+                )
             }
             Expr::Match(ref expr, ref alts) => {
                 chain![arena;
@@ -417,28 +473,12 @@ impl<'a> ExprPrinter<'a> {
                                 .group()
                         ].group()
                     }).interleave(newlines_iter!(self, binds.iter().map(|bind| bind.span())))),
-                    self.newlines(binds.last().unwrap().alias.span.end, body.span.start),
-                    pretty(body)
+                    self.pretty_expr_(binds.last().unwrap().alias.span.end, body)
                 ].group()
             }
             Expr::Error => arena.text("<error>"),
         };
-        arena
-            .concat(
-                self.source
-                    .comments_between(Span::new(previous_end, expr.span.start))
-                    .map(|comment| {
-                        chain![arena;
-                            if comment.is_empty() {
-                                arena.nil()
-                            } else {
-                                arena.text("// ").append(comment)
-                            },
-                            arena.newline()
-                        ]
-                    }),
-            )
-            .append(doc)
+        comments.append(doc)
     }
 
     fn pretty_lambda<Id>(
@@ -478,9 +518,7 @@ impl<'a> ExprPrinter<'a> {
                         },
                     )
                 };
-
-                let newlines = newlines_iter!(
-                    self,
+                let spans = || {
                     ordered_iter().map(|x| {
                         x.either(|l| l.name.span, |r| {
                             Span::new(
@@ -491,20 +529,33 @@ impl<'a> ExprPrinter<'a> {
                             )
                         })
                     })
-                ).collect::<Vec<_>>();
+                };
+
+                // Preserve comments before and after the comma
+                let newlines = newlines_iter!(self, spans())
+                    .zip(rev_newlines_iter!(self, spans()))
+                    .collect::<Vec<_>>();
 
                 let mut line = newline(arena, expr);
                 // If there are any explicit line breaks then we need put each field on a separate line
-                if newlines.iter().any(|doc| doc.1 != arena.nil().1) {
+                if newlines.iter().any(|&(ref l, ref r)| {
+                    l.1 != arena.nil().1 || r.1 != arena.nil().1
+                }) {
                     line = arena.newline();
                 }
-                let end_iter = newlines.into_iter().map(|mut doc| {
-                    if doc.1 == arena.nil().1 {
-                        doc = line.clone();
+                let end_iter = newlines.into_iter().map(|(l_doc, mut r_doc)| {
+                    if r_doc.1 == arena.nil().1 {
+                        r_doc = line.clone();
                     }
-                    arena.text(",").append(doc)
+                    chain![arena;
+                        l_doc,
+                        ",",
+                        r_doc
+                    ]
                 });
 
+                let last_field_end = spans().last().map_or(expr.span.start, |s| s.end);
+
                 let record = chain![arena;
                     if types.is_empty() && exprs.is_empty() {
                         arena.nil()
@@ -526,7 +577,10 @@ impl<'a> ExprPrinter<'a> {
                         }
                     }).interleave(end_iter))
                 ].nest(INDENT)
-                    .append(line.clone())
+                    .append(self.whitespace(
+                        Span::new(last_field_end, expr.span.end),
+                        line.clone(),
+                    ))
                     .group()
                     .append("}");
                 (arena.text("{"), record)
diff --git a/base/src/source.rs b/base/src/source.rs
index dc09d43a..69733fed 100644
--- a/base/src/source.rs
+++ b/base/src/source.rs
@@ -142,15 +142,21 @@ impl<'a> Iterator for CommentIter<'a> {
             self.src = self.src
                 .trim_matches(|c: char| c.is_whitespace() && c != '\n');
             if self.src.starts_with("//") && !self.src.starts_with("///") {
-                let comment_line = self.src[2..].lines().next().unwrap();
-                self.src = &self.src[(2 + comment_line.len())..];
+                let comment_line = self.src.lines().next().unwrap();
+                self.src = &self.src[comment_line.len()..];
                 self.src = if self.src.starts_with("\r\n") {
                     &self.src[2..]
                 } else {
                     /// \n
                     &self.src[1..]
                 };
-                Some(comment_line.trim_left())
+                Some(comment_line)
+            } else if self.src.starts_with("/*") {
+                self.src.find("*/").map(|i| {
+                    let (comment, rest) = self.src.split_at(i + 2);
+                    self.src = rest;
+                    comment
+                })
             } else if self.src.starts_with("\n") {
                 self.src = &self.src[1..];
                 Some("")
@@ -168,13 +174,15 @@ impl<'a> DoubleEndedIterator for CommentIter<'a> {
         } else {
             self.src = self.src
                 .trim_right_matches(|c: char| c.is_whitespace() && c != '\n');
-            if self.src.starts_with("\n") {
+            if self.src.ends_with("\n") {
                 let comment_line = self.src[..self.src.len() - 1].lines().next_back().unwrap();
-                // Add 1 to skip `\n' as well
-                self.src = &self.src[..(self.src.len() - 2 - comment_line.len() - 1)];
-
                 let trimmed = comment_line.trim_left();
+
+                let newline_len = if self.src.ends_with("\r\n") { 2 } else { 1 };
+                self.src = &self.src[..(self.src.len() - newline_len)];
+
                 if trimmed.starts_with("//") && !trimmed.starts_with("///") {
+                    self.src = &self.src[..(self.src.len() - 2 - comment_line.len() - 1)];
                     Some(trimmed)
                 } else {
                     Some("")
diff --git a/parser/src/infix.rs b/parser/src/infix.rs
index 0323e3a9..3f90d9c4 100644
--- a/parser/src/infix.rs
+++ b/parser/src/infix.rs
@@ -75,7 +75,8 @@ pub struct OpTable {
 
 impl OpTable {
     fn new<I>(ops: I) -> OpTable
-        where I: IntoIterator<Item = (&'static str, OpMeta)>
+    where
+        I: IntoIterator<Item = (&'static str, OpMeta)>,
     {
         OpTable {
             operators: ops.into_iter()
@@ -88,27 +89,29 @@ impl OpTable {
 
 impl Default for OpTable {
     fn default() -> OpTable {
-        OpTable::new(vec![("*", OpMeta::new(7, Fixity::Left)),
-                          ("/", OpMeta::new(7, Fixity::Left)),
-                          ("%", OpMeta::new(7, Fixity::Left)),
-                          ("+", OpMeta::new(6, Fixity::Left)),
-                          ("-", OpMeta::new(6, Fixity::Left)),
-                          (":", OpMeta::new(5, Fixity::Right)),
-                          ("++", OpMeta::new(5, Fixity::Right)),
-                          ("&&", OpMeta::new(3, Fixity::Right)),
-                          ("||", OpMeta::new(2, Fixity::Right)),
-                          ("$", OpMeta::new(0, Fixity::Right)),
-                          ("==", OpMeta::new(4, Fixity::Left)),
-                          ("/=", OpMeta::new(4, Fixity::Left)),
-                          ("<", OpMeta::new(4, Fixity::Left)),
-                          (">", OpMeta::new(4, Fixity::Left)),
-                          ("<=", OpMeta::new(4, Fixity::Left)),
-                          (">=", OpMeta::new(4, Fixity::Left)),
-                          // Hack for some library operators
-                          ("<<", OpMeta::new(9, Fixity::Right)),
-                          (">>", OpMeta::new(9, Fixity::Left)),
-                          ("<|", OpMeta::new(0, Fixity::Right)),
-                          ("|>", OpMeta::new(0, Fixity::Left))])
+        OpTable::new(vec![
+            ("*", OpMeta::new(7, Fixity::Left)),
+            ("/", OpMeta::new(7, Fixity::Left)),
+            ("%", OpMeta::new(7, Fixity::Left)),
+            ("+", OpMeta::new(6, Fixity::Left)),
+            ("-", OpMeta::new(6, Fixity::Left)),
+            (":", OpMeta::new(5, Fixity::Right)),
+            ("++", OpMeta::new(5, Fixity::Right)),
+            ("&&", OpMeta::new(3, Fixity::Right)),
+            ("||", OpMeta::new(2, Fixity::Right)),
+            ("$", OpMeta::new(0, Fixity::Right)),
+            ("==", OpMeta::new(4, Fixity::Left)),
+            ("/=", OpMeta::new(4, Fixity::Left)),
+            ("<", OpMeta::new(4, Fixity::Left)),
+            (">", OpMeta::new(4, Fixity::Left)),
+            ("<=", OpMeta::new(4, Fixity::Left)),
+            (">=", OpMeta::new(4, Fixity::Left)),
+            // Hack for some library operators
+            ("<<", OpMeta::new(9, Fixity::Right)),
+            (">>", OpMeta::new(9, Fixity::Left)),
+            ("<|", OpMeta::new(0, Fixity::Right)),
+            ("|>", OpMeta::new(0, Fixity::Left)),
+        ])
     }
 }
 
@@ -116,13 +119,13 @@ impl<'a> Index<&'a str> for OpTable {
     type Output = OpMeta;
 
     fn index(&self, name: &'a str) -> &OpMeta {
-        self.operators
-            .get(name)
-            .unwrap_or_else(|| if name.starts_with('#') {
-                                &self[name[1..].trim_left_matches(char::is_alphanumeric)]
-                            } else {
-                                &self.default_meta
-                            })
+        self.operators.get(name).unwrap_or_else(
+            || if name.starts_with('#') {
+                &self[name[1..].trim_left_matches(char::is_alphanumeric)]
+            } else {
+                &self.default_meta
+            },
+        )
     }
 }
 
@@ -143,9 +146,10 @@ impl<'s, Id> Reparser<'s, Id> {
         }
     }
 
-    pub fn reparse(&mut self,
-                   expr: &mut SpannedExpr<Id>)
-                   -> Result<(), Errors<Spanned<Error, BytePos>>> {
+    pub fn reparse(
+        &mut self,
+        expr: &mut SpannedExpr<Id>,
+    ) -> Result<(), Errors<Spanned<Error, BytePos>>> {
         self.visit_expr(expr);
         if self.errors.has_errors() {
             Err(mem::replace(&mut self.errors, Errors::new()))
@@ -160,9 +164,11 @@ impl<'s, Id> MutVisitor for Reparser<'s, Id> {
 
     fn visit_expr(&mut self, e: &mut SpannedExpr<Self::Ident>) {
         if let Expr::Infix(..) = e.value {
-            let dummy = pos::spanned2(BytePos::from(0),
-                                      BytePos::from(0),
-                                      Expr::Literal(Literal::Int(0)));
+            let dummy = pos::spanned2(
+                BytePos::from(0),
+                BytePos::from(0),
+                Expr::Literal(Literal::Int(0)),
+            );
             let expr = mem::replace(e, dummy);
             match reparse(expr, self.symbols, &self.operators) {
                 Ok(expr) => {
@@ -187,12 +193,14 @@ impl fmt::Display for Error {
         match *self {
             ConflictingFixities((ref lhs_name, lhs_meta), (ref rhs_name, rhs_meta)) => {
                 write!(f, "Conflicting fixities at the same precedence level. ")?;
-                write!(f,
-                       "left: `{} {}`, right: `{} {}`",
-                       lhs_meta,
-                       lhs_name,
-                       rhs_meta,
-                       rhs_name)
+                write!(
+                    f,
+                    "left: `{} {}`, right: `{} {}`",
+                    lhs_meta,
+                    lhs_name,
+                    rhs_meta,
+                    rhs_name
+                )
             }
         }
     }
@@ -210,10 +218,11 @@ impl StdError for Error {
 /// Inspired by [`Language.Haskell.Infix`].
 ///
 /// [`Language.Haskell.Infix`]: https://hackage.haskell.org/package/infix-0.1.1/docs/src/Language-Haskell-Infix.html
-pub fn reparse<Id>(expr: SpannedExpr<Id>,
-                   symbols: &IdentEnv<Ident = Id>,
-                   operators: &OpTable)
-                   -> Result<SpannedExpr<Id>, Spanned<Error, BytePos>> {
+pub fn reparse<Id>(
+    expr: SpannedExpr<Id>,
+    symbols: &IdentEnv<Ident = Id>,
+    operators: &OpTable,
+) -> Result<SpannedExpr<Id>, Spanned<Error, BytePos>> {
     use base::pos;
     use self::Error::*;
 
@@ -277,8 +286,10 @@ pub fn reparse<Id>(expr: SpannedExpr<Id>,
                                 let stack_op_name =
                                     symbols.string(&stack_op.value.name).to_string();
                                 let span = pos::span(stack_op.span.start, next_op.span.end);
-                                let error = ConflictingFixities((stack_op_name, stack_op_meta),
-                                                                (next_op_name, next_op_meta));
+                                let error = ConflictingFixities(
+                                    (stack_op_name, stack_op_meta),
+                                    (next_op_name, next_op_meta),
+                                );
 
                                 return Err(pos::spanned(span, error));
                             }
@@ -355,19 +366,17 @@ impl<Id> Iterator for Infixes<Id> {
             return Some(InfixToken::Op(op));
         }
 
-        self.remaining_expr
-            .take()
-            .map(|expr| {
-                let expr = *expr; // Workaround for http://stackoverflow.com/questions/28466809/
-                match expr.value {
-                    Expr::Infix(lhs, op, rhs) => {
-                        self.remaining_expr = Some(rhs);
-                        self.next_op = Some(op);
-                        InfixToken::Arg(lhs)
-                    }
-                    _ => InfixToken::Arg(Box::new(expr)), // FIXME: remove reallocation?
+        self.remaining_expr.take().map(|expr| {
+            let expr = *expr; // Workaround for http://stackoverflow.com/questions/28466809/
+            match expr.value {
+                Expr::Infix(lhs, op, rhs) => {
+                    self.remaining_expr = Some(rhs);
+                    self.next_op = Some(op);
+                    InfixToken::Arg(lhs)
                 }
-            })
+                _ => InfixToken::Arg(Box::new(expr)), // FIXME: remove reallocation?
+            }
+        })
     }
 }
 
@@ -397,7 +406,8 @@ mod tests {
     }
 
     impl<T> IdentEnv for MockEnv<T>
-        where T: AsRef<str> + for<'a> From<&'a str>
+    where
+        T: AsRef<str> + for<'a> From<&'a str>,
     {
         fn from_str(&mut self, s: &str) -> Self::Ident {
             T::from(s)
@@ -413,10 +423,11 @@ mod tests {
         TypedIdent::new(name.to_string())
     }
 
-    fn op(lhs: Box<SpannedExpr<String>>,
-          op_str: &str,
-          rhs: Box<SpannedExpr<String>>)
-          -> Box<SpannedExpr<String>> {
+    fn op(
+        lhs: Box<SpannedExpr<String>>,
+        op_str: &str,
+        rhs: Box<SpannedExpr<String>>,
+    ) -> Box<SpannedExpr<String>> {
         Box::new(no_loc(Expr::Infix(lhs, no_loc(ident(op_str)), rhs)))
     }
 
@@ -426,20 +437,24 @@ mod tests {
 
     #[test]
     fn infixes() {
-        let expr = op(int(1),
-                      "+",
-                      op(int(2), "^", op(int(4), "*", op(int(6), "-", int(8)))));
+        let expr = op(
+            int(1),
+            "+",
+            op(int(2), "^", op(int(4), "*", op(int(6), "-", int(8)))),
+        );
 
         let result: Vec<_> = Infixes::new(*expr).collect();
-        let expected = vec![InfixToken::Arg(int(1)),
-                            InfixToken::Op(no_loc(ident("+"))),
-                            InfixToken::Arg(int(2)),
-                            InfixToken::Op(no_loc(ident("^"))),
-                            InfixToken::Arg(int(4)),
-                            InfixToken::Op(no_loc(ident("*"))),
-                            InfixToken::Arg(int(6)),
-                            InfixToken::Op(no_loc(ident("-"))),
-                            InfixToken::Arg(int(8))];
+        let expected = vec![
+            InfixToken::Arg(int(1)),
+            InfixToken::Op(no_loc(ident("+"))),
+            InfixToken::Arg(int(2)),
+            InfixToken::Op(no_loc(ident("^"))),
+            InfixToken::Arg(int(4)),
+            InfixToken::Op(no_loc(ident("*"))),
+            InfixToken::Arg(int(6)),
+            InfixToken::Op(no_loc(ident("-"))),
+            InfixToken::Arg(int(8)),
+        ];
 
         assert_eq!(result, expected);
     }
@@ -458,8 +473,10 @@ mod tests {
     #[test]
     fn reparse_less_precedence() {
         let env = MockEnv::new();
-        let ops = OpTable::new(vec![("*", OpMeta::new(7, Fixity::Left)),
-                                    ("+", OpMeta::new(6, Fixity::Left))]);
+        let ops = OpTable::new(vec![
+            ("*", OpMeta::new(7, Fixity::Left)),
+            ("+", OpMeta::new(6, Fixity::Left)),
+        ]);
 
         // 1 + (2 * 8)
         let expr = *op(int(1), "+", op(int(2), "*", int(8)));
@@ -471,8 +488,10 @@ mod tests {
     #[test]
     fn reparse_greater_precedence() {
         let env = MockEnv::new();
-        let ops = OpTable::new(vec![("*", OpMeta::new(7, Fixity::Left)),
-                                    ("+", OpMeta::new(6, Fixity::Left))]);
+        let ops = OpTable::new(vec![
+            ("*", OpMeta::new(7, Fixity::Left)),
+            ("+", OpMeta::new(6, Fixity::Left)),
+        ]);
 
         // 1 * (2 + 8)
         let expr = *op(int(1), "*", op(int(2), "+", int(8)));
@@ -485,8 +504,10 @@ mod tests {
     #[test]
     fn reparse_equal_precedence_left_fixity() {
         let env = MockEnv::new();
-        let ops = OpTable::new(vec![("-", OpMeta::new(6, Fixity::Left)),
-                                    ("+", OpMeta::new(6, Fixity::Left))]);
+        let ops = OpTable::new(vec![
+            ("-", OpMeta::new(6, Fixity::Left)),
+            ("+", OpMeta::new(6, Fixity::Left)),
+        ]);
 
         // 1 + (2 - 8)
         let expr = *op(int(1), "+", op(int(2), "-", int(8)));
@@ -499,8 +520,10 @@ mod tests {
     #[test]
     fn reparse_equal_precedence_right_fixity() {
         let env = MockEnv::new();
-        let ops = OpTable::new(vec![("-", OpMeta::new(6, Fixity::Right)),
-                                    ("+", OpMeta::new(6, Fixity::Right))]);
+        let ops = OpTable::new(vec![
+            ("-", OpMeta::new(6, Fixity::Right)),
+            ("+", OpMeta::new(6, Fixity::Right)),
+        ]);
 
         // 1 + (2 - 8)
         let expr = *op(int(1), "+", op(int(2), "-", int(8)));
@@ -512,9 +535,11 @@ mod tests {
     #[test]
     fn reparse_mixed_precedences_mixed_fixities() {
         let env = MockEnv::new();
-        let ops = OpTable::new(vec![("*", OpMeta::new(7, Fixity::Left)),
-                                    ("-", OpMeta::new(6, Fixity::Left)),
-                                    ("+", OpMeta::new(6, Fixity::Left))]);
+        let ops = OpTable::new(vec![
+            ("*", OpMeta::new(7, Fixity::Left)),
+            ("-", OpMeta::new(6, Fixity::Left)),
+            ("+", OpMeta::new(6, Fixity::Left)),
+        ]);
 
         //  1  + (2  * (6   -  8))
         let expr = *op(int(1), "+", op(int(2), "*", op(int(6), "-", int(8))));
@@ -527,13 +552,17 @@ mod tests {
     #[test]
     fn reparse_equal_precedence_conflicting_fixities() {
         let env = MockEnv::new();
-        let ops = OpTable::new(vec![("|>", OpMeta::new(5, Fixity::Left)),
-                                    ("<|", OpMeta::new(5, Fixity::Right))]);
+        let ops = OpTable::new(vec![
+            ("|>", OpMeta::new(5, Fixity::Left)),
+            ("<|", OpMeta::new(5, Fixity::Right)),
+        ]);
 
         // 1 |> (2 <| 8)
         let expr = *op(int(1), "|>", op(int(2), "<|", int(8)));
-        let error = ConflictingFixities(("|>".to_string(), OpMeta::new(5, Fixity::Left)),
-                                        ("<|".to_string(), OpMeta::new(5, Fixity::Right)));
+        let error = ConflictingFixities(("|>".to_string(), OpMeta::new(5, Fixity::Left)), (
+            "<|".to_string(),
+            OpMeta::new(5, Fixity::Right),
+        ));
         let expected = Err(no_loc(error));
 
         assert_eq!(reparse(expr, &env, &ops), expected);
@@ -542,13 +571,17 @@ mod tests {
     #[test]
     fn reparse_equal_precedence_conflicting_fixities_nested() {
         let env = MockEnv::new();
-        let ops = OpTable::new(vec![("|>", OpMeta::new(5, Fixity::Left)),
-                                    ("<|", OpMeta::new(5, Fixity::Right))]);
+        let ops = OpTable::new(vec![
+            ("|>", OpMeta::new(5, Fixity::Left)),
+            ("<|", OpMeta::new(5, Fixity::Right)),
+        ]);
 
         // 1 + (1 |> (2 <| 8))
         let expr = *op(int(1), "+", op(int(1), "|>", op(int(2), "<|", int(8))));
-        let error = ConflictingFixities(("|>".to_string(), OpMeta::new(5, Fixity::Left)),
-                                        ("<|".to_string(), OpMeta::new(5, Fixity::Right)));
+        let error = ConflictingFixities(("|>".to_string(), OpMeta::new(5, Fixity::Left)), (
+            "<|".to_string(),
+            OpMeta::new(5, Fixity::Right),
+        ));
         let expected = Err(no_loc(error));
 
         assert_eq!(reparse(expr, &env, &ops), expected);
diff --git a/parser/src/layout.rs b/parser/src/layout.rs
index b1af11b6..b8b4cb08 100644
--- a/parser/src/layout.rs
+++ b/parser/src/layout.rs
@@ -77,7 +77,10 @@ impl Contexts {
         Ok(())
     }
 
-    fn check_unindentation_limit(&mut self, offside: Offside) -> Result<(), Spanned<Error, BytePos>> {
+    fn check_unindentation_limit(
+        &mut self,
+        offside: Offside,
+    ) -> Result<(), Spanned<Error, BytePos>> {
         let mut skip_block = false;
         for other_offside in self.stack.iter().rev() {
             match other_offside.context {
@@ -91,12 +94,16 @@ impl Contexts {
                 Context::MatchClause |
                 Context::Type |
                 Context::Let |
-                Context::Block { .. } if offside.location.column <
-                                         other_offside.location.column => (),
+                Context::Block { .. }
+                    if offside.location.column < other_offside.location.column => (),
                 _ => continue,
             }
             debug!("Unindentation error: {:?} < {:?}", offside, other_offside);
-            return Err(pos::spanned2(offside.location.absolute, offside.location.absolute, Error::UnindentedTooFar));
+            return Err(pos::spanned2(
+                offside.location.absolute,
+                offside.location.absolute,
+                Error::UnindentedTooFar,
+            ));
         }
         Ok(())
     }
@@ -109,7 +116,8 @@ pub struct Layout<'input, Tokens> {
 }
 
 impl<'input, Tokens> Layout<'input, Tokens>
-    where Tokens: Iterator<Item = SpannedToken<'input>>
+where
+    Tokens: Iterator<Item = SpannedToken<'input>>,
 {
     pub fn new(tokens: Tokens) -> Layout<'input, Tokens> {
         Layout {
@@ -120,27 +128,24 @@ impl<'input, Tokens> Layout<'input, Tokens>
     }
 
     fn next_token(&mut self) -> SpannedToken<'input> {
-        self.unprocessed_tokens
-            .pop()
-            .unwrap_or_else(|| {
-                self.tokens
-                    .next()
-                    .unwrap_or_else(|| {
-                        // Blegh
-                        let location = Location {
-                            line: Line::from(0),
-                            column: Column::from(1),
-                            absolute: BytePos::from(0),
-                        };
-                        pos::spanned2(location, location, Token::EOF)
-                    })
+        self.unprocessed_tokens.pop().unwrap_or_else(|| {
+            self.tokens.next().unwrap_or_else(|| {
+                // Blegh
+                let location = Location {
+                    line: Line::from(0),
+                    column: Column::from(1),
+                    absolute: BytePos::from(0),
+                };
+                pos::spanned2(location, location, Token::EOF)
             })
+        })
     }
 
-    fn layout_token(&mut self,
-                    token: SpannedToken<'input>,
-                    layout_token: Token<'input>)
-                    -> SpannedToken<'input> {
+    fn layout_token(
+        &mut self,
+        token: SpannedToken<'input>,
+        layout_token: Token<'input>,
+    ) -> SpannedToken<'input> {
         let span = token.span;
         self.unprocessed_tokens.push(token);
         pos::spanned(span, layout_token)
@@ -154,8 +159,7 @@ impl<'input, Tokens> Layout<'input, Tokens>
             self.unprocessed_tokens
                 .push(pos::spanned(span, Token::OpenBlock));
         }
-        self.indent_levels
-            .push(Offside::new(span.start, context))
+        self.indent_levels.push(Offside::new(span.start, context))
     }
 
     fn layout_next_token(&mut self) -> Result<SpannedToken<'input>, Spanned<Error, BytePos>> {
@@ -172,8 +176,8 @@ impl<'input, Tokens> Layout<'input, Tokens>
                 (_, Some(offside)) => offside,
                 (&Token::EOF, None) => return Ok(token),
                 (_, None) => {
-                    let offside = Offside::new(token.span.start,
-                                               Context::Block { emit_semi: false });
+                    let offside =
+                        Offside::new(token.span.start, Context::Block { emit_semi: false });
                     self.indent_levels.push(offside)?;
                     debug!("Default block {:?}", token);
                     return Ok(self.layout_token(token, Token::OpenBlock));
@@ -201,12 +205,9 @@ impl<'input, Tokens> Layout<'input, Tokens>
                     // syntax error. Just return the token directly in that case to avoid an
                     // infinite loop caused by repeatedly inserting a default block and removing
                     // it.
-                    if self.indent_levels
-                           .stack
-                           .iter()
-                           .all(|offside| {
-                                    !token_closes_context(&token.value, offside.context)
-                                }) {
+                    if self.indent_levels.stack.iter().all(|offside| {
+                        !token_closes_context(&token.value, offside.context)
+                    }) {
                         return Ok(token);
                     }
 
@@ -219,7 +220,8 @@ impl<'input, Tokens> Layout<'input, Tokens>
                                     // The enclosing block should not emit a block separator for the next
                                     // expression
                                     if let Context::Block { ref mut emit_semi, .. } =
-                                        offside.context {
+                                        offside.context
+                                    {
                                         *emit_semi = false;
                                     }
                                 }
@@ -233,7 +235,8 @@ impl<'input, Tokens> Layout<'input, Tokens>
                                     // The enclosing block should not emit a block separator for the next
                                     // expression
                                     if let Context::Block { ref mut emit_semi, .. } =
-                                        offside.context {
+                                        offside.context
+                                    {
                                         *emit_semi = false;
                                     }
                                     offside.location
@@ -246,8 +249,8 @@ impl<'input, Tokens> Layout<'input, Tokens>
                                 // b
                                 // ```
                                 // `let x = 1 in {{ a; b }}` and not `{{ (let x = 1 in a) ; b }}`
-                                let offside = Offside::new(location,
-                                                           Context::Block { emit_semi: false });
+                                let offside =
+                                    Offside::new(location, Context::Block { emit_semi: false });
                                 self.indent_levels.push(offside)?;
                                 self.unprocessed_tokens
                                     .push(pos::spanned(token.span, Token::OpenBlock));
@@ -309,15 +312,16 @@ impl<'input, Tokens> Layout<'input, Tokens>
                 (Context::MatchClause, _) => {
                     // Must allow `|` to be on the same line
                     if ordering == Ordering::Less ||
-                       (ordering == Ordering::Equal && token.value != Token::Pipe) {
+                        (ordering == Ordering::Equal && token.value != Token::Pipe)
+                    {
                         self.indent_levels.pop();
                         continue;
                     }
                 }
                 // `and` and `}` are allowed to be on the same line as the `let` or `type`
                 (Context::Let, Ordering::Equal) |
-                (Context::Type, Ordering::Equal) if token.value != Token::And &&
-                                                    token.value != Token::RBrace => {
+                (Context::Type, Ordering::Equal)
+                    if token.value != Token::And && token.value != Token::RBrace => {
                     // Insert an `in` token
                     self.indent_levels.pop();
                     let location = {
@@ -395,7 +399,7 @@ impl<'input, Tokens> Layout<'input, Tokens>
                     // else
                     //     3
                     let add_block = next.value != Token::If ||
-                                    next.span.start.line != token.span.start.line;
+                        next.span.start.line != token.span.start.line;
                     self.unprocessed_tokens.push(next);
                     if add_block {
                         self.scan_for_next_block(Context::Block { emit_semi: false })?;
@@ -434,7 +438,8 @@ fn token_closes_context(token: &Token, context: Context) -> bool {
 }
 
 impl<'input, Tokens> Iterator for Layout<'input, Tokens>
-    where Tokens: Iterator<Item = SpannedToken<'input>>
+where
+    Tokens: Iterator<Item = SpannedToken<'input>>,
 {
     type Item = Result<SpannedToken<'input>, Spanned<Error, BytePos>>;
 
diff --git a/parser/src/lib.rs b/parser/src/lib.rs
index 23157d4d..3e8b125f 100644
--- a/parser/src/lib.rs
+++ b/parser/src/lib.rs
@@ -3,7 +3,7 @@
 //! string interner and therefore also garbage collector needs to compiled before the parser.
 #![doc(html_root_url="https://docs.rs/gluon_parser/0.5.0")] // # GLUON
 
-#[macro_use] 
+#[macro_use]
 extern crate log;
 extern crate itertools;
 #[macro_use]
@@ -28,6 +28,7 @@ pub use infix::Error as InfixError;
 pub use layout::Error as LayoutError;
 pub use token::Error as TokenizeError;
 
+#[cfg_attr(rustfmt, rustfmt_skip)]
 mod grammar;
 mod infix;
 mod layout;
@@ -40,9 +41,11 @@ fn new_ident<Id>(type_cache: &TypeCache<Id>, name: Id) -> TypedIdent<Id> {
     }
 }
 
-type LalrpopError<'input> = lalrpop_util::ParseError<BytePos,
-                                                     Token<'input>,
-                                                     Spanned<Error, BytePos>>;
+type LalrpopError<'input> = lalrpop_util::ParseError<
+    BytePos,
+    Token<'input>,
+    Spanned<Error, BytePos>,
+>;
 
 /// Shrink hidden spans to fit the visible expressions and flatten singleton blocks.
 fn shrink_hidden_spans<Id>(mut expr: SpannedExpr<Id>) -> SpannedExpr<Id> {
@@ -78,7 +81,8 @@ fn shrink_hidden_spans<Id>(mut expr: SpannedExpr<Id>) -> SpannedExpr<Id> {
 }
 
 fn transform_errors<'a, Iter>(errors: Iter) -> Errors<Spanned<Error, BytePos>>
-    where Iter: IntoIterator<Item = LalrpopError<'a>>
+where
+    Iter: IntoIterator<Item = LalrpopError<'a>>,
 {
     errors.into_iter().map(Error::from_lalrpop).collect()
 }
@@ -162,9 +166,11 @@ impl Error {
                 mut expected,
             } => {
                 remove_extra_quotes(&mut expected);
-                pos::spanned2(lpos,
-                              rpos,
-                              Error::UnexpectedToken(token.to_string(), expected))
+                pos::spanned2(
+                    lpos,
+                    rpos,
+                    Error::UnexpectedToken(token.to_string(), expected),
+                )
             }
             UnrecognizedToken {
                 token: None,
@@ -205,8 +211,9 @@ impl<I, E> ResultOkIter<I, E> {
 }
 
 impl<I, T, E> Iterator for ResultOkIter<I, E>
-    where I: Iterator<Item = Result<T, E>>,
-          E: ::std::fmt::Debug
+where
+    I: Iterator<Item = Result<T, E>>,
+    E: ::std::fmt::Debug,
 {
     type Item = T;
 
@@ -240,7 +247,8 @@ impl<'a, I> SharedIter<'a, I> {
 }
 
 impl<'a, I> Iterator for SharedIter<'a, I>
-    where I: Iterator
+where
+    I: Iterator,
 {
     type Item = I::Item;
 
@@ -287,10 +295,12 @@ macro_rules! layout {
     } }
 }
 
-pub fn parse_partial_expr<Id>(symbols: &mut IdentEnv<Ident = Id>,
-                              input: &str)
-                              -> Result<SpannedExpr<Id>, (Option<SpannedExpr<Id>>, ParseErrors)>
-    where Id: Clone
+pub fn parse_partial_expr<Id>(
+    symbols: &mut IdentEnv<Ident = Id>,
+    input: &str,
+) -> Result<SpannedExpr<Id>, (Option<SpannedExpr<Id>>, ParseErrors)>
+where
+    Id: Clone,
 {
     let result_ok_iter;
     let layout = layout!(result_ok_iter, input);
@@ -307,10 +317,12 @@ pub fn parse_partial_expr<Id>(symbols: &mut IdentEnv<Ident = Id>,
     if let Err(err) = result_ok_iter.borrow_mut().result(()) {
         parse_errors.pop(); // Remove the EOF error
         parse_errors.push(lalrpop_util::ParseError::User {
-                              error: pos::spanned2(err.span.start.absolute,
-                                                   err.span.end.absolute,
-                                                   err.value.into()),
-                          });
+            error: pos::spanned2(
+                err.span.start.absolute,
+                err.span.end.absolute,
+                err.value.into(),
+            ),
+        });
     }
 
     match result {
@@ -318,9 +330,7 @@ pub fn parse_partial_expr<Id>(symbols: &mut IdentEnv<Ident = Id>,
             let mut errors = transform_errors(parse_errors);
             let mut reparser = Reparser::new(OpTable::default(), symbols);
             if let Err(reparse_errors) = reparser.reparse(&mut expr) {
-                errors.extend(reparse_errors
-                                  .into_iter()
-                                  .map(|err| err.map(Error::Infix)));
+                errors.extend(reparse_errors.into_iter().map(|err| err.map(Error::Infix)));
             }
 
             if errors.has_errors() {
@@ -336,19 +346,21 @@ pub fn parse_partial_expr<Id>(symbols: &mut IdentEnv<Ident = Id>,
     }
 }
 
-pub fn parse_expr(symbols: &mut IdentEnv<Ident = Symbol>,
-                  input: &str)
-                  -> Result<SpannedExpr<Symbol>, ParseErrors> {
+pub fn parse_expr(
+    symbols: &mut IdentEnv<Ident = Symbol>,
+    input: &str,
+) -> Result<SpannedExpr<Symbol>, ParseErrors> {
     parse_partial_expr(symbols, input).map_err(|t| t.1)
 }
 
 pub type LetOrExpr<Id> = Result<SpannedExpr<Id>, ValueBinding<Id>>;
 
-pub fn parse_partial_let_or_expr<Id>
-    (symbols: &mut IdentEnv<Ident = Id>,
-     input: &str)
-     -> Result<LetOrExpr<Id>, (Option<LetOrExpr<Id>>, ParseErrors)>
-    where Id: Clone,
+pub fn parse_partial_let_or_expr<Id>(
+    symbols: &mut IdentEnv<Ident = Id>,
+    input: &str,
+) -> Result<LetOrExpr<Id>, (Option<LetOrExpr<Id>>, ParseErrors)>
+where
+    Id: Clone,
 {
     let result_ok_iter;
     let layout = layout!(result_ok_iter, input);
@@ -365,9 +377,11 @@ pub fn parse_partial_let_or_expr<Id>
     if let Err(err) = result_ok_iter.borrow_mut().result(()) {
         parse_errors.pop(); // Remove the EOF error
         parse_errors.push(lalrpop_util::ParseError::User {
-            error: pos::spanned2(err.span.start.absolute,
-                                 err.span.end.absolute,
-                                 err.value.into()),
+            error: pos::spanned2(
+                err.span.start.absolute,
+                err.span.end.absolute,
+                err.value.into(),
+            ),
         });
     }
 
@@ -397,10 +411,10 @@ pub fn parse_partial_let_or_expr<Id>
 }
 
 #[cfg(feature = "test")]
-pub fn parse_string<'env, 'input>
-    (symbols: &'env mut IdentEnv<Ident = String>,
-     input: &'input str)
-     -> Result<SpannedExpr<String>, (Option<SpannedExpr<String>>, ParseErrors)> {
+pub fn parse_string<'env, 'input>(
+    symbols: &'env mut IdentEnv<Ident = String>,
+    input: &'input str,
+) -> Result<SpannedExpr<String>, (Option<SpannedExpr<String>>, ParseErrors)> {
     parse_partial_expr(symbols, input)
 }
 
@@ -419,7 +433,7 @@ pub fn format_expr(input: &str) -> Result<String, ParseErrors> {
                 "\n"
             }
         }
-        None => "\n"
+        None => "\n",
     };
 
     let expr = parse_expr(&mut Symbols::new(), input)?;
diff --git a/vm/Cargo.toml b/vm/Cargo.toml
index d40e01f2..e12dd745 100644
--- a/vm/Cargo.toml
+++ b/vm/Cargo.toml
@@ -35,9 +35,7 @@ gluon_parser = { path = "../parser", version = "0.5.0", optional = true } # GLUO
 lalrpop = { version = "0.13.1", optional = true }
 
 [dev-dependencies]
-# HACK Trick crates.io into letting letting this be published with a dependency on gluon
-# (which requires gluon_vm to be published)
-gluon = { path = "..", version = "<0.6.0, >=0.4.2" } # GLUON
+gluon = { path = "..", version = "0.5.0" } # GLUON
 
 lalrpop-util = "0.13.1"
 regex = "0.2.0"
diff --git a/vm/src/core/mod.rs b/vm/src/core/mod.rs
index 0a3d7691..cf25abb7 100644
--- a/vm/src/core/mod.rs
+++ b/vm/src/core/mod.rs
@@ -28,6 +28,7 @@ macro_rules! assert_deq {
 }
 
 #[cfg(test)]
+#[cfg_attr(rustfmt, rustfmt_skip)]
 mod grammar;
 pub mod optimize;
 


Test patch:
diff --git a/parser/tests/pretty_print.rs b/parser/tests/pretty_print.rs
index f96fed0b..b6f7860b 100644
--- a/parser/tests/pretty_print.rs
+++ b/parser/tests/pretty_print.rs
@@ -98,3 +98,51 @@ x
 "#
     );
 }
+
+#[test]
+fn dont_lose_information_in_literals() {
+    let expr = r#"
+3.14 "\t\n\r\""
+"#;
+    assert_eq!(&format_expr(expr).unwrap(), expr);
+}
+
+
+#[test]
+fn preserve_comment_between_let_in() {
+    let expr = r#"
+// test
+let x = 1
+// test
+type Test = Int
+// test
+1
+// test2
+"#;
+    assert_eq!(&format_expr(expr).unwrap(), expr);
+}
+
+#[test]
+fn preserve_whitespace_in_record() {
+    let expr = r#"
+{
+    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaax = 1,
+
+
+    bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbby = 2
+}
+"#;
+    assert_eq!(&format_expr(expr).unwrap(), expr);
+}
+
+
+#[test]
+fn preserve_block_comments() {
+    let expr = r#"
+/* test */
+let x = { field = f /* test */ 123 /* doc */ }
+/* test */
+x
+"#;
+    assert_eq!(&format_expr(expr).unwrap(), expr);
+}