Repository: gluon-lang/gluon
Pull request #209 (2016-11-28 21:13:56)

feat: Add a macro for describing gluon record patterns
cc #208


Patch:
diff --git a/.gitignore b/.gitignore
index cb24834f..8977c0a6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,5 +6,3 @@
 
 target
 Cargo.lock
-
-parser/src/grammar.rs
diff --git a/base/src/ast.rs b/base/src/ast.rs
index 1b72b38a..5a44b1b8 100644
--- a/base/src/ast.rs
+++ b/base/src/ast.rs
@@ -95,10 +95,9 @@ pub struct Lambda<Id> {
     pub body: Box<SpannedExpr<Id>>,
 }
 
+/// Expression which contains a location
 pub type SpannedExpr<Id> = Spanned<Expr<Id>, BytePos>;
 
-pub type SpannedIdent<Id> = Spanned<TypedIdent<Id>, BytePos>;
-
 /// The representation of gluon's expression syntax
 #[derive(Clone, PartialEq, Debug)]
 pub enum Expr<Id> {
@@ -115,7 +114,7 @@ pub enum Expr<Id> {
     /// Pattern match expression
     Match(Box<SpannedExpr<Id>>, Vec<Alternative<Id>>),
     /// Infix operator expression eg. `f >> g`
-    Infix(Box<SpannedExpr<Id>>, SpannedIdent<Id>, Box<SpannedExpr<Id>>),
+    Infix(Box<SpannedExpr<Id>>, TypedIdent<Id>, Box<SpannedExpr<Id>>),
     /// Record field projection, eg. `value.field`
     Projection(Box<SpannedExpr<Id>>, Id, ArcType<Id>),
     /// Array construction
@@ -178,7 +177,7 @@ pub fn walk_mut_expr<V: ?Sized + MutVisitor>(v: &mut V, e: &mut SpannedExpr<V::I
         }
         Expr::Infix(ref mut lhs, ref mut id, ref mut rhs) => {
             v.visit_expr(lhs);
-            v.visit_typ(&mut id.value.typ);
+            v.visit_typ(&mut id.typ);
             v.visit_expr(rhs);
         }
         Expr::LetBindings(ref mut bindings, ref mut body) => {
@@ -279,7 +278,7 @@ pub fn walk_expr<V: ?Sized + Visitor>(v: &mut V, e: &SpannedExpr<V::Ident>) {
         }
         Expr::Infix(ref lhs, ref id, ref rhs) => {
             v.visit_expr(lhs);
-            v.visit_typ(&id.value.typ);
+            v.visit_typ(&id.typ);
             v.visit_expr(rhs);
         }
         Expr::LetBindings(ref bindings, ref body) => {
@@ -395,7 +394,7 @@ impl Typed for Expr<Symbol> {
                 Type::unit()
             }
             Expr::Infix(_, ref op, _) => {
-                if let Type::App(_, ref args) = *op.value.typ.clone() {
+                if let Type::App(_, ref args) = *op.typ.clone() {
                     if let Type::App(_, ref args) = *args[1] {
                         return args[1].clone();
                     }
@@ -474,5 +473,5 @@ fn get_return_type(env: &TypeEnv, alias_type: &ArcType, arg_count: usize) -> Arc
 }
 
 pub fn is_operator_char(c: char) -> bool {
-    "#+-*/&|=<>:.".chars().any(|x| x == c)
+    "+-*/&|=<>".chars().any(|x| x == c)
 }
diff --git a/base/src/error.rs b/base/src/error.rs
index f12a9db2..9e511861 100644
--- a/base/src/error.rs
+++ b/base/src/error.rs
@@ -4,9 +4,6 @@
 use std::any::Any;
 use std::error::Error as StdError;
 use std::fmt;
-use std::iter::{Extend, FromIterator};
-use std::slice;
-use std::vec;
 
 use pos::{BytePos, Location, Span, Spanned, spanned2};
 use source::Source;
@@ -14,13 +11,13 @@ use source::Source;
 /// An error type which can represent multiple errors.
 #[derive(Debug, PartialEq)]
 pub struct Errors<T> {
-    errors: Vec<T>,
+    pub errors: Vec<T>,
 }
 
 impl<T> Errors<T> {
     /// Creates a new, empty `Errors` instance.
     pub fn new() -> Errors<T> {
-        Errors::from(Vec::new())
+        Errors { errors: Vec::new() }
     }
 
     /// Returns true if `self` contains any errors
@@ -28,64 +25,10 @@ impl<T> Errors<T> {
         !self.errors.is_empty()
     }
 
-    /// The number of errors in the error list
-    pub fn len(&self) -> usize {
-        self.errors.len()
-    }
-
     /// Adds an error to `self`
-    pub fn push(&mut self, t: T) {
+    pub fn error(&mut self, t: T) {
         self.errors.push(t);
     }
-
-    /// Pops and error off the error list
-    pub fn pop(&mut self) -> Option<T> {
-        self.errors.pop()
-    }
-}
-
-impl<T> Extend<T> for Errors<T> {
-    fn extend<Iter: IntoIterator<Item = T>>(&mut self, iter: Iter) {
-        self.errors.extend(iter);
-    }
-}
-
-impl<T> From<Vec<T>> for Errors<T> {
-    fn from(errors: Vec<T>) -> Errors<T> {
-        Errors { errors: errors }
-    }
-}
-
-impl<T> FromIterator<T> for Errors<T> {
-    fn from_iter<Iter: IntoIterator<Item = T>>(iter: Iter) -> Errors<T> {
-        Errors { errors: iter.into_iter().collect() }
-    }
-}
-
-impl<T> Into<Vec<T>> for Errors<T> {
-    fn into(self) -> Vec<T> {
-        self.errors
-    }
-}
-
-impl<T> IntoIterator for Errors<T> {
-    type Item = T;
-
-    type IntoIter = vec::IntoIter<T>;
-
-    fn into_iter(self) -> vec::IntoIter<T> {
-        self.errors.into_iter()
-    }
-}
-
-impl<'a, T> IntoIterator for &'a Errors<T> {
-    type Item = &'a T;
-
-    type IntoIter = slice::Iter<'a, T>;
-
-    fn into_iter(self) -> slice::Iter<'a, T> {
-        self.errors.iter()
-    }
 }
 
 impl<T: fmt::Display> fmt::Display for Errors<T> {
diff --git a/base/src/pos.rs b/base/src/pos.rs
index 8e4db0d3..64914172 100644
--- a/base/src/pos.rs
+++ b/base/src/pos.rs
@@ -96,7 +96,7 @@ pub struct Location {
 }
 
 impl Location {
-    pub fn shift(mut self, ch: char) -> Location {
+    pub fn bump(&mut self, ch: char) {
         if ch == '\n' {
             self.line += Line::from(1);
             self.column = Column::from(0);
@@ -104,6 +104,10 @@ impl Location {
             self.column += Column::from(1);
         }
         self.absolute += BytePos::from(ch.len_utf8());
+    }
+
+    pub fn line_offset(mut self, offset: Column) -> Location {
+        self.column += offset;
         self
     }
 }
@@ -220,17 +224,6 @@ pub struct Spanned<T, Pos> {
     pub value: T,
 }
 
-impl<T, Pos> Spanned<T, Pos> {
-    pub fn map<U, F>(self, mut f: F) -> Spanned<U, Pos>
-        where F: FnMut(T) -> U,
-    {
-        Spanned {
-            span: self.span,
-            value: f(self.value),
-        }
-    }
-}
-
 impl<T: PartialEq, Pos> PartialEq for Spanned<T, Pos> {
     fn eq(&self, other: &Spanned<T, Pos>) -> bool {
         self.value == other.value
@@ -243,14 +236,6 @@ impl<T: fmt::Display, Pos: fmt::Display> fmt::Display for Spanned<T, Pos> {
     }
 }
 
-pub fn span<Pos>(start: Pos, end: Pos) -> Span<Pos> {
-    Span {
-        start: start,
-        end: end,
-        expansion_id: NO_EXPANSION,
-    }
-}
-
 pub fn spanned<T, Pos>(span: Span<Pos>, value: T) -> Spanned<T, Pos> {
     Spanned {
         span: span,
@@ -260,7 +245,11 @@ pub fn spanned<T, Pos>(span: Span<Pos>, value: T) -> Spanned<T, Pos> {
 
 pub fn spanned2<T, Pos>(start: Pos, end: Pos, value: T) -> Spanned<T, Pos> {
     Spanned {
-        span: span(start, end),
+        span: Span {
+            start: start,
+            end: end,
+            expansion_id: NO_EXPANSION,
+        },
         value: value,
     }
 }
diff --git a/base/src/types.rs b/base/src/types.rs
index 588e8694..5a15a21f 100644
--- a/base/src/types.rs
+++ b/base/src/types.rs
@@ -222,15 +222,6 @@ pub struct Field<Id, T = ArcType<Id>> {
 /// increasing the size of `Type`.
 pub type AppVec<T> = SmallVec<[T; 2]>;
 
-impl<Id, T> Field<Id, T> {
-    pub fn new(name: Id, typ: T) -> Field<Id, T> {
-        Field {
-            name: name,
-            typ: typ,
-        }
-    }
-}
-
 /// The representation of gluon's types.
 ///
 /// For efficency this enum is not stored directly but instead a pointer wrapper which derefs to
diff --git a/benches/parser.rs b/benches/parser.rs
index 195eb7a7..c202a8b6 100644
--- a/benches/parser.rs
+++ b/benches/parser.rs
@@ -20,7 +20,7 @@ fn prelude(b: &mut ::test::Bencher) {
         let mut symbols = Symbols::new();
         let mut symbols = SymbolModule::new("".into(), &mut symbols);
         let expr = parser::parse_expr(&mut symbols, &text)
-            .unwrap_or_else(|err| panic!("{:?}", err));
+            .unwrap_or_else(|(_, err)| panic!("{:?}", err));
         ::test::black_box(expr)
     })
 }
diff --git a/check/src/completion.rs b/check/src/completion.rs
index 9268c2c3..d275ad37 100644
--- a/check/src/completion.rs
+++ b/check/src/completion.rs
@@ -237,7 +237,7 @@ impl<F> FindVisitor<F>
             Expr::Infix(ref l, ref op, ref r) => {
                 match (l.span.containment(&self.pos), r.span.containment(&self.pos)) {
                     (Ordering::Greater, Ordering::Less) => {
-                        self.on_found.ident(current, &op.value.name, &op.value.typ)
+                        self.on_found.ident(current, &op.name, &op.typ)
                     }
                     (_, Ordering::Greater) |
                     (_, Ordering::Equal) => self.visit_expr(r),
diff --git a/check/src/rename.rs b/check/src/rename.rs
index 7fbf5aa5..1a0e0040 100644
--- a/check/src/rename.rs
+++ b/check/src/rename.rs
@@ -217,15 +217,15 @@ pub fn rename(symbols: &mut SymbolModule,
                         }
                     }
                 }
-                Expr::Infix(ref mut lhs, ref mut op, ref mut rhs) => {
-                    if let Some(new_id) = self.rename(&op.value.name, &op.value.typ)? {
+                Expr::Infix(ref mut l, ref mut id, ref mut r) => {
+                    if let Some(new_id) = self.rename(&id.name, &id.typ)? {
                         debug!("Rename {} = {}",
-                               self.symbols.string(&op.value.name),
+                               self.symbols.string(&id.name),
                                self.symbols.string(&new_id));
-                        op.value.name = new_id;
+                        id.name = new_id;
                     }
-                    self.visit_expr(lhs);
-                    self.visit_expr(rhs);
+                    self.visit_expr(l);
+                    self.visit_expr(r);
                 }
                 Expr::Match(ref mut expr, ref mut alts) => {
                     self.visit_expr(expr);
@@ -290,7 +290,7 @@ pub fn rename(symbols: &mut SymbolModule,
 
         fn visit_expr(&mut self, expr: &mut SpannedExpr<Self::Ident>) {
             if let Err(err) = self.rename_expr(expr) {
-                self.errors.push(Spanned {
+                self.errors.error(Spanned {
                     span: expr.span,
                     value: err,
                 });
diff --git a/check/src/typecheck.rs b/check/src/typecheck.rs
index e707809b..b42f7cf2 100644
--- a/check/src/typecheck.rs
+++ b/check/src/typecheck.rs
@@ -239,7 +239,7 @@ impl<'a> Typecheck<'a> {
     }
 
     fn error(&mut self, span: Span<BytePos>, error: TypeError<Symbol>) -> ArcType {
-        self.errors.push(Spanned {
+        self.errors.error(Spanned {
             span: span,
             value: error,
         });
@@ -404,8 +404,8 @@ impl<'a> Typecheck<'a> {
                     Ok(typ)
                 }
                 Err(errors) => {
-                    for Spanned { span, value } in errors {
-                        self.errors.push(Spanned {
+                    for Spanned { span, value } in errors.errors {
+                        self.errors.error(Spanned {
                             span: span,
                             value: value.into(),
                         });
@@ -446,7 +446,7 @@ impl<'a> Typecheck<'a> {
                 }
                 Err(err) => {
                     returned_type = self.subs.new_var();
-                    self.errors.push(Spanned {
+                    self.errors.error(Spanned {
                         span: expr.span,
                         value: err,
                     });
@@ -510,33 +510,32 @@ impl<'a> Typecheck<'a> {
             Expr::Infix(ref mut lhs, ref mut op, ref mut rhs) => {
                 let lhs_type = self.typecheck(&mut **lhs);
                 let rhs_type = self.typecheck(&mut **rhs);
-                let op_name = String::from(self.symbols.string(&op.value.name));
+                let op_name = String::from(self.symbols.string(&op.name));
                 let result = if op_name.starts_with('#') {
                     // Handle primitives
                     let arg_type = self.unify(&lhs_type, rhs_type)?;
                     let op_type = op_name.trim_matches(|c: char| !c.is_alphabetic());
                     let prim_type = primitive_type(op_type);
-                    op.value.typ = Type::function(vec![prim_type.clone(), prim_type.clone()],
-                                                  prim_type.clone());
+                    op.typ = Type::function(vec![prim_type.clone(), prim_type.clone()],
+                                            prim_type.clone());
                     let typ = self.unify(&prim_type, arg_type)?;
                     match &op_name[1 + op_type.len()..] {
                         "+" | "-" | "*" | "/" => Ok(typ),
                         "==" | "<" => Ok(self.bool()),
-                        _ => Err(UndefinedVariable(op.value.name.clone())),
+                        _ => Err(UndefinedVariable(op.name.clone())),
                     }
                 } else {
                     match &*op_name {
                         "&&" | "||" => {
                             self.unify(&lhs_type, rhs_type.clone())?;
-                            op.value.typ = Type::function(vec![self.bool(), self.bool()],
-                                                          self.bool());
+                            op.typ = Type::function(vec![self.bool(), self.bool()], self.bool());
                             self.unify(&self.bool(), lhs_type)
                         }
                         _ => {
-                            op.value.typ = self.find(&op.value.name)?;
+                            op.typ = self.find(&op.name)?;
                             let func_type = Type::function(vec![lhs_type, rhs_type],
                                                            self.subs.new_var());
-                            let ret = self.unify(&op.value.typ, func_type)?
+                            let ret = self.unify(&op.typ, func_type)?
                                 .as_function()
                                 .and_then(|(_, ret)| ret.as_function())
                                 .map(|(_, ret)| ret.clone())
@@ -972,7 +971,7 @@ impl<'a> Typecheck<'a> {
         // Finally insert the declared types into the global scope
         for bind in bindings {
             if self.environment.stack_types.get(&bind.name).is_some() {
-                self.errors.push(Spanned {
+                self.errors.error(Spanned {
                     span: expr.span,
                     value: DuplicateTypeDefinition(bind.name.clone()),
                 });
@@ -1245,8 +1244,9 @@ impl<'a> Typecheck<'a> {
                 let mut expected = expected.clone();
                 expected = self.subs.set_type(expected);
                 actual = self.subs.set_type(actual);
-                let err = TypeError::Unification(expected, actual, apply_subs(&self.subs, errors));
-                self.errors.push(Spanned {
+                let err =
+                    TypeError::Unification(expected, actual, apply_subs(&self.subs, errors.errors));
+                self.errors.error(Spanned {
                     span: span,
                     value: err,
                 });
@@ -1259,7 +1259,7 @@ impl<'a> Typecheck<'a> {
         match self.unify(expected, actual) {
             Ok(typ) => typ,
             Err(err) => {
-                self.errors.push(Spanned {
+                self.errors.error(Spanned {
                     span: span,
                     value: err,
                 });
@@ -1283,7 +1283,7 @@ impl<'a> Typecheck<'a> {
                        errors,
                        types::display_type(&self.symbols, &expected),
                        types::display_type(&self.symbols, &actual));
-                Err(TypeError::Unification(expected, actual, apply_subs(&self.subs, errors)))
+                Err(TypeError::Unification(expected, actual, apply_subs(&self.subs, errors.errors)))
             }
         }
     }
@@ -1320,7 +1320,7 @@ impl<'a> Typecheck<'a> {
                                  -> bool {
         match duplicated_fields.replace(name) {
             Some(name) => {
-                self.errors.push(Spanned {
+                self.errors.error(Spanned {
                     span: span,
                     value: DuplicateField(name),
                 });
@@ -1345,10 +1345,10 @@ fn with_pattern_types<F>(fields: &[(Symbol, Option<Symbol>)], typ: &ArcType, mut
 }
 
 fn apply_subs(subs: &Substitution<ArcType>,
-              errors: Errors<unify_type::Error<Symbol>>)
+              error: Vec<unify_type::Error<Symbol>>)
               -> Vec<unify_type::Error<Symbol>> {
     use unify::Error::*;
-    errors.into_iter()
+    error.into_iter()
         .map(|error| {
             match error {
                 TypeMismatch(expected, actual) => {
diff --git a/check/src/unify.rs b/check/src/unify.rs
index 6cd59efb..7f1a4ec4 100644
--- a/check/src/unify.rs
+++ b/check/src/unify.rs
@@ -121,7 +121,7 @@ impl<'e, S, T> Unifier<S, T> for Unify<'e, T, T::Error>
           T::Variable: Clone,
 {
     fn report_error(unifier: &mut UnifierState<S, Self>, error: Error<T, T::Error>) {
-        unifier.unifier.errors.push(error);
+        unifier.unifier.errors.error(error);
     }
 
     fn try_match(unifier: &mut UnifierState<S, Self>, l: &T, r: &T) -> Option<T> {
@@ -154,7 +154,7 @@ impl<'e, S, T> Unifier<S, T> for Unify<'e, T, T::Error>
         match result {
             Ok(typ) => typ,
             Err(error) => {
-                unifier.unifier.errors.push(error);
+                unifier.unifier.errors.error(error);
                 Some(subs.new_var())
             }
         }
@@ -340,7 +340,7 @@ mod test {
         // Check that var1 does not unify with int as it should already be a string
         let result = unify(&subs, &var1, &int);
         assert_eq!(result,
-                   Err(Errors::from(vec![Error::TypeMismatch(string.clone(), int.clone())])));
+                   Err(Errors { errors: vec![Error::TypeMismatch(string.clone(), int.clone())] }));
     }
 
     #[test]
@@ -352,7 +352,9 @@ mod test {
         let fun = TType(Box::new(Type::Arrow(string.clone(), var1.clone())));
         let result = unify(&subs, &fun, &var1);
         assert_eq!(result,
-                   Err(Errors::from(vec![Error::Occurs(*var1.get_var().unwrap(), fun.clone())])));
+                   Err(Errors {
+                       errors: vec![Error::Occurs(*var1.get_var().unwrap(), fun.clone())],
+                   }));
     }
 
     #[test]
diff --git a/check/src/unify_type.rs b/check/src/unify_type.rs
index 767ef3de..723d4747 100644
--- a/check/src/unify_type.rs
+++ b/check/src/unify_type.rs
@@ -637,7 +637,7 @@ struct Merge<'e> {
 impl<'a, 'e> Unifier<State<'a>, ArcType> for Merge<'e> {
     fn report_error(unifier: &mut UnifierState<Self>,
                     error: UnifyError<ArcType, TypeError<Symbol>>) {
-        unifier.unifier.errors.push(error);
+        unifier.unifier.errors.error(error);
     }
 
     fn try_match(unifier: &mut UnifierState<Self>, l: &ArcType, r: &ArcType) -> Option<ArcType> {
@@ -662,7 +662,7 @@ impl<'a, 'e> Unifier<State<'a>, ArcType> for Merge<'e> {
                             Type::Variable(ref var) if var.id > r_var.id => {
                                 let error = UnifyError::Other(TypeError::UnableToGeneralize(l_gen.id
                                     .clone()));
-                                unifier.unifier.errors.push(error);
+                                unifier.unifier.errors.error(error);
                                 return None;
                             }
                             _ => l,
@@ -698,7 +698,7 @@ impl<'a, 'e> Unifier<State<'a>, ArcType> for Merge<'e> {
         match result {
             Ok(typ) => typ,
             Err(error) => {
-                unifier.unifier.errors.push(error);
+                unifier.unifier.errors.error(error);
                 Some(subs.new_var())
             }
         }
@@ -743,8 +743,10 @@ mod tests {
         let state = State::new(&env, &subs);
         let result = unify(&subs, state, &l, &r);
         assert_eq!(result,
-                   Err(Errors::from(vec![TypeMismatch(Type::int(), Type::string()),
-                                         TypeMismatch(Type::string(), Type::int())])));
+                   Err(Errors {
+                       errors: vec![TypeMismatch(Type::int(), Type::string()),
+                                    TypeMismatch(Type::string(), Type::int())],
+                   }));
     }
 
     #[test]
diff --git a/parser/Cargo.toml b/parser/Cargo.toml
index 77004e05..afb41d36 100644
--- a/parser/Cargo.toml
+++ b/parser/Cargo.toml
@@ -10,20 +10,13 @@ description = "The parser for the gluon programming language"
 repository = "https://github.com/gluon-lang/gluon"
 documentation = "https://docs.rs/gluon"
 
-build = "build.rs"
-
 [dependencies]
+combine-language = "=2.0.0-beta4"
+combine = "=2.0.0-beta3"
 env_logger = { version = "0.3.4", optional = true }
-quick-error = "1.0.0"
-lalrpop-util = "0.12.4"
 log = "0.3.6"
 gluon_base = { path = "../base", version = "0.2.2" }
-
-[dev-dependencies]
 collect-mac = "0.1.0"
 
-[build-dependencies]
-lalrpop = "0.12.4"
-
 [features]
 test = ["env_logger"]
diff --git a/parser/build.rs b/parser/build.rs
deleted file mode 100644
index 1307ee2d..00000000
--- a/parser/build.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-extern crate lalrpop;
-
-fn main() {
-    lalrpop::Configuration::new()
-        .process_current_dir()
-        .unwrap();
-    println!("cargo:rerun-if-changed=src/grammar.lalrpop");
-}
diff --git a/parser/src/grammar.lalrpop b/parser/src/grammar.lalrpop
deleted file mode 100644
index 3a07441d..00000000
--- a/parser/src/grammar.lalrpop
+++ /dev/null
@@ -1,426 +0,0 @@
-use base::ast::{Alternative, Array, Expr, Lambda, Literal, Pattern, SpannedExpr, TypeBinding, TypedIdent, ValueBinding};
-use base::kind::Kind;
-use base::pos::{self, BytePos, Spanned};
-use base::types::{Alias, ArcType, BuiltinType, Field, Generic, Type};
-use std::str::FromStr;
-
-use token::Token;
-
-use {Error, ErrorEnv, FieldExpr, FieldPattern, MutIdentEnv};
-
-grammar<'input, 'env, Id>(src: &'input str, env: MutIdentEnv<'env, Id>, errors: ErrorEnv<'env, 'input>)
-    where Id: Clone;
-
-extern {
-    type Location = BytePos;
-    type Error = Error;
-
-    enum Token<'input> {
-        "Identifier" => Token::Identifier(<&'input str>),
-        "Operator" => Token::Operator(<&'input str>),
-        "StringLiteral" => Token::StringLiteral(<String>),
-        "CharLiteral" => Token::CharLiteral(<char>),
-        "IntLiteral" => Token::IntLiteral(<i64>),
-        "ByteLiteral" => Token::ByteLiteral(<u8>),
-        "FloatLiteral" => Token::FloatLiteral(<f64>),
-        "DocComment" => Token::DocComment(<String>),
-
-        "and" => Token::And,
-        "else" => Token::Else,
-        "if" => Token::If,
-        "in" => Token::In,
-        "let" => Token::Let,
-        "match" => Token::Match,
-        "then" => Token::Then,
-        "type" => Token::Type,
-        "with" => Token::With,
-
-        ":" => Token::Colon,
-        "," => Token::Comma,
-        "." => Token::Dot,
-        "=" => Token::Equals,
-        "\\" => Token::Lambda,
-        "|" => Token::Pipe,
-        "->" => Token::RArrow,
-
-        "{" => Token::LBrace,
-        "[" => Token::LBracket,
-        "(" => Token::LParen,
-
-        "}" => Token::RBrace,
-        "]" => Token::RBracket,
-        ")" => Token::RParen,
-
-        "OpenBlock" => Token::OpenBlock,
-        "CloseBlock" => Token::CloseBlock,
-        "Semi" => Token::Semi,
-    }
-}
-
-// Utils
-
-Comma<Rule>: Vec<Rule> =
-    <rules: (<Rule> ",")*> <last: Rule?> => {
-        let mut rules = rules;
-        rules.extend(last);
-        rules
-    };
-
-Sp<Rule>: Spanned<Rule, BytePos> =
-    <l: @L> <rule: Rule> <r: @R> =>
-        pos::spanned2(l, r, rule);
-
-IdentStr: &'input str = {
-    "Identifier" => <>,
-    "(" <"Operator"> ")" => <>,
-};
-
-Ident: Id =
-    IdentStr => env.from_str(<>);
-
-Operator: TypedIdent<Id> =
-    "Operator" => TypedIdent::new(env.from_str(<>));
-
-DocComment: String =
-    "DocComment"+ => <>.join("\n");
-
-// Types
-
-RecordField: Field<Id> =
-    <Ident> ":" <Type> => Field::new(<>);
-
-VariantField: (Id, Vec<ArcType<Id>>) =
-    "|" <Ident> <AtomicType*> => (<>);
-
-TypeBinding: TypeBinding<Id> = {
-    <id: Ident> <params: Ident*> "=" <row: VariantField+> => {
-        let params: Vec<_> = params.into_iter()
-            .map(|id| Generic { kind: Kind::variable(0), id: id })
-            .collect();
-
-        let typ_args = params.iter().cloned().map(Type::generic).collect();
-        let typ: ArcType<Id> = Type::app(Type::ident(id.clone()), typ_args);
-
-        let row = row.into_iter()
-            .map(|(id, params)| Field::new(id, Type::function(params, typ.clone())))
-            .collect();
-
-        TypeBinding {
-            comment: None,
-            name: id.clone(),
-            alias: Alias::new(id, params, Type::variant(row)),
-        }
-    },
-
-    <id: Ident> <params: Ident*> "=" <body: Type> => {
-        let params = params.into_iter()
-            .map(|id| Generic { kind: Kind::variable(0), id: id })
-            .collect();
-
-        TypeBinding {
-            comment: None,
-            name: id.clone(),
-            alias: Alias::new(id, params, body),
-        }
-    },
-};
-
-AtomicType: ArcType<Id> = {
-    "(" "->" ")" =>
-        Type::builtin(BuiltinType::Function),
-
-    IdentStr =>
-        match BuiltinType::from_str(<>) {
-            Ok(ty) => Type::builtin(ty),
-            Err(_) if (<>).starts_with(char::is_uppercase) => {
-                Type::ident(env.from_str(<>))
-            }
-            Err(_) => {
-                Type::generic(Generic {
-                    kind: Kind::variable(0),
-                    id: env.from_str(<>),
-                })
-            }
-        },
-
-    "(" <elems: Comma<Type>> ")" =>
-        match elems.len() {
-            // Unit type
-            0 => Type::unit(),
-            // Parenthesized type
-            1 => elems.into_iter().next().unwrap(),
-            // TODO: Tuples
-            _ => unimplemented!(),
-        },
-
-    "{" <row: Comma<RecordField>> "}" =>
-        Type::record(vec![], row),
-};
-
-AppType = {
-    AtomicType,
-
-    <ty: AtomicType> <args: AtomicType+> =>
-        Type::app(ty, args.into_iter().collect()),
-};
-
-Type = {
-    AppType,
-
-    <lhs: AppType> "->" <rhs: Type> =>
-        Type::function(vec![lhs], rhs),
-};
-
-// Patterns
-
-FieldPattern : FieldPattern<Id> = {
-    <id: Ident> "=" <body: Ident> =>
-        FieldPattern::Value(id, Some(body)),
-
-    <IdentStr> => {
-        let id = env.from_str(<>);
-        if <>.starts_with(char::is_uppercase) {
-            FieldPattern::Type(id, None)
-        } else {
-            FieldPattern::Value(id, None)
-        }
-    },
-};
-
-AtomicPattern: Pattern<Id> = {
-    <id: Ident> =>
-        if env.string(&id).starts_with(char::is_uppercase) {
-            Pattern::Constructor(TypedIdent::new(id), Vec::new())
-        } else {
-            Pattern::Ident(TypedIdent::new(id))
-        },
-
-    "(" <elems: Comma<Pattern>> ")" =>
-        match elems.len() {
-            // Unit pattern
-            0 => unimplemented!(),
-            // Parenthesized pattern
-            1 => elems.into_iter().next().unwrap(),
-            // TODO: Tuples
-            _ => unimplemented!(),
-        },
-
-    "{" <fields: Comma<FieldPattern>> "}" => {
-        let mut types = Vec::new();
-        let mut values = Vec::new();
-
-        for field in fields {
-            match field {
-                FieldPattern::Type(id, typ) => types.push((id, typ)),
-                FieldPattern::Value(id, field) => values.push((id, field)),
-            }
-        }
-
-        Pattern::Record {
-            typ: Type::hole(),
-            types: types,
-            fields: values,
-        }
-    },
-};
-
-Pattern = {
-    AtomicPattern,
-
-    <id: Ident> <args: Ident+> => {
-        let id = TypedIdent::new(id);
-        let args = args.into_iter()
-                       .map(TypedIdent::new)
-                       .collect();
-
-        Pattern::Constructor(id, args)
-    },
-};
-
-// Expressions
-
-Literal: Literal = {
-    "StringLiteral" => Literal::String(<>),
-    "CharLiteral" => Literal::Char(<>),
-    "IntLiteral" => Literal::Int(<>),
-    "ByteLiteral" => Literal::Byte(<>),
-    "FloatLiteral" => Literal::Float(<>),
-};
-
-Alternative: Alternative<Id> =
-    "|" <pat: Sp<Pattern>> "->" <expr: Sp<BlockExpr>> => {
-        Alternative {
-            pattern: pat,
-            expr: super::shrink_hidden_spans(expr),
-        }
-    };
-
-FieldExpr: FieldExpr<Id> = {
-    <id: Ident> "=" <body: SpExpr> => {
-        FieldExpr::Value(id, Some(body))
-    },
-
-    <IdentStr> => {
-        let id = env.from_str(<>);
-        if <>.starts_with(char::is_uppercase) {
-            FieldExpr::Type(id, None)
-        } else {
-            FieldExpr::Value(id, None)
-        }
-    },
-};
-
-ValueBinding: ValueBinding<Id> = {
-    <comment: DocComment?> <name: Sp<AtomicPattern>> <typ: (":" <Type>)?> "=" <body: SpExpr> =>
-        ValueBinding {
-            comment: comment,
-            name: name,
-            typ: typ.unwrap_or_else(Type::hole),
-            args: vec![],
-            expr: body,
-        },
-
-    <comment: DocComment?> <name: Sp<Ident>> <args: Ident+> <typ: (":" <Type>)?> "=" <body: SpExpr> =>
-        ValueBinding {
-            comment: comment,
-            name: name.map(TypedIdent::new).map(Pattern::Ident),
-            typ: typ.unwrap_or_else(Type::hole),
-            args: args.into_iter().map(TypedIdent::new).collect(),
-            expr: body,
-        },
-};
-
-AtomicExpr: Expr<Id> = {
-    <id: Ident> =>
-        Expr::Ident(TypedIdent::new(id)),
-
-    <lit: Literal> =>
-        Expr::Literal(lit),
-
-    // TODO: Getters
-    // "(" "." <id: Ident> ")" =>
-    //     Expr::Getter(id),
-
-    <expr: Sp<AtomicExpr>> "." <id: Ident> =>
-        Expr::Projection(Box::new(expr), id, Type::hole()),
-
-    <expr: Sp<AtomicExpr>> "." <err: !> => {
-        errors.push(err.error);
-        Expr::Projection(Box::new(expr), env.from_str(""), Type::hole())
-    },
-
-    "(" <elems: Comma<SpExpr>> ")" =>
-        match elems.len() {
-            // Unit expression
-            0 => Expr::Tuple(vec![]),
-            // Parenthesized expression - wrap in a block to ensure
-            // that it survives operator reparsing
-            1 => Expr::Block(elems),
-            // TODO: Tuples
-            _ => unimplemented!(),
-        },
-
-    "[" <elems: Comma<SpExpr>> "]" => Expr::Array(Array {
-            typ: Type::hole(),
-            exprs: elems,
-        }),
-
-    "{" <fields: Comma<FieldExpr>> "}" => {
-        let mut types = Vec::new();
-        let mut values = Vec::new();
-
-        for field in fields {
-            match field {
-                FieldExpr::Type(id, typ) => types.push((id, typ)),
-                FieldExpr::Value(id, expr) => values.push((id, expr)),
-            }
-        }
-
-        Expr::Record {
-            typ: Type::hole(),
-            types: types,
-            exprs: values,
-        }
-    },
-};
-
-AppExpr = {
-    AtomicExpr,
-
-    <expr: Sp<AtomicExpr>> <args: Sp<AtomicExpr>+> =>
-        Expr::App(Box::new(expr), args),
-};
-
-InfixExpr = {
-    AppExpr,
-
-    "\\" <args: Ident+> "->" <body: SpExpr> =>
-        Expr::Lambda(Lambda {
-            id: TypedIdent::new(env.from_str("")),
-            args: args.into_iter().map(TypedIdent::new).collect(),
-            body: Box::new(body),
-        }),
-
-    <lhs: Sp<AppExpr>> <op: Sp<Operator>> <rhs: Sp<InfixExpr>> =>
-        Expr::Infix(Box::new(lhs), op, Box::new(rhs)),
-};
-
-AndValueBinding: ValueBinding<Id> =
-    <comment: DocComment?> "and" <binding: ValueBinding> => {
-        let mut binding = binding;
-        binding.comment = comment;
-        binding
-    };
-
-AndTypeBinding: TypeBinding<Id> =
-    <comment: DocComment?> "and" <binding: TypeBinding> => {
-        let mut binding = binding;
-        binding.comment = comment;
-        binding
-    };
-
-Expr: Expr<Id> = {
-    InfixExpr,
-
-    "if" <pred: SpExpr> "then" <if_true: SpExpr> "else" <if_false: SpExpr> =>
-        Expr::IfElse(Box::new(pred), Box::new(if_true), Box::new(if_false)),
-
-    "match" <input: SpExpr> "with" <arms: Alternative+> =>
-        Expr::Match(Box::new(input), arms),
-
-    <comment: DocComment?> "let" <first: ValueBinding> <bindings: AndValueBinding*> "in" <body: SpExpr> => {
-        let mut first = first;
-        let mut bindings = bindings;
-        first.comment = comment;
-        bindings.insert(0, first);
-
-        Expr::LetBindings(bindings, Box::new(body))
-    },
-
-    <comment: DocComment?> "type" <first: TypeBinding> <bindings: AndTypeBinding*> "in" <body: SpExpr> => {
-        let mut first = first;
-        let mut bindings = bindings;
-        first.comment = comment;
-        bindings.insert(0, first);
-
-        Expr::TypeBindings(bindings, Box::new(body))
-    },
-
-    BlockExpr,
-};
-
-BlockExpr: Expr<Id> = {
-    "OpenBlock" <exprs: (<SpExpr> "Semi")*> <last: SpExpr> "CloseBlock" => {
-        let mut exprs = exprs;
-        exprs.push(last);
-        Expr::Block(exprs)
-    },
-};
-
-SpExpr: SpannedExpr<Id> = {
-    <expr: Sp<Expr>> => super::shrink_hidden_spans(expr),
-};
-
-pub TopExpr: SpannedExpr<Id> = {
-    <expr: SpExpr> => expr,
-};
diff --git a/parser/src/infix.rs b/parser/src/infix.rs
deleted file mode 100644
index 7f961b4e..00000000
--- a/parser/src/infix.rs
+++ /dev/null
@@ -1,568 +0,0 @@
-//! Infix expressions in gluon are initially parsed as if they were all left-
-//! associative with the same precedence. Therefore we need to rebalance them
-//! after the fact.
-
-use base::ast::{Expr, IdentEnv, Literal, MutVisitor, SpannedExpr, SpannedIdent, walk_mut_expr};
-use base::error::Errors;
-use base::fnv::FnvMap;
-use base::pos::{self, BytePos, Spanned};
-use std::cmp::Ordering;
-use std::error::Error as StdError;
-use std::fmt;
-use std::marker::PhantomData;
-use std::mem;
-use std::ops::Index;
-
-/// The fixity (associativity) of an infix operator
-#[derive(Copy, Clone, Debug, PartialEq)]
-pub enum Fixity {
-    /// Left operator associativity.
-    ///
-    /// For example, when the `(~)` operator is left-associative:
-    ///
-    /// ```text
-    /// x ~ y ~ z ≡ (x ~ y) ~ z
-    /// ```
-    Left,
-    /// Right operator associativity.
-    ///
-    /// For example, when the `(~)` operator is right-associative:
-    ///
-    /// ```text
-    /// x ~ y ~ z ≡ x ~ (y ~ z)
-    /// ```
-    Right,
-}
-
-impl fmt::Display for Fixity {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match *self {
-            Fixity::Left => write!(f, "infixl"),
-            Fixity::Right => write!(f, "infixr"),
-        }
-    }
-}
-
-/// Metadata pertaining to an infix operator
-#[derive(Copy, Clone, Debug, PartialEq)]
-pub struct OpMeta {
-    /// The precedence of the operator
-    pub precedence: i32,
-    /// The fixity of the operator
-    pub fixity: Fixity,
-}
-
-impl OpMeta {
-    fn new(precedence: i32, fixity: Fixity) -> OpMeta {
-        OpMeta {
-            precedence: precedence,
-            fixity: fixity,
-        }
-    }
-}
-
-impl fmt::Display for OpMeta {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{} {}", self.fixity, self.precedence)
-    }
-}
-
-/// A table of operator metadata
-pub struct OpTable {
-    pub operators: FnvMap<String, OpMeta>,
-    pub default_meta: OpMeta,
-}
-
-impl OpTable {
-    fn new<I>(ops: I) -> OpTable
-        where I: IntoIterator<Item = (&'static str, OpMeta)>,
-    {
-        OpTable {
-            operators: ops.into_iter().map(|(name, op)| (name.to_string(), op)).collect(),
-            default_meta: OpMeta::new(9, Fixity::Left),
-        }
-    }
-}
-
-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)),
-        ])
-    }
-}
-
-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
-            }
-        })
-    }
-}
-
-pub struct Reparser<'s, Id: 's> {
-    operators: OpTable,
-    symbols: &'s IdentEnv<Ident = Id>,
-    errors: Errors<Spanned<Error, BytePos>>,
-    _marker: PhantomData<Id>,
-}
-
-impl<'s, Id> Reparser<'s, Id> {
-    pub fn new(operators: OpTable, symbols: &'s IdentEnv<Ident = Id>) -> Reparser<'s, Id> {
-        Reparser {
-            operators: operators,
-            symbols: symbols,
-            errors: Errors::new(),
-            _marker: PhantomData,
-        }
-    }
-
-    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()))
-        } else {
-            Ok(())
-        }
-    }
-}
-
-impl<'s, Id> MutVisitor for Reparser<'s, Id> {
-    type Ident = 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 expr = mem::replace(e, dummy);
-            match reparse(expr, self.symbols, &self.operators) {
-                Ok(expr) => {
-                    *e = expr;
-                }
-                Err(err) => self.errors.push(err),
-            }
-        }
-        walk_mut_expr(self, e);
-    }
-}
-
-#[derive(Clone, Debug, PartialEq)]
-pub enum Error {
-    ConflictingFixities((String, OpMeta), (String, OpMeta)),
-}
-
-impl fmt::Display for Error {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        use self::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)
-            }
-        }
-    }
-}
-
-impl StdError for Error {
-    fn description(&self) -> &str {
-        "Conflicting fixities at the same precedence level"
-    }
-}
-
-/// Reconstruct the infix expression using the correct associativities
-/// and precedences.
-///
-/// 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>> {
-    use base::pos;
-    use self::Error::*;
-
-    let make_op = |lhs: Box<SpannedExpr<Id>>, op, rhs: Box<SpannedExpr<Id>>| {
-        let span = pos::span(lhs.span.start, rhs.span.end);
-        Box::new(pos::spanned(span, Expr::Infix(lhs, op, rhs)))
-    };
-
-    let mut infixes = Infixes::new(expr);
-    let mut arg_stack = Vec::new();
-    let mut op_stack = Vec::new();
-
-    while let Some(token) = infixes.next() {
-        match token {
-            InfixToken::Arg(next_expr) => arg_stack.push(next_expr),
-            InfixToken::Op(next_op) => {
-                let stack_op = match op_stack.pop() {
-                    Some(stack_op) => stack_op,
-                    None => {
-                        op_stack.push(next_op);
-                        continue;
-                    }
-                };
-
-                let next_op_meta = operators[symbols.string(&next_op.value.name)];
-                let stack_op_meta = operators[symbols.string(&stack_op.value.name)];
-
-                match i32::cmp(&next_op_meta.precedence, &stack_op_meta.precedence) {
-                    // Reduce
-                    Ordering::Less => {
-                        let rhs = arg_stack.pop().unwrap();
-                        let lhs = arg_stack.pop().unwrap();
-
-                        infixes.next_op = Some(next_op);
-                        arg_stack.push(make_op(lhs, stack_op, rhs));
-                    }
-                    // Shift
-                    Ordering::Greater => {
-                        op_stack.push(stack_op);
-                        op_stack.push(next_op);
-                    }
-                    Ordering::Equal => {
-                        match (next_op_meta.fixity, stack_op_meta.fixity) {
-                            // Reduce
-                            (Fixity::Left, Fixity::Left) => {
-                                let rhs = arg_stack.pop().unwrap();
-                                let lhs = arg_stack.pop().unwrap();
-
-                                infixes.next_op = Some(next_op);
-                                arg_stack.push(make_op(lhs, stack_op, rhs));
-                            }
-                            // Shift
-                            (Fixity::Right, Fixity::Right) => {
-                                op_stack.push(stack_op);
-                                op_stack.push(next_op);
-                            }
-                            // Conflicting fixities at the same precedence level!
-                            (Fixity::Left, Fixity::Right) |
-                            (Fixity::Right, Fixity::Left) => {
-                                let next_op_name = symbols.string(&next_op.value.name).to_string();
-                                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));
-
-                                return Err(pos::spanned(span, error));
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    for op in op_stack.into_iter().rev() {
-        let rhs = arg_stack.pop().unwrap();
-        let lhs = arg_stack.pop().unwrap();
-        arg_stack.push(make_op(lhs, op, rhs));
-    }
-
-    assert_eq!(arg_stack.len(), 1);
-
-    Ok(*arg_stack.pop().unwrap())
-}
-
-#[derive(Debug, Clone, PartialEq)]
-enum InfixToken<Id> {
-    Arg(Box<SpannedExpr<Id>>),
-    // TODO: Make this spanned to allow for accurate error reporting
-    Op(SpannedIdent<Id>),
-}
-
-/// An iterator that takes an expression that has had its operators grouped
-/// with _right associativity_, and yeilds a sequence of `InfixToken`s. This
-/// is useful for reparsing the operators with their correct associativies
-/// and precedences.
-///
-/// For example, the expression:
-///
-/// ```text
-/// (1 + (2 ^ (4 * (6 - 8))))
-/// ```
-///
-/// Will result in the following iterations:
-///
-/// ```text
-/// Arg:  1
-/// Op:   +
-/// Arg:  2
-/// Op:   ^
-/// Arg:  4
-/// Op:   *
-/// Arg:  6
-/// Op:   -
-/// Arg:  8
-/// ```
-struct Infixes<Id> {
-    /// The next part of the expression that we need to flatten
-    remaining_expr: Option<Box<SpannedExpr<Id>>>,
-    /// Cached operator from a previous iteration
-    next_op: Option<SpannedIdent<Id>>,
-}
-
-impl<Id> Infixes<Id> {
-    fn new(expr: SpannedExpr<Id>) -> Infixes<Id> {
-        Infixes {
-            remaining_expr: Some(Box::new(expr)),
-            next_op: None,
-        }
-    }
-}
-
-impl<Id> Iterator for Infixes<Id> {
-    type Item = InfixToken<Id>;
-
-    fn next(&mut self) -> Option<InfixToken<Id>> {
-        if let Some(op) = self.next_op.take() {
-            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?
-            }
-        })
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use base::ast::{DisplayEnv, Expr, IdentEnv, Literal, SpannedExpr, TypedIdent};
-    use base::pos::{self, BytePos, Spanned};
-    use std::marker::PhantomData;
-
-    use super::{Fixity, Infixes, InfixToken, OpMeta, OpTable, reparse};
-    use super::Error::*;
-
-    pub struct MockEnv<T>(PhantomData<T>);
-
-    impl<T> MockEnv<T> {
-        pub fn new() -> MockEnv<T> {
-            MockEnv(PhantomData)
-        }
-    }
-
-    impl<T: AsRef<str>> DisplayEnv for MockEnv<T> {
-        type Ident = T;
-
-        fn string<'a>(&'a self, ident: &'a Self::Ident) -> &'a str {
-            ident.as_ref()
-        }
-    }
-
-    impl<T> IdentEnv for MockEnv<T>
-        where T: AsRef<str> + for<'a> From<&'a str>,
-    {
-        fn from_str(&mut self, s: &str) -> Self::Ident {
-            T::from(s)
-        }
-    }
-
-
-    fn no_loc<T>(value: T) -> Spanned<T, BytePos> {
-        pos::spanned2(BytePos::from(0), BytePos::from(0), value)
-    }
-
-    fn ident(name: &str) -> TypedIdent<String> {
-        TypedIdent::new(name.to_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)))
-    }
-
-    fn int(value: i64) -> Box<SpannedExpr<String>> {
-        Box::new(no_loc(Expr::Literal(Literal::Int(value))))
-    }
-
-    #[test]
-    fn infixes() {
-        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))];
-
-        assert_eq!(result, expected);
-    }
-
-    #[test]
-    fn reparse_single() {
-        let env = MockEnv::new();
-        let ops = OpTable::new(vec![]);
-
-        let expr = *op(int(1), "+", int(2));
-        let expected = Ok(expr.clone());
-
-        assert_eq!(reparse(expr, &env, &ops), expected);
-    }
-
-    #[test]
-    fn reparse_less_precedence() {
-        let env = MockEnv::new();
-        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)));
-        let expected = Ok(expr.clone());
-
-        assert_eq!(reparse(expr, &env, &ops), expected);
-    }
-
-    #[test]
-    fn reparse_greater_precedence() {
-        let env = MockEnv::new();
-        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)));
-        // (1 * 2) + 8
-        let expected = Ok(*op(op(int(1), "*", int(2)), "+", int(8)));
-
-        assert_eq!(reparse(expr, &env, &ops), expected);
-    }
-
-    #[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)),
-        ]);
-
-        // 1 + (2 - 8)
-        let expr = *op(int(1), "+", op(int(2), "-", int(8)));
-        // (1 + 2) - 8
-        let expected = Ok(*op(op(int(1), "+", int(2)), "-", int(8)));
-
-        assert_eq!(reparse(expr, &env, &ops), expected);
-    }
-
-    #[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)),
-        ]);
-
-        // 1 + (2 - 8)
-        let expr = *op(int(1), "+", op(int(2), "-", int(8)));
-        let expected = Ok(expr.clone());
-
-        assert_eq!(reparse(expr, &env, &ops), expected);
-    }
-
-    #[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)),
-        ]);
-
-        //  1  + (2  * (6   -  8))
-        let expr = *op(int(1), "+", op(int(2), "*", op(int(6), "-", int(8))));
-        // (1  + (2  *  6)) -  8
-        let expected = Ok(*op(op(int(1), "+", op(int(2), "*", int(6))), "-", int(8)));
-
-        assert_eq!(reparse(expr, &env, &ops), expected);
-    }
-
-    #[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)),
-        ]);
-
-        // 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 expected = Err(no_loc(error));
-
-        assert_eq!(reparse(expr, &env, &ops), expected);
-    }
-
-    #[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)),
-        ]);
-
-        // 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 expected = Err(no_loc(error));
-
-        assert_eq!(reparse(expr, &env, &ops), expected);
-    }
-}
diff --git a/parser/src/layout.rs b/parser/src/layout.rs
deleted file mode 100644
index 3a7c5324..00000000
--- a/parser/src/layout.rs
+++ /dev/null
@@ -1,408 +0,0 @@
-use base::pos::{self, BytePos, Column, Line, Location, Spanned};
-
-use token::{SpannedToken, Token};
-
-quick_error! {
-    #[derive(Debug, PartialEq)]
-    pub enum Error {
-        UnindentedTooFar {
-            description("line was unindented too far")
-        }
-    }
-}
-
-#[derive(Copy, Clone, Debug)]
-struct Offside {
-    location: Location,
-    context: Context,
-}
-
-impl Offside {
-    fn new(location: Location, context: Context) -> Offside {
-        Offside {
-            location: location,
-            context: context,
-        }
-    }
-}
-
-#[derive(Copy, Clone, Debug, PartialEq)]
-enum Context {
-    /// Context which contains several expressions/declarations separated by semicolons
-    Block { emit_semi: bool },
-    /// After brace token
-    Brace,
-    /// After bracket token
-    Bracket,
-    /// After paren token
-    Paren,
-    /// A simple expression
-    Expr,
-    /// In a let expression
-    Let,
-    /// In a type expression
-    Type,
-    /// In an if expression
-    If,
-    /// In a match clause
-    MatchClause,
-    /// In a lambda function
-    Lambda,
-}
-
-struct Contexts {
-    stack: Vec<Offside>,
-}
-
-impl Contexts {
-    fn new() -> Contexts {
-        Contexts { stack: Vec::new() }
-    }
-
-    fn last(&self) -> Option<&Offside> {
-        self.stack.last()
-    }
-
-    fn last_mut(&mut self) -> Option<&mut Offside> {
-        self.stack.last_mut()
-    }
-
-    fn pop(&mut self) -> Option<Offside> {
-        self.stack.pop()
-    }
-
-    fn push(&mut self, offside: Offside) -> Result<(), Error> {
-        self.check_unindentation_limit(offside)?;
-        self.stack.push(offside);
-        Ok(())
-    }
-
-    fn check_unindentation_limit(&mut self, offside: Offside) -> Result<(), Error> {
-        let mut skip_block = false;
-        for other_offside in self.stack.iter().rev() {
-            match other_offside.context {
-                Context::Lambda => {
-                    skip_block = true;
-                    continue;
-                }
-                Context::Block { .. } if skip_block => continue,
-                Context::Brace | Context::Bracket | Context::Paren => return Ok(()),
-                // New context should not be unindented past the closest enclosing block context
-                Context::MatchClause |
-                Context::Type |
-                Context::Let |
-                Context::Block { .. } if offside.location.column <
-                                         other_offside.location.column => (),
-                _ => continue,
-            }
-            debug!("Unindentation error: {:?} < {:?}", offside, other_offside);
-            return Err(Error::UnindentedTooFar);
-        }
-        Ok(())
-    }
-}
-
-pub struct Layout<'input, Tokens> {
-    tokens: Tokens,
-    unprocessed_tokens: Vec<SpannedToken<'input>>,
-    indent_levels: Contexts,
-}
-
-impl<'input, Tokens> Layout<'input, Tokens>
-    where Tokens: Iterator<Item = SpannedToken<'input>>,
-{
-    pub fn new(tokens: Tokens) -> Layout<'input, Tokens> {
-        Layout {
-            tokens: tokens,
-            unprocessed_tokens: Vec::new(),
-            indent_levels: Contexts::new(),
-        }
-    }
-
-    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)
-            })
-        })
-    }
-
-    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)
-    }
-
-    fn scan_for_next_block(&mut self, context: Context) -> Result<(), Error> {
-        let next = self.next_token();
-        let span = next.span;
-        self.unprocessed_tokens.push(next);
-        if let Context::Block { .. } = context {
-            self.unprocessed_tokens.push(pos::spanned(span, Token::OpenBlock));
-        }
-        self.indent_levels.push(Offside::new(span.start, context))
-    }
-
-    fn layout_next_token(&mut self) -> Result<SpannedToken<'input>, Error> {
-        use std::cmp::Ordering;
-
-        let mut token = self.next_token();
-        if token.value == Token::EOF {
-            token.span.start.column = Column::from(0);
-        }
-
-        loop {
-            // Retrieve the current indentation level if one exists
-            let offside = match (&token.value, self.indent_levels.last().cloned()) {
-                (_, Some(offside)) => offside,
-                (&Token::EOF, None) => return Ok(token),
-                (_, None) => {
-                    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));
-                }
-            };
-
-            debug!("--------\n{:?}\n{:?}", token, offside);
-
-            match (&token.value, offside.context) {
-                (&Token::Comma, Context::Brace) |
-                (&Token::Comma, Context::Bracket) => return Ok(token),
-
-                // If it is closing token we remove contexts until a context for that token is found
-                (&Token::In, _) |
-                (&Token::CloseBlock, _) |
-                (&Token::Else, _) |
-                (&Token::RBrace, _) |
-                (&Token::RBracket, _) |
-                (&Token::RParen, _) |
-                (&Token::Comma, _) => {
-                    self.indent_levels.pop();
-
-                    match (&token.value, offside.context) {
-                        (&Token::Else, Context::If) => (),
-                        (&Token::RBrace, Context::Brace) |
-                        (&Token::RBracket, Context::Bracket) |
-                        (&Token::RParen, Context::Paren) => return Ok(token),
-                        (&Token::CloseBlock, Context::Block { .. }) => {
-                            if let Some(offside) = self.indent_levels.last_mut() {
-                                // The enclosing block should not emit a block separator for the next
-                                // expression
-                                if let Context::Block { ref mut emit_semi, .. } = offside.context {
-                                    *emit_semi = false;
-                                }
-                            }
-                            return Ok(token);
-                        }
-                        (&Token::In, Context::Let) |
-                        (&Token::In, Context::Type) => {
-                            let location = {
-                                let offside = self.indent_levels
-                                    .last_mut()
-                                    .expect("No top level block found");
-                                // The enclosing block should not emit a block separator for the next
-                                // expression
-                                if let Context::Block { ref mut emit_semi, .. } = offside.context {
-                                    *emit_semi = false;
-                                }
-                                offside.location
-                            };
-
-                            // Inject a block to ensure that a sequence of expressions end up in the `let` body
-                            // ```
-                            // let x = 1
-                            // a
-                            // 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 });
-                            self.indent_levels.push(offside)?;
-                            self.unprocessed_tokens
-                                .push(pos::spanned(token.span, Token::OpenBlock));
-
-                            return Ok(token);
-                        }
-                        (_, Context::Block { .. }) => {
-                            return Ok(self.layout_token(token, Token::CloseBlock));
-                        }
-                        (_, _) => continue,
-                    }
-                }
-                (_, _) => (),
-            }
-
-            // Next we check offside rules for each of the contexts
-            let ordering = token.span.start.column.cmp(&offside.location.column);
-            match (offside.context, ordering) {
-                (Context::Block { .. }, Ordering::Less) => {
-                    self.unprocessed_tokens.push(token.clone());
-                    token.value = Token::CloseBlock;
-                    continue;
-                }
-                (Context::Block { emit_semi: true }, Ordering::Equal) => {
-                    if let Some(offside) = self.indent_levels.last_mut() {
-                        // The enclosing block should not emit a block separator for the
-                        // next expression
-                        if let Context::Block { ref mut emit_semi, .. } = offside.context {
-                            *emit_semi = false;
-                        }
-                    }
-                    return Ok(self.layout_token(token, Token::Semi));
-                }
-                (Context::Block { emit_semi: false }, Ordering::Equal) => {
-                    match token.value {
-                        Token::DocComment(_) |
-                        Token::OpenBlock => (),
-                        _ => {
-                            // If it is the first token in a sequence we dont want to emit a
-                            // separator
-                            if let Some(offside) = self.indent_levels.last_mut() {
-                                if let Context::Block { ref mut emit_semi, .. } = offside.context {
-                                    *emit_semi = true;
-                                }
-                            }
-                        }
-                    }
-                }
-                (Context::Expr, _) |
-                (Context::Lambda, _) => {
-                    if ordering != Ordering::Greater {
-                        self.indent_levels.pop();
-                        continue;
-                    }
-                }
-                (Context::MatchClause, _) => {
-                    // Must allow `|` to be on the same line
-                    if ordering == Ordering::Less ||
-                       (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 => {
-                    // Insert an `in` token
-                    self.indent_levels.pop();
-                    let location = {
-                        let offside =
-                            self.indent_levels.last_mut().expect("No top level block found");
-                        // The enclosing block should not emit a block separator for the next
-                        // expression
-                        if let Context::Block { ref mut emit_semi, .. } = offside.context {
-                            *emit_semi = false;
-                        }
-                        offside.location
-                    };
-                    let span = token.span;
-                    let result = Ok(self.layout_token(token, Token::In));
-
-                    // Inject a block to ensure that a sequence of expressions end up in the `let` body
-                    // ```
-                    // let x = 1
-                    // a
-                    // 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 });
-                    self.indent_levels.push(offside)?;
-                    self.unprocessed_tokens.push(pos::spanned(span, Token::OpenBlock));
-
-                    return result;
-                }
-                _ => (),
-            }
-
-            // Some tokens directly insert a new context when emitted
-            let push_context = match token.value {
-                Token::Let => Some(Context::Let),
-                Token::If => Some(Context::If),
-                Token::Type => Some(Context::Type),
-                Token::Match => Some(Context::Expr),
-                Token::Lambda => Some(Context::Lambda),
-                Token::LBrace => Some(Context::Brace),
-                Token::LBracket => Some(Context::Bracket),
-                Token::LParen => Some(Context::Paren),
-                _ => None,
-            };
-            if let Some(context) = push_context {
-                let offside = Offside::new(token.span.start, context);
-                return self.indent_levels.push(offside).map(move |()| token);
-            }
-
-            // For other tokens we need to scan for the next token to get its position
-            match (&token.value, offside.context) {
-                (&Token::In, context) => {
-                    self.indent_levels.pop();
-                    if let Context::Block { .. } = context {
-                        return Ok(self.layout_token(token, Token::CloseBlock));
-                    }
-                }
-
-                (&Token::Equals, Context::Let) |
-                (&Token::RArrow, Context::Lambda) |
-                (&Token::RArrow, Context::MatchClause) |
-                (&Token::Then, _) => self.scan_for_next_block(Context::Block { emit_semi: false })?,
-                (&Token::With, _) => self.scan_for_next_block(Context::MatchClause)?,
-
-                (&Token::Else, _) => {
-                    let next = self.next_token();
-                    // Need to allow "else if" expressions so avoid inserting a block for those cases
-                    // (A block would be inserted at column 5 and we would then get unindentation
-                    // errors on the branches)
-                    // if x then
-                    //     1
-                    // else if y then
-                    //     2
-                    // else
-                    //     3
-                    let add_block = next.value != Token::If ||
-                                    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 })?;
-                    }
-                }
-                (&Token::Comma, _) => {
-                    // Prevent a semi to be emitted before the next token
-                    if let Some(offside) = self.indent_levels.last_mut() {
-                        // The enclosing block should not emit a block separator for the next
-                        // expression
-                        if let Context::Block { ref mut emit_semi, .. } = offside.context {
-                            *emit_semi = false;
-                        }
-                    }
-                }
-                (_, _) => (),
-            }
-
-            return Ok(token);
-        }
-    }
-}
-
-impl<'input, Tokens> Iterator for Layout<'input, Tokens>
-    where Tokens: Iterator<Item = SpannedToken<'input>>,
-{
-    type Item = Result<SpannedToken<'input>, Error>;
-
-    fn next(&mut self) -> Option<Result<SpannedToken<'input>, Error>> {
-        match self.layout_next_token() {
-            Ok(Spanned { value: Token::EOF, .. }) => None,
-            token => Some(token),
-        }
-    }
-}
diff --git a/parser/src/lexer.rs b/parser/src/lexer.rs
new file mode 100644
index 00000000..27ec7440
--- /dev/null
+++ b/parser/src/lexer.rs
@@ -0,0 +1,984 @@
+use std::cmp::Ordering;
+use std::fmt;
+
+use base::ast::is_operator_char;
+use base::pos::{BytePos, Column, Line, Location, Span, Spanned, NO_EXPANSION};
+
+use combine::primitives::{Consumed, Error as CombineError, RangeStream};
+use combine::combinator::EnvParser;
+use combine::range::{take, take_while};
+use combine::*;
+use combine::char::{alpha_num, char, letter, spaces, string};
+use combine_language::{LanguageEnv, LanguageDef, Identifier};
+
+#[derive(Clone)]
+pub struct LocatedStream<I> {
+    location: Location,
+    input: I,
+}
+
+impl<I> StreamOnce for LocatedStream<I>
+    where I: StreamOnce<Item = char>,
+{
+    type Item = I::Item;
+    type Range = I::Range;
+    type Position = Location;
+
+    fn uncons(&mut self) -> Result<Self::Item, CombineError<Self::Item, Self::Range>> {
+        self.input
+            .uncons()
+            .map(|ch| {
+                self.location.bump(ch);
+                // HACK: The layout algorithm expects `1` indexing for columns -
+                // this could be altered in the future though
+                self.location.column += Column::from(1);
+                ch
+            })
+    }
+
+    fn position(&self) -> Self::Position {
+        self.location
+    }
+}
+
+impl<'input, I> RangeStream for LocatedStream<I>
+    where I: RangeStream<Item = char, Range = &'input str>,
+{
+    fn uncons_range(&mut self,
+                    len: usize)
+                    -> Result<Self::Range, CombineError<Self::Item, Self::Range>> {
+        self.input
+            .uncons_range(len)
+            .map(|range| {
+                for ch in range.chars() {
+                    self.location.bump(ch)
+                }
+                range
+            })
+    }
+    fn uncons_while<F>(&mut self,
+                       mut predicate: F)
+                       -> Result<Self::Range, CombineError<Self::Item, Self::Range>>
+        where F: FnMut(Self::Item) -> bool,
+    {
+        let location = &mut self.location;
+        self.input.uncons_while(|t| {
+            if predicate(t.clone()) {
+                location.bump(t);
+                true
+            } else {
+                false
+            }
+        })
+    }
+}
+
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub enum Delimiter {
+    Brace,
+    Bracket,
+    Paren,
+}
+
+impl Delimiter {
+    fn as_str(&self) -> &'static str {
+        use self::Delimiter::*;
+        match *self {
+            Brace => "Brace",
+            Bracket => "Bracket",
+            Paren => "Paren",
+        }
+    }
+}
+
+impl fmt::Display for Delimiter {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        self.as_str().fmt(f)
+    }
+}
+
+#[derive(Clone, Copy, PartialEq, Debug)]
+pub enum IdentType {
+    /// Constructors are identifiers starting with an uppercase letter
+    Constructor,
+    /// An operator in identifier position (Example: (+), (-), (>>=))
+    Operator,
+    /// A normal variable
+    Variable,
+}
+
+pub type Error<Id> = CombineError<Token<Id>, Token<Id>>;
+
+#[derive(Clone, PartialEq, Debug)]
+pub enum Token<Id> {
+    Ident(Id, IdentType),
+    Operator(Id),
+    String(String),
+    Char(char),
+    Int(i64),
+    Byte(u8),
+    Float(f64),
+    DocComment(String),
+    Let,
+    And,
+    In,
+    Type,
+    Match,
+    With,
+    If,
+    Then,
+    Else,
+    Open(Delimiter),
+    Close(Delimiter),
+    Lambda,
+    RightArrow,
+    Colon,
+    Dot,
+    Comma,
+    Pipe,
+    Equal,
+    OpenBlock,
+    CloseBlock,
+    Semi,
+    EOF,
+}
+
+impl<Id> fmt::Display for Token<Id> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::Token::*;
+        use self::Delimiter::*;
+        let s = match *self {
+            Ident(..) => "Ident",
+            Operator(..) => "Operator",
+            String(..) => "String",
+            Char(..) => "Char",
+            Int(..) => "Int",
+            Byte(..) => "Byte",
+            Float(..) => "Float",
+            DocComment(..) => "DocComment",
+            Let => "Let",
+            And => "And",
+            In => "In",
+            Type => "Type",
+            Match => "Match",
+            With => "With",
+            If => "If",
+            Then => "Then",
+            Else => "Else",
+            Open(Brace) => "OpenBrace",
+            Close(Brace) => "CloseBrace",
+            Open(Paren) => "OpenParen",
+            Close(Paren) => "CloseParen",
+            Open(Bracket) => "OpenBracket",
+            Close(Bracket) => "CloseBracket",
+            Lambda => "Lambda",
+            RightArrow => "RightArrow",
+            Colon => "Colon",
+            Dot => "Dot",
+            Comma => "Comma",
+            Pipe => "Pipe",
+            Equal => "Equal",
+            OpenBlock => "OpenBlock",
+            CloseBlock => "CloseBlock",
+            Semi => "Semi",
+            EOF => "EOF",
+        };
+        s.fmt(f)
+    }
+}
+
+impl<Id> Token<Id> {
+    pub fn map<Id2, F>(&self, f: F) -> Token<Id2>
+        where F: FnOnce(&Id) -> Id2,
+    {
+        use self::Token::*;
+        match *self {
+            Ident(ref id, b) => Ident(f(id), b),
+            Operator(ref id) => Operator(f(id)),
+            String(ref s) => String(s.clone()),
+            Char(c) => Char(c),
+            Int(i) => Int(i),
+            Byte(i) => Byte(i),
+            Float(f) => Float(f),
+            DocComment(ref s) => DocComment(s.clone()),
+            Let => Let,
+            And => And,
+            In => In,
+            Type => Type,
+            Match => Match,
+            With => With,
+            If => If,
+            Then => Then,
+            Else => Else,
+            Open(d) => Open(d),
+            Close(d) => Close(d),
+            Lambda => Lambda,
+            RightArrow => RightArrow,
+            Colon => Colon,
+            Dot => Dot,
+            Comma => Comma,
+            Pipe => Pipe,
+            Equal => Equal,
+            OpenBlock => OpenBlock,
+            CloseBlock => CloseBlock,
+            Semi => Semi,
+            EOF => EOF,
+        }
+    }
+}
+
+pub type SpannedToken<Id> = Spanned<Token<Id>, Location>;
+
+#[derive(Clone, Debug)]
+pub struct Offside {
+    pub location: Location,
+    pub context: Context,
+}
+
+#[derive(Clone, Debug, PartialEq)]
+pub enum Context {
+    /// Context which contains several expressions/declarations separated by semicolons
+    Block { emit_semi: bool, needs_close: bool },
+    /// A simple expression
+    Expr,
+    Let,
+    Type,
+    If,
+    Then,
+    Delimiter(Delimiter),
+    MatchClause,
+    Lambda,
+}
+
+/// Parser passes the environment to each parser function
+type LanguageParser<'input: 'lexer, 'lexer, I: 'lexer, T> = EnvParser<&'lexer Lexer<'input, I>,
+                                                                      LocatedStream<I>,
+                                                                      T>;
+
+pub struct Contexts {
+    stack: Vec<Offside>,
+}
+
+impl Contexts {
+    pub fn last(&self) -> Option<&Offside> {
+        self.stack.last()
+    }
+
+    pub fn last_mut(&mut self) -> Option<&mut Offside> {
+        self.stack.last_mut()
+    }
+
+    pub fn pop(&mut self) -> Option<Offside> {
+        self.stack.pop()
+    }
+
+    pub fn push<Id>(&mut self, offside: Offside) -> Result<(), Error<Id>> {
+        self.check_unindentation_limit(&offside)?;
+        self.stack.push(offside);
+        Ok(())
+    }
+
+    pub fn replace<Id>(&mut self, offside: Offside) -> Result<(), Error<Id>> {
+        self.pop();
+        self.push(offside)
+    }
+
+    fn check_unindentation_limit<Id>(&mut self, offside: &Offside) -> Result<(), Error<Id>> {
+        let mut skip_block = false;
+        for other_offside in self.stack.iter().rev() {
+            match other_offside.context {
+                Context::Lambda => {
+                    skip_block = true;
+                    continue;
+                }
+                Context::Delimiter(_) => return Ok(()),
+                Context::Block { .. } if skip_block => continue,
+                // New context should not be unindented past the closest enclosing block context
+                Context::MatchClause |
+                Context::Type |
+                Context::Let |
+                Context::Block { .. } if offside.location.column <
+                                         other_offside.location.column => (),
+                _ => continue,
+            }
+            debug!("Unindentation error: {:?} < {:?}", offside, other_offside);
+            return Err(CombineError::Message("Line was unindented to far".into()));
+        }
+        Ok(())
+    }
+}
+
+pub struct Lexer<'input, I>
+    where I: RangeStream<Item = char, Range = &'input str>,
+{
+    pub env: LanguageEnv<'input, LocatedStream<I>>,
+    pub input: Option<LocatedStream<I>>,
+    pub unprocessed_tokens: Vec<SpannedToken<&'input str>>,
+    pub indent_levels: Contexts,
+    /// Since the parser will call `position` before retrieving the token we need to cache one
+    /// token so the span can be returned for it
+    next_token: Option<SpannedToken<&'input str>>,
+    end_span: Option<Span<Location>>,
+}
+
+impl<'input, I> Lexer<'input, I>
+    where I: RangeStream<Item = char, Range = &'input str> + 'input,
+          I::Range: fmt::Debug + 'input,
+{
+    pub fn new(input: I) -> Lexer<'input, I> {
+        let env = LanguageEnv::new(LanguageDef {
+            ident: Identifier {
+                start: letter().or(char('_')),
+                rest: alpha_num()
+                    .or(char('_'))
+                    .or(char('\'')),
+                // ["if", "then", "else", "let", "and", "in", "type", "case", "of"]
+                // .iter()
+                // .map(|x| (*x).into())
+                // .collect(),
+                reserved: Vec::new(),
+            },
+            op: Identifier {
+                start: satisfy(is_operator_char),
+                rest: satisfy(is_operator_char),
+                reserved: Vec::new(),
+            },
+            comment_start: satisfy(|_| false).map(|_| ()),
+            comment_end: satisfy(|_| false).map(|_| ()),
+            comment_line: satisfy(|_| false).map(|_| ()),
+        });
+
+        let mut lexer = Lexer {
+            env: env,
+            input: Some(LocatedStream {
+                location: Location {
+                    line: Line::from(0),
+                    column: Column::from(1),
+                    absolute: BytePos::from(0),
+                },
+                input: input,
+            }),
+            unprocessed_tokens: Vec::new(),
+            indent_levels: Contexts { stack: Vec::new() },
+            next_token: None,
+            end_span: None,
+        };
+        lexer.next_token = lexer.uncons_next().ok();
+        lexer
+    }
+
+    fn parser<'a, T>(&'a self,
+                     parser: fn(&Lexer<'input, I>, LocatedStream<I>)
+                                -> ParseResult<T, LocatedStream<I>>)
+                     -> LanguageParser<'input, 'a, I, T> {
+        env_parser(self, parser)
+    }
+
+    /// Parses an operator
+    fn op<'a>(&'a self) -> LanguageParser<'input, 'a, I, &'input str> {
+        self.parser(Lexer::parse_op)
+    }
+
+    fn parse_op(&self, input: LocatedStream<I>) -> ParseResult<&'input str, LocatedStream<I>> {
+        let initial = input.clone();
+        let ((builtin, op), _) = (optional((char('#'), take_while(char::is_alphabetic))),
+                                  try(self.env.op_())).parse_stream(input)?;
+        let len = builtin.map_or(0, |(c, typ)| c.len_utf8() + typ.len()) + op.len();
+        take(len).parse_stream(initial)
+    }
+
+    fn ident<'a>(&'a self) -> LanguageParser<'input, 'a, I, Token<&'input str>> {
+        self.parser(Lexer::parse_ident)
+    }
+
+    fn parse_ident(&self,
+                   input: LocatedStream<I>)
+                   -> ParseResult<Token<&'input str>, LocatedStream<I>> {
+        self.parser(Lexer::parse_ident2)
+            .map(|x| Token::Ident(x.0, x.1))
+            .parse_stream(input)
+    }
+
+    /// Identifier parser which returns the identifier as well as the type of the identifier
+    fn parse_ident2(&self,
+                    input: LocatedStream<I>)
+                    -> ParseResult<(&'input str, IdentType), LocatedStream<I>> {
+        let id = self.env.range_identifier_().map(|id| {
+            let typ = if id.starts_with(char::is_uppercase) {
+                IdentType::Constructor
+            } else {
+                IdentType::Variable
+            };
+            (id, typ)
+        });
+        let op = self.env.parens(self.env.range_op_()).map(|id| (id, IdentType::Operator));
+        try(id)
+            .or(try(op))
+            .parse_stream(input)
+    }
+
+    fn layout_independent_token(&mut self,
+                                token: SpannedToken<&'input str>)
+                                -> Result<SpannedToken<&'input str>, Error<&'input str>> {
+        layout(self, token)
+    }
+
+    fn id_to_keyword(&self, id: Token<&'input str>) -> Token<&'input str> {
+        let t = match id {
+            Token::Ident(id, _) => {
+                match id {
+                    "let" => Some(Token::Let),
+                    "type" => Some(Token::Type),
+                    "and" => Some(Token::And),
+                    "in" => Some(Token::In),
+                    "match" => Some(Token::Match),
+                    "with" => Some(Token::With),
+                    "if" => Some(Token::If),
+                    "then" => Some(Token::Then),
+                    "else" => Some(Token::Else),
+                    _ => None,
+                }
+            }
+            _ => None,
+        };
+        match t {
+            Some(t) => t,
+            _ => id,
+        }
+    }
+
+    pub fn next_token(&mut self) -> SpannedToken<&'input str> {
+        if let Some(token) = self.unprocessed_tokens.pop() {
+            return token;
+        }
+        let input = match self.input.take() {
+            Some(input) => input,
+            None => {
+                let loc = Location {
+                    line: Line::from(0),
+                    column: Column::from(1),
+                    absolute: BytePos::from(0),
+                };
+                return SpannedToken {
+                    span: Span {
+                        start: loc,
+                        end: loc,
+                        expansion_id: NO_EXPANSION,
+                    },
+                    value: Token::EOF,
+                };
+            }
+        };
+        let mut start = input.position();
+        let result = self.next_token_(&mut start, input);
+        match result {
+            Ok((token, input)) => {
+                let input = input.into_inner();
+                let end = input.position();
+                let input = match self.env.white_space().parse_stream(input.clone()) {
+                    Ok(((), input)) => input.into_inner(),
+                    Err(_) => input,
+                };
+                self.input = Some(input);
+                SpannedToken {
+                    span: Span {
+                        start: start,
+                        end: end,
+                        expansion_id: NO_EXPANSION,
+                    },
+                    value: token,
+                }
+            }
+            Err(err) => {
+                let err = err.into_inner();
+                debug!("Error tokenizing: {:?}", err);
+                let span = Span {
+                    start: start,
+                    end: start,
+                    expansion_id: NO_EXPANSION,
+                };
+                self.end_span = Some(span);
+                SpannedToken {
+                    span: span,
+                    value: Token::CloseBlock,
+                }
+            }
+        }
+    }
+
+    fn next_token_(&mut self,
+                   location: &mut Location,
+                   mut input: LocatedStream<I>)
+                   -> ParseResult<Token<&'input str>, LocatedStream<I>> {
+        loop {
+            // Skip all whitespace before the token
+            let parsed_spaces: Result<_, _> = spaces().parse_lazy(input).into();
+            let (_, new_input) = parsed_spaces?;
+            input = new_input.into_inner();
+            *location = input.position();
+            let (first, one_char_consumed) = any().parse_stream(input.clone())?;
+
+            // Decide how to tokenize depending on what the first char is
+            // ie if its an operator then more operators will follow
+            if is_operator_char(first) || first == '#' {
+                let (op, new_input) = self.op().parse_stream(input)?;
+                input = new_input.into_inner();
+                let tok = match op {
+                    "=" => Token::Equal,
+                    "->" => Token::RightArrow,
+                    "|" => Token::Pipe,
+                    _ => {
+                        if op.starts_with("///") {
+                            let mut comment = String::new();
+                            let ((), new_input) = try!(spaces().parse_stream(input));
+                            input = new_input.into_inner();
+                            // Merge consecutive line comments
+                            loop {
+                                let mut line = satisfy(|c| c != '\n' && c != '\r').iter(input);
+                                comment.extend(line.by_ref());
+                                comment.push('\n');
+                                let ((), new_input) = try!(line.into_result(()));
+                                input = new_input.into_inner();
+                                let mut p = spaces().with(try(string("///"))).skip(spaces());
+                                match p.parse_stream(input.clone()) {
+                                    Ok((_, new_input)) => input = new_input.into_inner(),
+                                    Err(_) => break,
+                                }
+                            }
+                            comment.pop();
+                            return Ok((Token::DocComment(comment), Consumed::Consumed(input)));
+                        } else if op.starts_with("/**") {
+                            return self.block_doc_comment(input);
+                        } else if op.starts_with("//") {
+                            let ((), new_input) =
+                                try!(skip_many(satisfy(|c| c != '\n' && c != '\r'))
+                                    .parse_lazy(input)
+                                    .into());
+                            input = new_input.into_inner();
+                            continue;
+                        } else if op.starts_with("/*") {
+                            // Skip over normal comments and try to parse a new token
+                            let ((), new_input) = self.skip_block_comment(input)?;
+                            input = new_input.into_inner();
+                            continue;
+                        } else {
+                            Token::Operator(op)
+                        }
+                    }
+                };
+                return Ok((tok, Consumed::Consumed(input)));
+            } else if first.is_digit(10) {
+                let int_or_byte = (self.env.integer_(), optional(char('b')));
+                return try(int_or_byte.skip(not_followed_by(string("."))))
+                    .and_then(|(i, byte)| {
+                        if byte.is_none() {
+                            Ok(Token::Int(i))
+                        } else {
+                            if i >= 0 && i <= 256 {
+                                Ok(Token::Byte(i as u8))
+                            } else {
+                                Err(CombineError::Message("Byte literal out of range".into()))
+                            }
+                        }
+                    })
+                    .or(self.env.float_().map(Token::Float))
+                    .parse_stream(input);
+            } else if first.is_alphabetic() || first == '_' {
+                return self.ident().map(|t| self.id_to_keyword(t)).parse_stream(input);
+            }
+
+            let tok = match first {
+                '(' => {
+                    match self.ident().map(|t| self.id_to_keyword(t)).parse_stream(input) {
+                        Ok(x) => return Ok(x),
+                        Err(_) => Token::Open(Delimiter::Paren),
+                    }
+                }
+                ')' => Token::Close(Delimiter::Paren),
+                '{' => Token::Open(Delimiter::Brace),
+                '}' => Token::Close(Delimiter::Brace),
+                '[' => Token::Open(Delimiter::Bracket),
+                ']' => Token::Close(Delimiter::Bracket),
+                ':' => Token::Colon,
+                ',' => Token::Comma,
+                '.' => Token::Dot,
+                '\\' => Token::Lambda,
+                '"' => return self.env.string_literal_().map(Token::String).parse_stream(input),
+                '\'' => return self.env.char_literal_().map(Token::Char).parse_stream(input),
+                _ => Token::EOF,
+            };
+            return Ok((tok, one_char_consumed));
+        }
+    }
+
+    fn skip_block_comment(&self, input: LocatedStream<I>) -> ParseResult<(), LocatedStream<I>> {
+        let mut block_doc_comment = parser(|input| {
+            let mut input = Consumed::Empty(input);
+            loop {
+                match input.clone()
+                    .combine(|input| try(string("*/")).parse_lazy(input).into()) {
+                    Ok((_, input)) => return Ok(((), input)),
+                    Err(_) => {
+                        match input.combine(|input| any().parse_stream(input)) {
+                            Ok((_, rest)) => {
+                                input = rest;
+                            }
+                            Err(err) => return Err(err),
+                        }
+                    }
+                }
+            }
+        });
+        block_doc_comment.parse_stream(input)
+    }
+
+    fn block_doc_comment(&self,
+                         input: LocatedStream<I>)
+                         -> ParseResult<Token<&'input str>, LocatedStream<I>> {
+        let mut block_doc_comment = parser(|input| {
+            let ((), mut input) = try!(spaces().parse_stream(input));
+            let mut out = String::new();
+            loop {
+                match input.clone()
+                    .combine(|input| try(string("*/")).parse_lazy(input).into()) {
+                    Ok((_, input)) => return Ok((Token::DocComment(out), input)),
+                    Err(_) => {
+                        match input.combine(|input| any().parse_stream(input)) {
+                            Ok((c, rest)) => {
+                                out.push(c);
+                                input = rest
+                            }
+                            Err(err) => return Err(err),
+                        }
+                    }
+                }
+            }
+        });
+        block_doc_comment.parse_stream(input)
+    }
+
+    fn layout_token(&mut self,
+                    token: SpannedToken<&'input str>,
+                    layout_token: Token<&'input str>)
+                    -> SpannedToken<&'input str> {
+        let span = token.span;
+        self.unprocessed_tokens.push(token);
+        SpannedToken {
+            span: span,
+            value: layout_token,
+        }
+    }
+
+    fn uncons_next(&mut self) -> Result<SpannedToken<&'input str>, Error<&'input str>> {
+        let token = self.next_token();
+        match self.layout_independent_token(token) {
+            Ok(SpannedToken { value: Token::EOF, .. }) => Err(Error::end_of_input()),
+            Ok(token) => {
+                debug!("Lex {:?}", token);
+                Ok(token)
+            }
+            Err(err) => {
+                if let Some(input) = self.input.take() {
+                    let loc = input.position();
+                    self.end_span = Some(Span {
+                        start: loc,
+                        end: loc,
+                        expansion_id: NO_EXPANSION,
+                    });
+                }
+                Err(err)
+            }
+        }
+    }
+}
+
+fn layout<'input, I>(lexer: &mut Lexer<'input, I>,
+                     mut token: SpannedToken<&'input str>)
+                     -> Result<SpannedToken<&'input str>, Error<&'input str>>
+    where I: RangeStream<Item = char, Range = &'input str> + 'input,
+          I::Range: fmt::Debug,
+{
+    if token.value == Token::EOF {
+        token.span.start.column = Column::from(0);
+    }
+    loop {
+        // Retrieve the current indentation level if one exists
+        let offside = match lexer.indent_levels.last().cloned() {
+            Some(offside) => offside,
+            None => {
+                if token.value == Token::EOF {
+                    return Ok(token);
+                }
+                lexer.indent_levels
+                    .push(Offside {
+                        context: Context::Block {
+                            emit_semi: false,
+                            needs_close: true,
+                        },
+                        location: token.span.start,
+                    })?;
+                debug!("Default block {:?}", token);
+                return Ok(lexer.layout_token(token, Token::OpenBlock));
+            }
+        };
+        debug!("--------\n{:?}\n{:?}", token, offside);
+        let ordering = token.span.start.column.cmp(&offside.location.column);
+
+        // If it is closing token we remove contexts until a context for that token is found
+        if [Token::In,
+            Token::CloseBlock,
+            Token::Else,
+            Token::Close(Delimiter::Brace),
+            Token::Close(Delimiter::Bracket),
+            Token::Close(Delimiter::Paren),
+            Token::Comma]
+            .iter()
+            .any(|t| *t == token.value) {
+
+            if token.value == Token::Comma &&
+               (offside.context == Context::Delimiter(Delimiter::Brace) ||
+                offside.context == Context::Delimiter(Delimiter::Bracket)) {
+                return Ok(token);
+            }
+            lexer.indent_levels.pop();
+            match (&token.value, &offside.context) {
+                (&Token::Else, &Context::If) => (),
+                (&Token::Close(close_delim), &Context::Delimiter(context_delim))
+                    if close_delim == context_delim => return Ok(token),
+                (&Token::In, &Context::Let) |
+                (&Token::In, &Context::Type) |
+                (&Token::CloseBlock, &Context::Block { .. }) => {
+                    if let Some(offside) = lexer.indent_levels.last_mut() {
+                        // The enclosing block should not emit a block separator for the next
+                        // expression
+                        if let Context::Block { ref mut emit_semi, .. } = offside.context {
+                            *emit_semi = false;
+                        }
+                    }
+                    return Ok(token);
+                }
+                _ => {
+                    match offside.context {
+                        Context::Block { needs_close: true, .. } => {
+                            return Ok(lexer.layout_token(token, Token::CloseBlock));
+                        }
+                        _ => (),
+                    }
+                    continue;
+                }
+            }
+        }
+        // Next we check offside rules for each of the contexts
+        match offside.context {
+            Context::Block { emit_semi, needs_close } => {
+                match ordering {
+                    Ordering::Less => {
+                        if needs_close {
+                            lexer.unprocessed_tokens.push(token.clone());
+                            token.value = Token::CloseBlock;
+                        } else {
+                            lexer.indent_levels.pop();
+                        }
+                        continue;
+                    }
+                    Ordering::Equal => {
+                        match token.value {
+                            _ if emit_semi => {
+                                if let Some(offside) = lexer.indent_levels.last_mut() {
+                                    // The enclosing block should not emit a block separator for the
+                                    // next expression
+                                    if let Context::Block { ref mut emit_semi, .. } =
+                                           offside.context {
+                                        *emit_semi = false;
+                                    }
+                                }
+                                return Ok(lexer.layout_token(token, Token::Semi));
+                            }
+                            Token::DocComment(_) |
+                            Token::OpenBlock => (),
+                            _ => {
+                                // If it is the first token in a sequence we dont want to emit a
+                                // separator
+                                if let Some(offside) = lexer.indent_levels.last_mut() {
+                                    if let Context::Block { ref mut emit_semi, .. } =
+                                           offside.context {
+                                        *emit_semi = true;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                    _ => (),
+                }
+            }
+            Context::Expr | Context::Lambda => {
+                if ordering != Ordering::Greater {
+                    lexer.indent_levels.pop();
+                    continue;
+                }
+            }
+            Context::MatchClause => {
+                // Must allow `|` to be on the same line
+                if ordering == Ordering::Less ||
+                   (ordering == Ordering::Equal && token.value != Token::Pipe) {
+                    lexer.indent_levels.pop();
+                    continue;
+                }
+            }
+            Context::Let | Context::Type => {
+                // `and` and `}` are allowed to be on the same line as the `let` or `type`
+                if ordering == Ordering::Equal && token.value != Token::And &&
+                   token.value != Token::Close(Delimiter::Brace) {
+                    // Insert an `in` token
+                    lexer.indent_levels.pop();
+                    if let Some(offside) = lexer.indent_levels.last_mut() {
+                        // The enclosing block should not emit a block separator for the next
+                        // expression
+                        if let Context::Block { ref mut emit_semi, .. } = offside.context {
+                            *emit_semi = false;
+                        }
+                    }
+                    return Ok(lexer.layout_token(token, Token::In));
+                }
+            }
+            _ => (),
+        }
+        // Some tokens directly inserts a new context when emitted
+        let push_context = match token.value {
+            Token::Let => Some(Context::Let),
+            Token::If => Some(Context::If),
+            Token::Type => Some(Context::Type),
+            Token::Match => Some(Context::Expr),
+            Token::Lambda => Some(Context::Lambda),
+            Token::Open(delim) => Some(Context::Delimiter(delim)),
+            _ => None,
+        };
+        if let Some(context) = push_context {
+            let offside = Offside {
+                location: token.span.start,
+                context: context,
+            };
+            return lexer.indent_levels.push(offside).map(move |()| token);
+        }
+        // For other tokens we need to scan for the next token to get its position
+        match token.value {
+            Token::In => {
+                lexer.indent_levels.pop();
+                if let Context::Block { needs_close: true, .. } = offside.context {
+                    return Ok(lexer.layout_token(token, Token::CloseBlock));
+                }
+            }
+            Token::Equal => {
+                if offside.context == Context::Let {
+                    scan_for_next_block(lexer,
+                                        Context::Block {
+                                            emit_semi: false,
+                                            needs_close: true,
+                                        })?;
+                }
+            }
+            Token::RightArrow => {
+                if offside.context == Context::MatchClause || offside.context == Context::Lambda {
+                    scan_for_next_block(lexer,
+                                        Context::Block {
+                                            emit_semi: false,
+                                            needs_close: true,
+                                        })?;
+                }
+            }
+            Token::Else => {
+                let next = lexer.next_token();
+                // Need to allow "else if" expressions so avoid inserting a block for those cases
+                // (A block would be inserted at column 5 and we would then get unindentation
+                // errors on the branches)
+                // if x then
+                //     1
+                // else if y then
+                //     2
+                // else
+                //     3
+                let add_block = next.value != Token::If ||
+                                next.span.start.line != token.span.start.line;
+                lexer.unprocessed_tokens.push(next);
+                if add_block {
+                    scan_for_next_block(lexer,
+                                        Context::Block {
+                                            emit_semi: false,
+                                            needs_close: true,
+                                        })?;
+                }
+            }
+            Token::Then => {
+                scan_for_next_block(lexer,
+                                    Context::Block {
+                                        emit_semi: false,
+                                        needs_close: true,
+                                    })?;
+            }
+            Token::Comma => {
+                // Prevent a semi to be emitted before the next token
+                if let Some(offside) = lexer.indent_levels.last_mut() {
+                    // The enclosing block should not emit a block separator for the next
+                    // expression
+                    if let Context::Block { ref mut emit_semi, .. } = offside.context {
+                        *emit_semi = false;
+                    }
+                }
+            }
+            Token::With => scan_for_next_block(lexer, Context::MatchClause)?,
+            _ => (),
+        }
+        return Ok(token);
+    }
+}
+
+fn scan_for_next_block<'input, 'a, I>(lexer: &mut Lexer<'input, I>,
+                                      context: Context)
+                                      -> Result<(), Error<&'input str>>
+    where I: RangeStream<Item = char, Range = &'input str> + 'input,
+          I::Range: fmt::Debug + 'input,
+{
+    let next = lexer.next_token();
+    let span = next.span;
+    lexer.unprocessed_tokens.push(next);
+    if let Context::Block { needs_close: true, .. } = context {
+        lexer.unprocessed_tokens.push(SpannedToken {
+            span: span,
+            value: Token::OpenBlock,
+        });
+    }
+    lexer.indent_levels.push(Offside {
+        location: span.start,
+        context: context,
+    })
+}
+
+impl<'input, I> StreamOnce for Lexer<'input, I>
+    where I: RangeStream<Item = char, Range = &'input str> + 'input,
+          I::Range: fmt::Debug,
+{
+    type Item = Token<&'input str>;
+    type Range = Token<&'input str>;
+    type Position = Span<Location>;
+
+    fn uncons(&mut self) -> Result<Token<&'input str>, Error<&'input str>> {
+        match self.next_token.take() {
+            Some(token) => {
+                self.next_token = self.uncons_next().ok();
+                Ok(token.value)
+            }
+            None => {
+                self.next_token = Some(self.uncons_next()?);
+                self.uncons()
+            }
+        }
+    }
+
+    fn position(&self) -> Self::Position {
+        self.next_token
+            .as_ref()
+            .or_else(|| self.unprocessed_tokens.last())
+            .map(|token| token.span)
+            .unwrap_or_else(|| self.end_span.unwrap())
+    }
+}
diff --git a/parser/src/lib.rs b/parser/src/lib.rs
index 7aee97d5..c0768d98 100644
--- a/parser/src/lib.rs
+++ b/parser/src/lib.rs
@@ -1,186 +1,917 @@
 //! The parser is a bit more complex than it needs to be as it needs to be fully specialized to
 //! avoid a recompilation every time a later part of the compiler is changed. Due to this the
 //! string interner and therefore also garbage collector needs to compiled before the parser.
-
 #[macro_use]
 extern crate log;
-#[macro_use]
-extern crate quick_error;
 extern crate gluon_base as base;
-extern crate lalrpop_util;
+extern crate combine;
+extern crate combine_language;
+
+// pub mod grammar;
+pub mod lexer;
 
-use base::ast::{Expr, IdentEnv, SpannedExpr};
+use std::cell::RefCell;
+use std::fmt;
+use std::iter::FromIterator;
+use std::marker::PhantomData;
+use std::rc::Rc;
+
+use base::ast::*;
+use base::kind::Kind;
 use base::error::Errors;
 use base::pos::{self, BytePos, Span, Spanned};
-use base::symbol::Symbol;
-use base::types::ArcType;
-
-use infix::{OpTable, Reparser, Error as InfixError};
-use layout::{Layout, Error as LayoutError};
-use token::{Token, Tokenizer};
-
-mod grammar;
-mod infix;
-mod layout;
-mod token;
-
-type LalrpopError<'input> = lalrpop_util::ParseError<BytePos, Token<'input>, Error>;
-
-/// Shrink hidden spans to fit the visible expressions and flatten singleton blocks.
-fn shrink_hidden_spans<Id>(mut expr: SpannedExpr<Id>) -> SpannedExpr<Id> {
-    match expr.value {
-        Expr::IfElse(_, _, ref last) |
-        Expr::LetBindings(_, ref last) |
-        Expr::TypeBindings(_, ref last) => expr.span.end = last.span.end,
-        Expr::Lambda(ref lambda) => expr.span.end = lambda.body.span.end,
-        Expr::Block(ref mut exprs) => {
-            match exprs.len() {
-                0 => (),
-                1 => return exprs.pop().unwrap(),
-                _ => expr.span.end = exprs.last().unwrap().span.end,
-            }
+use base::symbol::{Name, Symbol};
+use base::types::{Alias, AppVec, ArcType, Generic, Field, Type};
+
+use combine::primitives::{Consumed, Stream, StreamOnce, Error as CombineError, Info,
+                          BufferedStream};
+use combine::primitives::FastResult::*;
+use combine::combinator::EnvParser;
+use combine::{between, choice, env_parser, many, many1, optional, parser, satisfy, sep_by1,
+              sep_end_by, token, try, value, ParseError as CombineParseError, ParseResult, Parser};
+use combine_language::{Assoc, Fixity, expression_parser};
+
+use lexer::{Lexer, Delimiter, Token, IdentType};
+
+#[derive(Debug, PartialEq)]
+pub struct ParseError {
+    pub errors: Vec<CombineError<Token<String>, Token<String>>>,
+}
+
+impl fmt::Display for ParseError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        CombineError::fmt_errors(&self.errors, f)
+    }
+}
+
+pub type Error = Errors<Spanned<ParseError, BytePos>>;
+
+// Dummy type for ParseError which has the correct associated types
+#[derive(Clone)]
+pub struct StreamType(());
+
+impl StreamOnce for StreamType {
+    type Item = Token<String>;
+    type Range = Token<String>;
+    type Position = BytePos;
+
+    fn uncons(&mut self) -> Result<Token<String>, ::lexer::Error<String>> {
+        unimplemented!()
+    }
+
+    fn position(&self) -> Self::Position {
+        unimplemented!()
+    }
+}
+
+
+/// Parser passes the environment to each parser function
+type LanguageParser<'parser, I: 'parser, F: 'parser, T> = EnvParser<&'parser ParserEnv<I, F>, I, T>;
+
+/// `ParserEnv` is passed around to all individual parsers so that identifiers can always be
+/// constructed through calling `make_ident`.
+struct ParserEnv<I, F>
+    where F: IdentEnv,
+          I: Stream,
+{
+    empty_id: F::Ident,
+    hole_typ: ArcType<F::Ident>,
+    make_ident: Rc<RefCell<F>>,
+    errors: RefCell<Error>,
+    env: PhantomData<I>,
+}
+
+// Wrapper type to reduce typechecking times
+#[derive(Clone)]
+pub struct Wrapper<'input: 'lexer, 'lexer> {
+    stream: BufferedStream<'lexer, Lexer<'input, &'input str>>,
+}
+
+impl<'input, 'lexer> StreamOnce for Wrapper<'input, 'lexer> {
+    type Item = Token<&'input str>;
+    type Range = Token<&'input str>;
+    type Position = Span<BytePos>;
+
+    fn uncons(&mut self) -> Result<Token<&'input str>, lexer::Error<&'input str>> {
+        self.stream.uncons()
+    }
+
+    fn position(&self) -> Self::Position {
+        let span = self.stream.position();
+
+        Span {
+            start: span.start.absolute,
+            end: span.end.absolute,
+            expansion_id: pos::NO_EXPANSION,
         }
-        Expr::Match(_, ref alts) => {
-            if let Some(last_alt) = alts.last() {
-                let end = last_alt.expr.span.end;
-                expr.span.end = end;
+    }
+}
+
+enum Bindings<Id> {
+    LetBindings(Vec<ValueBinding<Id>>),
+    TypeBindings(Vec<TypeBinding<Id>>),
+}
+
+macro_rules! match_parser {
+    ($function: ident, $variant: ident -> $typ: ty) => {
+        fn $function<'a>(&'a self) -> LanguageParser<'a, I, F, $typ> {
+            fn inner<'input, I, Id, F>(_: &ParserEnv<I, F>, input: I) -> ParseResult<$typ, I>
+                where I: Stream<Item = Token<&'input str>>,
+                      F: IdentEnv<Ident = Id>,
+                      Id: Clone + PartialEq + fmt::Debug,
+                      I::Range: fmt::Debug
+            {
+                satisfy(|t: Token<&'input str>| {
+                    match t {
+                        Token::$variant(_) => true,
+                        _ => false,
+                    }
+                })
+                    .map(|t| {
+                        match t {
+                            Token::$variant(s) => s,
+                            _ => unreachable!(),
+                        }
+                    })
+                    .parse_stream(input)
             }
+
+            self.parser(inner)
         }
-        Expr::App(_, _) |
-        Expr::Ident(_) |
-        Expr::Literal(_) |
-        Expr::Projection(_, _, _) |
-        Expr::Infix(_, _, _) |
-        Expr::Array(_) |
-        Expr::Record { .. } |
-        Expr::Tuple(_) => (),
-    }
-    expr
+    }
 }
 
-fn transform_errors<'a, Iter>(errors: Iter) -> Errors<Spanned<Error, BytePos>>
-    where Iter: IntoIterator<Item = LalrpopError<'a>>,
-{
-    errors.into_iter()
-        .map(Error::from_lalrpop)
-        .collect()
+fn as_trait<P: Parser>(p: &mut P) -> &mut Parser<Input = P::Input, Output = P::Output> {
+    p
 }
 
-quick_error! {
-    #[derive(Debug, PartialEq)]
-    pub enum Error {
-        Layout(err: LayoutError) {
-            description(err.description())
-            display("{}", err)
-            from()
+impl<'input, I, Id, F> ParserEnv<I, F>
+    where I: Stream<Item = Token<&'input str>, Range = Token<&'input str>, Position = Span<BytePos>>,
+          F: IdentEnv<Ident = Id>,
+          Id: Clone + PartialEq + fmt::Debug,
+          I::Range: fmt::Debug,
+{
+    fn intern(&self, s: &str) -> Id {
+        self.make_ident.borrow_mut().from_str(s)
+    }
+
+    fn parser<'a, T>(&'a self,
+                     parser: fn(&ParserEnv<I, F>, I) -> ParseResult<T, I>)
+                     -> LanguageParser<'a, I, F, T> {
+        env_parser(self, parser)
+    }
+
+    fn precedence(&self, s: &str) -> i32 {
+        match s {
+            "*" | "/" | "%" => 7,
+            "+" | "-" => 6,
+            ":" | "++" => 5,
+            "&&" => 3,
+            "||" => 2,
+            "$" => 0,
+            "==" | "/=" | "<" | ">" | "<=" | ">=" => 4,
+            // Primitive operators starts with # and has the op at the end
+            _ if s.starts_with("#") => {
+                let op = s[1..].trim_left_matches(|c: char| c.is_alphanumeric());
+                self.precedence(op)
+            }
+            // Hack for some library operators
+            "<<" | ">>" => 9,
+            "<|" | "|>" => 0,
+            // User-defined operators
+            _ => 9,
         }
-        InvalidToken {
-            description("invalid token")
-            display("Invalid token")
+    }
+
+    fn fixity(&self, i: &str) -> Fixity {
+        match i {
+            "*" | "/" | "%" | "+" | "-" | "==" | "/=" | "<" | ">" | "<=" | ">=" => Fixity::Left,
+            ":" | "++" | "&&" | "||" | "$" => Fixity::Right,
+            // Hack for some library operators
+            ">>" | "|>" => Fixity::Left,
+            "<<" | "<|" => Fixity::Right,
+            // User-defined operators
+            _ => Fixity::Left,
         }
-        UnexpectedToken(token: String) {
-            description("unexpected token")
-            display("Unexpected token: {}", token)
+    }
+
+    fn ident<'a>(&'a self) -> LanguageParser<'a, I, F, Id> {
+        self.parser(ParserEnv::<I, F>::parse_ident)
+    }
+
+    fn parse_ident(&self, input: I) -> ParseResult<Id, I> {
+        self.parser(ParserEnv::<I, F>::parse_ident2)
+            .map(|x| x.0)
+            .parse_stream(input)
+    }
+
+    /// Identifier parser which returns the identifier as well as the type of the identifier
+    fn parse_ident2(&self, input: I) -> ParseResult<(Id, IdentType), I> {
+        satisfy(|t: Token<&'input str>| {
+                match t {
+                    Token::Ident(..) => true,
+                    _ => false,
+                }
+            })
+            .map(|t| {
+                match t {
+                    Token::Ident(id, typ) => (self.intern(id), typ),
+                    _ => unreachable!(),
+                }
+            })
+            .parse_stream(input)
+    }
+
+    fn ident_type<'a>(&'a self) -> LanguageParser<'a, I, F, ArcType<Id>> {
+        self.parser(ParserEnv::<I, F>::parse_ident_type)
+    }
+
+    fn parse_ident_type(&self, input: I) -> ParseResult<ArcType<Id>, I> {
+        try(self.parser(ParserEnv::<I, F>::parse_ident2))
+            .map(|(s, typ)| {
+                debug!("Id: {:?}", s);
+                if typ == IdentType::Variable {
+                    Type::generic(Generic {
+                        kind: Kind::variable(0),
+                        id: s,
+                    })
+                } else {
+                    let ident_env = self.make_ident.borrow();
+                    match ident_env.string(&s).parse() {
+                        Ok(prim) => Type::builtin(prim),
+                        Err(()) => Type::ident(s),
+                    }
+                }
+            })
+            .parse_stream(input)
+    }
+
+    match_parser! { string_literal, String -> String }
+
+    match_parser! { char_literal, Char -> char }
+
+    match_parser! { float, Float -> f64 }
+
+    match_parser! { int, Int -> i64 }
+
+    match_parser! { byte, Byte -> u8 }
+
+    match_parser! { doc_comment, DocComment -> String }
+
+    fn typ<'a>(&'a self) -> LanguageParser<'a, I, F, ArcType<Id>> {
+        self.parser(ParserEnv::<I, F>::parse_type)
+    }
+
+    fn parse_adt(&self, return_type: &ArcType<Id>, input: I) -> ParseResult<ArcType<Id>, I> {
+        let variant =
+            (token(Token::Pipe), self.ident(), many(self.parser(ParserEnv::<I, F>::type_arg)))
+                .map(|(_, id, args): (_, _, Vec<_>)| {
+                    Field {
+                        name: id,
+                        typ: Type::function(args, return_type.clone()),
+                    }
+                });
+
+        many1(variant)
+            .map(Type::variant)
+            .parse_stream(input)
+    }
+
+    fn parse_type(&self, input: I) -> ParseResult<ArcType<Id>, I> {
+        (many1(self.parser(ParserEnv::<I, F>::type_arg)),
+         optional(token(Token::RightArrow).with(self.typ())))
+            .map(|(mut arg, ret): (AppVec<_>, _)| {
+                let arg = if arg.len() == 1 {
+                    arg.pop().unwrap()
+                } else {
+                    let x = arg.remove(0);
+                    Type::app(x, arg)
+                };
+                debug!("Parse: {:?} -> {:?}", arg, ret);
+                match ret {
+                    Some(ret) => Type::function(vec![arg], ret),
+                    None => arg,
+                }
+            })
+            .parse_stream(input)
+    }
+
+    fn record_type(&self, input: I) -> ParseResult<ArcType<Id>, I> {
+        let field = self.parser(ParserEnv::<I, F>::parse_ident2)
+            .then(|(id, typ)| {
+                parser(move |input| {
+                    if typ == IdentType::Constructor {
+                        value((id.clone(), None)).parse_stream(input)
+                    } else {
+                        token(Token::Colon)
+                            .with(self.typ())
+                            .map(|typ| (id.clone(), Some(typ)))
+                            .parse_stream(input)
+                    }
+                })
+            });
+        between(token(Token::Open(Delimiter::Brace)),
+                token(Token::Close(Delimiter::Brace)),
+                sep_end_by(field, token(Token::Comma)))
+            .map(|fields: Vec<(Id, _)>| {
+                let mut associated = Vec::new();
+                let mut types = Vec::new();
+                let mut ids = self.make_ident.borrow_mut();
+                for (id, field) in fields {
+                    let untyped_id = id.clone();
+                    match field {
+                        Some(typ) => {
+                            types.push(Field {
+                                name: untyped_id,
+                                typ: typ,
+                            })
+                        }
+                        None => {
+                            let typ = Type::ident(untyped_id.clone());
+                            let short_name = String::from(Name::new(ids.string(&id))
+                                .name()
+                                .as_str());
+                            associated.push(Field {
+                                name: ids.from_str(&short_name),
+                                typ: Alias::new(untyped_id, vec![], typ),
+                            });
+                        }
+                    }
+                }
+                Type::record(associated, types)
+            })
+            .parse_stream(input)
+    }
+
+    fn type_arg(&self, input: I) -> ParseResult<ArcType<Id>, I> {
+        choice::<[&mut Parser<Input = I, Output = ArcType<Id>>; 3],
+                 _>([&mut self.parser(ParserEnv::<I, F>::record_type),
+                     &mut between(token(Token::Open(Delimiter::Paren)),
+                                  token(Token::Close(Delimiter::Paren)),
+                                  optional(self.typ()))
+                         .map(|typ| {
+                             match typ {
+                                 Some(typ) => typ,
+                                 None => Type::unit(),
+                             }
+                         }),
+                     &mut self.ident_type()])
+            .parse_stream(input)
+    }
+
+    fn type_decl(&self, input: I) -> ParseResult<Bindings<Id>, I> {
+        debug!("type_decl");
+        let type_binding = |t| {
+            (try(optional(self.doc_comment()).skip(token(t))),
+             self.parser(ParserEnv::<I, F>::type_binding))
+                .map(|(comment, mut bind)| {
+                    bind.comment = comment;
+                    bind
+                })
+        };
+        (as_trait(&mut type_binding(Token::Type)),
+         many(as_trait(&mut type_binding(Token::And))),
+         token(Token::In).expected("`in` or an expression in the same column as the `let`"))
+            .map(|(first, mut bindings, _): (_, Vec<_>, _)| {
+                bindings.insert(0, first);
+                Bindings::TypeBindings(bindings)
+            })
+            .parse_stream(input)
+    }
+
+    fn type_binding(&self, input: I) -> ParseResult<TypeBinding<Id>, I> {
+        (self.ident(), many(self.ident()))
+            .then(|(name, args): (Id, AppVec<Id>)| {
+                let return_type = if args.is_empty() {
+                    Type::ident(name.clone())
+                } else {
+                    let arg_types = args.iter()
+                        .map(|id| {
+                            Type::generic(Generic {
+                                kind: Kind::variable(0),
+                                id: id.clone(),
+                            })
+                        })
+                        .collect();
+                    Type::app(Type::ident(name.clone()), arg_types)
+                };
+                token(Token::Equal)
+                    .with(self.typ()
+                        .or(parser(move |input| self.parse_adt(&return_type, input))))
+                    .map(move |rhs_type| {
+                        TypeBinding {
+                            comment: None,
+                            name: name.clone(),
+                            alias: Alias::new(name.clone(),
+                                              args.iter()
+                                                  .map(|id| {
+                                                      Generic {
+                                                          kind: Kind::variable(0),
+                                                          id: id.clone(),
+                                                      }
+                                                  })
+                                                  .collect(),
+                                              rhs_type),
+                        }
+                    })
+            })
+            .parse_stream(input)
+    }
+
+    fn expr<'a>(&'a self) -> LanguageParser<'a, I, F, SpannedExpr<Id>> {
+        self.parser(ParserEnv::<I, F>::top_expr)
+    }
+
+    fn parse_expr(&self, input: I) -> ParseResult<SpannedExpr<Id>, I> {
+        let arg_expr1 = self.parser(ParserEnv::<I, F>::parse_arg);
+        let arg_expr2 = self.parser(ParserEnv::<I, F>::parse_arg);
+        (arg_expr1, many(arg_expr2))
+            .map(|(f, args): (SpannedExpr<Id>, Vec<SpannedExpr<_>>)| {
+                if let Some(end) = args.last().map(|last| last.span.end) {
+                    pos::spanned2(f.span.start, end, Expr::App(Box::new(f), args))
+                } else {
+                    f
+                }
+            })
+            .parse_stream(input)
+    }
+
+    /// Parses an expression which could be an argument to a function
+    fn parse_arg(&self, input: I) -> ParseResult<SpannedExpr<Id>, I> {
+        debug!("Expr start: {:?}", input.clone().uncons());
+        let start = input.position().start;
+
+        // To prevent stack overflows we push all binding groups (which are commonly deeply nested)
+        // to a stack and construct the expressions afterwards
+        let mut let_bindings = Vec::new();
+        let mut resulting_expr;
+        let mut input = input;
+        let mut declaration_parser = self.parser(ParserEnv::<I, F>::type_decl)
+            .or(self.parser(ParserEnv::<I, F>::let_in))
+            .and(parser(move |input: I| {
+                let span = Span {
+                    start: start,
+                    end: input.position().end,
+                    expansion_id: pos::NO_EXPANSION,
+                };
+                Ok((span, Consumed::Empty(input)))
+            }))
+            .map(|(decl, span)| pos::spanned(span, decl));
+        loop {
+            match declaration_parser.parse_lazy(input.clone()) {
+                ConsumedOk((bindings, new_input)) |
+                EmptyOk((bindings, new_input)) => {
+                    let_bindings.push(bindings);
+                    input = new_input;
+                }
+                ConsumedErr(err) => return Err(Consumed::Consumed(err)),
+                EmptyErr(err) => {
+                    // If a let or type binding has been parsed then any kind of expression can
+                    // follow
+                    let mut expr_parser = if let_bindings.is_empty() {
+                        self.parser(ParserEnv::<I, F>::rest_expr)
+                    } else {
+                        self.expr()
+                    };
+                    let (expr, new_input) = expr_parser.parse_stream(input)
+                        .map_err(|err2| err2.map(|err2| err.merge(err2)))?;
+                    resulting_expr = expr;
+                    input = new_input.into_inner();
+                    break;
+                }
+            }
         }
-        UnexpectedEof {
-            description("unexpected end of file")
-            display("Undexpected end of file")
+        for binding in let_bindings.into_iter().rev() {
+            resulting_expr =
+                pos::spanned(binding.span,
+                             match binding.value {
+                                 Bindings::LetBindings(bindings) => {
+                                     Expr::LetBindings(bindings, Box::new(resulting_expr))
+                                 }
+                                 Bindings::TypeBindings(bindings) => {
+                                     Expr::TypeBindings(bindings, Box::new(resulting_expr))
+                                 }
+                             });
         }
-        ExtraToken(token: String) {
-            description("extra token")
-            display("Extra token: {}", token)
+        Ok((resulting_expr, Consumed::Consumed(input)))
+    }
+
+    fn rest_expr(&self, input: I) -> ParseResult<SpannedExpr<Id>, I> {
+        let span = input.position();
+        let loc = |expr| pos::spanned(span, expr);
+
+        choice::<[&mut Parser<Input = I, Output = SpannedExpr<Id>>; 12],
+                 _>([&mut parser(|input| self.if_else(input)),
+                     &mut self.parser(ParserEnv::<I, F>::case_of),
+                     &mut self.parser(ParserEnv::<I, F>::lambda),
+                     &mut self.int()
+                         .map(|i| loc(Expr::Literal(Literal::Int(i)))),
+                     &mut self.byte()
+                         .map(|i| loc(Expr::Literal(Literal::Byte(i)))),
+                     &mut self.float()
+                         .map(|f| loc(Expr::Literal(Literal::Float(f)))),
+                     &mut self.ident()
+                         .map(|id| loc(Expr::Ident(TypedIdent::new(id.clone())))),
+                     &mut self.parser(ParserEnv::<I, F>::record).map(&loc),
+                     &mut between(token(Token::Open(Delimiter::Paren)),
+                                  token(Token::Close(Delimiter::Paren)),
+                                  optional(self.expr()).map(|expr| {
+                                      match expr {
+                                          Some(expr) => expr,
+                                          None => loc(Expr::Tuple(vec![])),
+                                      }
+                                  })),
+                     &mut self.string_literal()
+                         .map(|s| loc(Expr::Literal(Literal::String(s)))),
+                     &mut self.char_literal()
+                         .map(|s| loc(Expr::Literal(Literal::Char(s)))),
+                     &mut between(token(Token::Open(Delimiter::Bracket)),
+                                  token(Token::Close(Delimiter::Bracket)),
+                                  sep_end_by(self.expr(), token(Token::Comma)))
+                         .map(|exprs| {
+                             loc(Expr::Array(Array {
+                                 typ: self.hole_typ.clone(),
+                                 exprs: exprs,
+                             }))
+                         })])
+            .and(self.parser(Self::fields))
+            .map(|(expr, fields): (_, Vec<_>)| {
+                debug!("Parsed expr {:?}", expr);
+                fields.into_iter().fold(expr, |expr, (id, end): (Id, _)| {
+                    pos::spanned2(span.start,
+                                  end,
+                                  Expr::Projection(Box::new(expr), id, Type::hole()))
+                })
+            })
+            .parse_stream(input)
+
+    }
+
+    // The BytePos is the end of the field
+    fn fields(&self, input: I) -> ParseResult<Vec<(Id, BytePos)>, I> {
+        let mut fields = Vec::new();
+        let mut input = Consumed::Empty(input);
+        loop {
+            input = match input.clone()
+                .combine(|input| token(Token::Dot).parse_lazy(input).into()) {
+                Ok((_, input)) => input,
+                Err(_) => return Ok((fields, input)),
+            };
+            let end = input.clone().into_inner().position().end;
+            input = match input.clone()
+                .combine(|input| self.ident().parse_lazy(input).into()) {
+                Ok((field, input)) => {
+                    fields.push((field, end));
+                    input
+                }
+                Err(err) => {
+                    // If not field where found after the '.' add an empty field so that running
+                    // completion can be done for the attempt to access the field
+                    self.errors
+                        .borrow_mut()
+                        .error(static_error(err.into_inner()));
+                    fields.push((self.empty_id.clone(), end));
+                    return Ok((fields, input));
+                }
+            };
         }
-        Infix(err: InfixError) {
-            description(err.description())
-            display("{}", err)
-            from()
+    }
+
+    fn op<'a>(&'a self) -> LanguageParser<'a, I, F, &'input str> {
+        fn inner<'input, I, Id, F>(_: &ParserEnv<I, F>, input: I) -> ParseResult<&'input str, I>
+            where I: Stream<Item = Token<&'input str>,
+                            Range = Token<&'input str>,
+                            Position = Span<BytePos>>,
+                  F: IdentEnv<Ident = Id>,
+                  Id: Clone + PartialEq + fmt::Debug,
+                  I::Range: fmt::Debug,
+        {
+            satisfy(|t: Token<&'input str>| {
+                    match t {
+                        Token::Operator(_) => true,
+                        _ => false,
+                    }
+                })
+                .map(|t| {
+                    match t {
+                        Token::Operator(s) => s,
+                        _ => unreachable!(),
+                    }
+                })
+                .parse_stream(input)
         }
+        self.parser(inner)
     }
-}
 
-impl Error {
-    fn from_lalrpop(err: LalrpopError) -> Spanned<Error, BytePos> {
-        use lalrpop_util::ParseError::*;
+    /// Parses any sort of expression
+    fn top_expr(&self, input: I) -> ParseResult<SpannedExpr<Id>, I> {
+        let term = self.parser(ParserEnv::<I, F>::parse_expr);
+        let op = self.op()
+            .map(|op| {
+                let assoc = Assoc {
+                    precedence: self.precedence(&op),
+                    fixity: self.fixity(&op),
+                };
+                (op, assoc)
+            });
+        between(token(Token::OpenBlock),
+                token(Token::CloseBlock),
+                self.expr())
+            .or(sep_by1(expression_parser(term, op, |l, op, r| {
+                pos::spanned2(l.span.start,
+                              r.span.end,
+                              Expr::Infix(Box::new(l),
+                                          TypedIdent::new(self.intern(&op)),
+                                          Box::new(r)))
+            }),
+                        token(Token::Semi))
+                .map(|mut exprs: Vec<SpannedExpr<Id>>| {
+                    if exprs.len() == 1 {
+                        exprs.pop().unwrap()
+                    } else {
+                        pos::spanned(exprs.first().expect("Expr in block").span,
+                                     Expr::Block(exprs))
+                    }
+                }))
+            .parse_stream(input)
+    }
 
-        match err {
-            InvalidToken { location } => pos::spanned2(location, location, Error::InvalidToken),
-            UnrecognizedToken { token: Some((lpos, token, rpos)), .. } => {
-                pos::spanned2(lpos, rpos, Error::UnexpectedToken(token.to_string()))
-            }
-            UnrecognizedToken { token: None, .. } => {
-                pos::spanned2(0.into(), 0.into(), Error::UnexpectedEof)
-            }
-            ExtraToken { token: (lpos, token, rpos) } => {
-                pos::spanned2(lpos, rpos, Error::ExtraToken(token.to_string()))
-            }
-            User { error } => pos::spanned2(0.into(), 0.into(), error),
-        }
+    fn lambda(&self, input: I) -> ParseResult<SpannedExpr<Id>, I> {
+        let start = input.position().start;
+        (token(Token::Lambda), many(self.ident()), token(Token::RightArrow), self.expr())
+            .map(|(_, args, _, expr): (_, Vec<Id>, _, SpannedExpr<_>)| {
+                pos::spanned2(start,
+                              expr.span.end,
+                              Expr::Lambda(Lambda {
+                                  // TODO: Generate name of lambda here?
+                                  id: TypedIdent::new(self.empty_id.clone()),
+                                  args: args.iter()
+                                      .map(|arg| TypedIdent::new(arg.clone()))
+                                      .collect(),
+                                  body: Box::new(expr),
+                              }))
+            })
+            .parse_stream(input)
     }
-}
 
-pub enum FieldPattern<Id> {
-    Type(Id, Option<Id>),
-    Value(Id, Option<Id>),
-}
+    fn case_of(&self, input: I) -> ParseResult<SpannedExpr<Id>, I> {
+        let alt = (token(Token::Pipe), self.pattern(), token(Token::RightArrow), self.expr())
+            .map(|(_, pattern, _, expr)| {
+                Alternative {
+                    pattern: pattern,
+                    expr: expr,
+                }
+            });
+        let start = input.position().start;
+        (token(Token::Match), self.expr(), token(Token::With), many1::<Vec<_>, _>(alt))
+            .map(|(_, expr, _, alts)| {
+                pos::spanned2(start,
+                              alts.last().expect("No alternatives").expr.span.end,
+                              Expr::Match(Box::new(expr), alts))
+            })
+            .parse_stream(input)
+    }
+
+    fn pattern<'a>(&'a self) -> LanguageParser<'a, I, F, SpannedPattern<Id>> {
+        self.parser(ParserEnv::<I, F>::parse_pattern)
+    }
 
-pub enum FieldExpr<Id> {
-    Type(Id, Option<ArcType<Id>>),
-    Value(Id, Option<SpannedExpr<Id>>),
+    fn parse_pattern(&self, input: I) -> ParseResult<SpannedPattern<Id>, I> {
+        self.record_parser(self.ident(), self.ident(), |record| {
+            let span = input.position();
+
+            self.parser(ParserEnv::<I, F>::parse_ident2)
+                .then(|(id, typ)| {
+                    parser(move |input| {
+                        if typ == IdentType::Constructor {
+                            many(self.ident())
+                                .parse_stream(input)
+                                .map(|(args, input): (Vec<Id>, _)| {
+                                    (Pattern::Constructor(TypedIdent::new(id.clone()),
+                                                          args.iter()
+                                                              .map(|arg| {
+                                                                  TypedIdent::new(arg.clone())
+                                                              })
+                                                              .collect()),
+                                     input)
+                                })
+                        } else {
+                            Ok((Pattern::Ident(TypedIdent::new(id.clone())),
+                                Consumed::Empty(input)))
+                        }
+                    })
+                })
+                .or(record.map(|fields: Vec<_>| {
+                    let mut types = Vec::new();
+                    let mut patterns = Vec::new();
+                    for (id, field) in fields {
+                        match field {
+                            Ok(name) => types.push((id, name)),
+                            Err(pattern) => patterns.push((id, pattern)),
+                        }
+                    }
+                    Pattern::Record {
+                        typ: self.hole_typ.clone(),
+                        types: types,
+                        fields: patterns,
+                    }
+                }))
+                .map(|p| pos::spanned(span, p))
+                .or(between(token(Token::Open(Delimiter::Paren)),
+                            token(Token::Close(Delimiter::Paren)),
+                            self.pattern()))
+                .parse_stream(input)
+        })
+    }
+
+    fn if_else(&self, input: I) -> ParseResult<SpannedExpr<Id>, I> {
+        let start = input.position().start;
+        (token(Token::If),
+         self.expr(),
+         token(Token::Then),
+         self.expr(),
+         token(Token::Else),
+         self.expr())
+            .map(|(_, b, _, t, _, f)| {
+                pos::spanned2(start,
+                              f.span.end,
+                              Expr::IfElse(Box::new(b), Box::new(t), Box::new(f)))
+            })
+            .parse_stream(input)
+    }
+
+    fn let_in(&self, input: I) -> ParseResult<Bindings<Id>, I> {
+        let binding = |t| {
+            (try(optional(self.doc_comment()).skip(token(t))),
+             self.parser(ParserEnv::<I, F>::binding))
+                .map(|(comment, mut bind)| {
+                    bind.comment = comment;
+                    bind
+                })
+        };
+        (as_trait(&mut binding(Token::Let)),
+         many(as_trait(&mut binding(Token::And))),
+         token(Token::In).expected("`in` or an expression in the same column as the `let`"))
+            .map(|(b, bindings, _)| {
+                let mut bindings: Vec<_> = bindings;
+                bindings.insert(0, b);
+                Bindings::LetBindings(bindings)
+            })
+            .parse_stream(input)
+    }
+
+    fn binding(&self, input: I) -> ParseResult<ValueBinding<Id>, I> {
+        let (name, input) = self.pattern().parse_stream(input)?;
+        let (args, input) = match name.value {
+            Pattern::Ident(_) => input.combine(|input| many(self.ident()).parse_stream(input))?,
+            _ => (Vec::new(), input),
+        };
+        let type_sig = token(Token::Colon).with(self.typ());
+        let ((typ, _, e), input) = input.combine(|input| {
+                (optional(type_sig), token(Token::Equal), self.expr()).parse_stream(input)
+            })?;
+
+        Ok((ValueBinding {
+            comment: None,
+            name: name,
+            typ: typ.unwrap_or_else(|| self.hole_typ.clone()),
+            args: args.iter()
+                .map(|arg| TypedIdent::new(arg.clone()))
+                .collect(),
+            expr: e,
+        },
+            input))
+    }
+
+    fn record(&self, input: I) -> ParseResult<Expr<Id>, I> {
+        self.record_parser(self.typ(), self.expr(), |record| {
+            record.map(|fields: Vec<_>| {
+                    let mut types = Vec::new();
+                    let mut exprs = Vec::new();
+                    for (id, field) in fields {
+                        match field {
+                            Ok(typ) => types.push((id, typ)),
+                            Err(expr) => exprs.push((id, expr)),
+                        }
+                    }
+                    Expr::Record {
+                        typ: self.hole_typ.clone(),
+                        types: types,
+                        exprs: exprs,
+                    }
+                })
+                .parse_stream(input)
+        })
+    }
+
+    fn record_parser<'a, P1, P2, O, G, R>(&'a self, ref p1: P1, ref p2: P2, f: G) -> R
+        where P1: Parser<Input = I> + Clone,
+              P2: Parser<Input = I> + Clone,
+              O: FromIterator<(Id, Result<Option<P1::Output>, Option<P2::Output>>)>,
+              G: FnOnce(&mut Parser<Input = I, Output = O>) -> R,
+    {
+        let mut field = self.parser(ParserEnv::<I, F>::parse_ident2)
+            .then(move |(id, typ)| {
+                parser(move |input| {
+                    let result = if typ == IdentType::Constructor {
+                        optional(token(Token::Equal).with(p1.clone()))
+                            .map(Ok)
+                            .parse_stream(input)
+
+                    } else {
+                        optional(token(Token::Equal).with(p2.clone()))
+                            .map(Err)
+                            .parse_stream(input)
+                    };
+                    result.map(|(x, input)| ((id.clone(), x), input))
+                })
+            });
+        let mut parser = between(token(Token::Open(Delimiter::Brace)),
+                                 token(Token::Close(Delimiter::Brace)),
+                                 sep_end_by(&mut field, token(Token::Comma)));
+        f(&mut parser)
+    }
 }
 
-// Hack around LALRPOP's limited type syntax
-type MutIdentEnv<'env, Id> = &'env mut IdentEnv<Ident = Id>;
-type ErrorEnv<'err, 'input> = &'err mut Errors<LalrpopError<'input>>;
+// Force a specialized version of `parse_expr` to be created in the parser crate so the the
+// compiletimes of the parser does not bleed into the other crates
+pub fn parse_expr(symbols: &mut IdentEnv<Ident = Symbol>,
+                  input: &str)
+                  -> Result<SpannedExpr<Symbol>, (Option<SpannedExpr<Symbol>>, Error)> {
+    parse_expr_(symbols, input)
+}
 
-pub type ParseErrors = Errors<Spanned<Error, BytePos>>;
+#[cfg(feature = "test")]
+pub fn parse_string<'env, 'input>
+    (make_ident: &'env mut IdentEnv<Ident = String>,
+     input: &'input str)
+     -> Result<SpannedExpr<String>, (Option<SpannedExpr<String>>, Error)> {
+    parse_expr_(make_ident, input)
+}
 
-pub fn parse_partial_expr<Id>(symbols: &mut IdentEnv<Ident = Id>,
-                              input: &str)
-                              -> Result<SpannedExpr<Id>, (Option<SpannedExpr<Id>>, ParseErrors)>
-    where Id: Clone,
+/// Parses a gluon expression
+pub fn parse_expr_<'env, 'input, Id>(make_ident: &'env mut IdentEnv<Ident = Id>,
+                                     input: &'input str)
+                                     -> Result<SpannedExpr<Id>, (Option<SpannedExpr<Id>>, Error)>
+    where Id: Clone + PartialEq + fmt::Debug,
 {
-    let tokenizer = Tokenizer::new(input).map(|token| token.unwrap()); // FIXME
-
-    let layout = Layout::new(tokenizer).map(|token| {
-        let token = token?;
-        debug!("Lex {:?}", token.value);
-        let Span { start, end, .. } = token.span;
-        Ok((start.absolute, token.value, end.absolute))
-    });
-
-    let mut parse_errors = Errors::new();
-
-    match grammar::parse_TopExpr(input, symbols, &mut parse_errors, layout) {
-        Ok(mut expr) => {
-            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)));
-            }
+    let make_ident = Rc::new(RefCell::new(make_ident));
+    let lexer = Lexer::new(input);
+    let env = ParserEnv {
+        empty_id: make_ident.borrow_mut().from_str(""),
+        hole_typ: Type::hole(),
+        make_ident: make_ident.clone(),
+        errors: RefCell::new(Errors::new()),
+        env: PhantomData,
+    };
+    let buffer = BufferedStream::new(lexer, 10);
+    let stream = Wrapper { stream: buffer.as_stream() };
+
+    let result = env.expr()
+        .parse(stream)
+        .map(|t| t.0);
 
-            if errors.has_errors() {
-                Err((Some(expr), errors))
+    let mut errors = env.errors.into_inner();
+    match result {
+        Ok(x) => {
+            if !errors.has_errors() {
+                Ok(x)
             } else {
-                Ok(expr)
+                Err((Some(x), errors))
             }
         }
         Err(err) => {
-            parse_errors.push(err);
-            Err((None, transform_errors(parse_errors)))
+            errors.errors.push(static_error(err));
+            Err((None, errors))
         }
     }
 }
 
-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)
+fn static_error<'input, I>(error: CombineParseError<I>) -> Spanned<ParseError, BytePos>
+    where I: Stream<Item = Token<&'input str>, Range = Token<&'input str>, Position = Span<BytePos>>,
+{
+    let errors = error.errors
+        .into_iter()
+        .map(static_error_)
+        .collect();
+    pos::spanned(error.position, ParseError { errors: errors })
 }
 
-#[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)> {
-    parse_partial_expr(symbols, input)
+// Converts an error into a static error by transforming any range arguments into strings
+fn static_error_<'input>(e: CombineError<Token<&'input str>, Token<&'input str>>)
+                         -> CombineError<Token<String>, Token<String>> {
+    let static_info = |i: Info<Token<&'input str>, Token<&'input str>>| {
+        match i {
+            Info::Token(t) => Info::Token(t.map(|id| String::from(*id))),
+            Info::Range(t) => Info::Token(t.map(|id| String::from(*id))),
+            Info::Borrowed(t) => Info::Borrowed(t),
+            Info::Owned(t) => Info::Owned(t),
+        }
+    };
+    match e {
+        CombineError::Unexpected(t) => CombineError::Unexpected(static_info(t)),
+        CombineError::Expected(t) => CombineError::Expected(static_info(t)),
+        CombineError::Message(t) => CombineError::Message(static_info(t)),
+        CombineError::Other(t) => CombineError::Other(t),
+    }
 }
diff --git a/parser/src/token.rs b/parser/src/token.rs
deleted file mode 100644
index aef6a0d3..00000000
--- a/parser/src/token.rs
+++ /dev/null
@@ -1,696 +0,0 @@
-use base::ast::is_operator_char;
-use base::pos::{self, BytePos, Column, Line, Location, Spanned};
-use std::error::Error as StdError;
-use std::fmt;
-use std::str::Chars;
-
-use self::ErrorCode::*;
-
-#[derive(Clone, PartialEq, Debug)]
-pub enum Token<'input> {
-    Identifier(&'input str),
-    Operator(&'input str),
-
-    StringLiteral(String),
-    CharLiteral(char),
-    IntLiteral(i64),
-    ByteLiteral(u8),
-    FloatLiteral(f64),
-    DocComment(String),
-
-    And,
-    Else,
-    If,
-    In,
-    Let,
-    Match,
-    Then,
-    Type,
-    With,
-
-    Colon,
-    Comma,
-    Dot,
-    Equals,
-    Lambda,
-    Pipe,
-    RArrow,
-
-    LBrace,
-    LBracket,
-    LParen,
-    RBrace,
-    RBracket,
-    RParen,
-
-    OpenBlock,
-    CloseBlock,
-    Semi,
-
-    EOF, // Required for the layout algorithm
-}
-
-impl<'input> fmt::Display for Token<'input> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        use self::Token::*;
-
-        let s = match *self {
-            Identifier(_) => "Identifier",
-            Operator(_) => "Operator",
-            StringLiteral(_) => "StringLiteral",
-            CharLiteral(_) => "CharLiteral",
-            IntLiteral(_) => "IntLiteral",
-            ByteLiteral(_) => "ByteLiteral",
-            FloatLiteral(_) => "FloatLiteral",
-            DocComment(_) => "DocComment",
-
-            And => "And",
-            Else => "Else",
-            If => "If",
-            In => "In",
-            Let => "Let",
-            Match => "Match",
-            Then => "Then",
-            Type => "Type",
-            With => "With",
-
-            LBrace => "LBrace",
-            LBracket => "LBracket",
-            LParen => "LParen",
-
-            RBrace => "RBrace",
-            RBracket => "RBracket",
-            RParen => "RParen",
-
-            Colon => "Colon",
-            Comma => "Comma",
-            Dot => "Dot",
-            Equals => "Equal",
-            Lambda => "Lambda",
-            Pipe => "Pipe",
-            RArrow => "RArrow",
-
-            OpenBlock => "OpenBlock",
-            CloseBlock => "CloseBlock",
-            Semi => "Semi",
-
-            EOF => "EOF",
-        };
-        s.fmt(f)
-    }
-}
-
-pub type SpannedToken<'input> = Spanned<Token<'input>, Location>;
-
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct Error {
-    pub location: Location,
-    pub code: ErrorCode,
-}
-
-impl fmt::Display for Error {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}", self.description()) // TODO: Improve
-    }
-}
-
-impl StdError for Error {
-    fn description(&self) -> &str {
-        self.code.description()
-    }
-}
-
-quick_error! {
-    #[derive(Clone, Debug, PartialEq, Eq)]
-    pub enum ErrorCode {
-        EmptyCharLiteral {
-            description("empty char literal")
-        }
-        UnexpectedChar(ch: char) {
-            description("unexpected character")
-        }
-        UnexpectedEof {
-            description("unexpected end of file")
-        }
-        UnexpectedEscapeCode(ch: char) {
-            description("unexpected escape code")
-        }
-        UnterminatedCharLiteral {
-            description("unterminated character literal")
-        }
-        UnterminatedStringLiteral {
-            description("unterminated string literal")
-        }
-    }
-}
-
-fn error<T>(location: Location, code: ErrorCode) -> Result<T, Error> {
-    Err(Error {
-        location: location,
-        code: code,
-    })
-}
-
-fn is_ident_start(ch: char) -> bool {
-    // TODO: Unicode?
-    match ch {
-        '_' | 'a'...'z' | 'A'...'Z' => true,
-        _ => false,
-    }
-}
-
-fn is_ident_continue(ch: char) -> bool {
-    // TODO: Unicode?
-    match ch {
-        '0'...'9' | '\'' => true,
-        ch => is_ident_start(ch),
-    }
-}
-
-fn is_digit(ch: char) -> bool {
-    ch.is_digit(10)
-}
-
-struct CharLocations<'input> {
-    location: Location,
-    chars: Chars<'input>,
-}
-
-impl<'input> CharLocations<'input> {
-    pub fn new(input: &'input str) -> CharLocations<'input> {
-        CharLocations {
-            location: Location {
-                line: Line::from(0),
-                column: Column::from(1),
-                absolute: BytePos::from(0),
-            },
-            chars: input.chars(),
-        }
-    }
-}
-
-impl<'input> Iterator for CharLocations<'input> {
-    type Item = (Location, char);
-
-    fn next(&mut self) -> Option<(Location, char)> {
-        self.chars.next().map(|ch| {
-            let location = self.location;
-            self.location = self.location.shift(ch);
-            // HACK: The layout algorithm expects `1` indexing for columns -
-            // this could be altered in the future though
-            if self.location.column == Column::from(0) {
-                self.location.column = Column::from(1);
-            }
-            (location, ch)
-        })
-    }
-}
-
-pub struct Tokenizer<'input> {
-    input: &'input str,
-    chars: CharLocations<'input>,
-    eof_location: Location,
-    lookahead: Option<(Location, char)>,
-}
-
-impl<'input> Tokenizer<'input> {
-    pub fn new(input: &'input str) -> Tokenizer<'input> {
-        let mut chars = CharLocations::new(input);
-        let eof_location = chars.location;
-
-        Tokenizer {
-            input: input,
-            eof_location: eof_location,
-            lookahead: chars.next(),
-            chars: chars,
-        }
-    }
-
-    fn bump(&mut self) -> Option<(Location, char)> {
-        match self.lookahead {
-            Some((location, ch)) => {
-                self.eof_location = self.eof_location.shift(ch);
-                self.lookahead = self.chars.next();
-                Some((location, ch))
-            }
-            None => None,
-        }
-    }
-
-    fn skip_to_end(&mut self) {
-        while let Some(_) = self.bump() {}
-    }
-
-    fn error<T>(&mut self, location: Location, code: ErrorCode) -> Result<T, Error> {
-        self.skip_to_end();
-        error(location, code)
-    }
-
-    fn eof_error<T>(&mut self) -> Result<T, Error> {
-        let location = self.eof_location;
-        self.error(location, UnexpectedEof)
-    }
-
-    fn slice(&self, start: Location, end: Location) -> &'input str {
-        let start = start.absolute;
-        let end = end.absolute;
-
-        &self.input[start.to_usize()..end.to_usize()]
-    }
-
-    fn take_while<F>(&mut self, start: Location, mut keep_going: F) -> (Location, &'input str)
-        where F: FnMut(char) -> bool,
-    {
-        self.take_until(start, |c| !keep_going(c))
-    }
-
-    fn take_until<F>(&mut self, start: Location, mut terminate: F) -> (Location, &'input str)
-        where F: FnMut(char) -> bool,
-    {
-        while let Some((end, ch)) = self.lookahead {
-            if terminate(ch) {
-                return (end, self.slice(start, end));
-            } else {
-                self.bump();
-            }
-        }
-        (self.eof_location, self.slice(start, self.eof_location))
-    }
-
-    fn test_lookahead<F>(&self, mut test: F) -> bool
-        where F: FnMut(char) -> bool,
-    {
-        self.lookahead.map_or(false, |(_, ch)| test(ch))
-    }
-
-    fn line_comment(&mut self, start: Location) -> Option<SpannedToken<'input>> {
-        let (end, comment) = self.take_until(start, |ch| ch == '\n');
-
-        if comment.starts_with("///") {
-            let skip = if comment.starts_with("/// ") { 4 } else { 3 };
-            let doc = Token::DocComment(comment[skip..].to_string());
-            Some(pos::spanned2(start, end, doc))
-        } else {
-            None
-        }
-    }
-
-    fn block_comment(&mut self, start: Location) -> Result<Option<SpannedToken<'input>>, Error> {
-        self.bump(); // Skip first '*'
-
-        loop {
-            let (_, comment) = self.take_until(start, |ch| ch == '*');
-            self.bump(); // Skip next '*'
-            match self.lookahead {
-                Some((end, '/')) => {
-                    self.bump();
-                    if comment.starts_with("/**") && comment != "/**" {
-                        // FIXME: whitespace alignment
-                        let doc = Token::DocComment(comment[3..].trim_left().to_string());
-                        return Ok(Some(pos::spanned2(start, end.shift('/'), doc)));
-                    } else {
-                        return Ok(None);
-                    }
-                }
-                Some((_, _)) => continue,
-                None => return self.eof_error(),
-            }
-        }
-    }
-
-    fn operator(&mut self, start: Location) -> SpannedToken<'input> {
-        let (end, op) = self.take_while(start, is_operator_char);
-
-        let token = match op {
-            "." => Token::Dot,
-            ":" => Token::Colon,
-            "=" => Token::Equals,
-            "|" => Token::Pipe,
-            "->" => Token::RArrow,
-            "#" => {
-                // Is this too permissive?
-                self.take_while(start, is_ident_start);
-                let (_, op) = self.take_while(start, is_operator_char);
-                Token::Operator(op)
-            }
-            op => Token::Operator(op),
-        };
-
-        pos::spanned2(start, end, token)
-    }
-
-    fn escape_code(&mut self) -> Result<char, Error> {
-        match self.bump() {
-            Some((_, '\'')) => Ok('\''),
-            Some((_, '"')) => Ok('"'),
-            Some((_, '\\')) => Ok('\\'),
-            Some((_, '/')) => Ok('/'),
-            Some((_, 'n')) => Ok('\n'),
-            Some((_, 'r')) => Ok('\r'),
-            Some((_, 't')) => Ok('\t'),
-            // TODO: Unicode escape codes
-            Some((start, ch)) => self.error(start, UnexpectedEscapeCode(ch)),
-            None => return self.eof_error(),
-        }
-    }
-
-    fn string_literal(&mut self, start: Location) -> Result<SpannedToken<'input>, Error> {
-        let mut string = String::new();
-
-        while let Some((next, ch)) = self.bump() {
-            match ch {
-                '\\' => string.push(self.escape_code()?),
-                '"' => {
-                    let end = next.shift(ch);
-                    let token = Token::StringLiteral(string);
-                    return Ok(pos::spanned2(start, end, token));
-                }
-                ch => string.push(ch),
-            }
-        }
-
-        self.error(start, UnterminatedStringLiteral)
-    }
-
-    fn char_literal(&mut self, start: Location) -> Result<SpannedToken<'input>, Error> {
-        let ch = match self.bump() {
-            Some((_, '\\')) => self.escape_code()?,
-            Some((_, '\'')) => return self.error(start, EmptyCharLiteral),
-            Some((_, ch)) => ch,
-            None => return self.eof_error(),
-        };
-
-        match self.bump() {
-            Some((end, '\'')) => Ok(pos::spanned2(start, end.shift('\''), Token::CharLiteral(ch))),
-            Some((_, _)) => self.error(start, UnterminatedCharLiteral), // UnexpectedEscapeCode?
-            None => self.eof_error(),
-        }
-    }
-
-    fn numeric_literal(&mut self, start: Location) -> Result<SpannedToken<'input>, Error> {
-        let (end, int) = self.take_while(start, is_digit);
-
-        let (start, end, token) = match self.lookahead {
-            Some((_, '.')) => {
-                self.bump(); // Skip '.'
-                let (end, float) = self.take_while(start, is_digit);
-                (start, end, Token::FloatLiteral(float.parse().unwrap()))
-            }
-            Some((end, 'b')) => {
-                self.bump(); // Skip 'b'
-                (start, end.shift('b'), Token::ByteLiteral(int.parse().unwrap()))
-            }
-            Some((start, ch)) if is_ident_start(ch) => return self.error(start, UnexpectedChar(ch)),
-            None | Some(_) => (start, end, Token::IntLiteral(int.parse().unwrap())),
-        };
-
-        Ok(pos::spanned2(start, end, token))
-    }
-
-    fn identifier(&mut self, start: Location) -> SpannedToken<'input> {
-        let (end, ident) = self.take_while(start, is_ident_continue);
-
-        let token = match ident {
-            "and" => Token::And,
-            "else" => Token::Else,
-            "if" => Token::If,
-            "in" => Token::In,
-            "let" => Token::Let,
-            "match" => Token::Match,
-            "then" => Token::Then,
-            "type" => Token::Type,
-            "with" => Token::With,
-            src => Token::Identifier(src),
-        };
-
-        pos::spanned2(start, end, token)
-    }
-}
-
-impl<'input> Iterator for Tokenizer<'input> {
-    type Item = Result<SpannedToken<'input>, Error>;
-
-    fn next(&mut self) -> Option<Result<SpannedToken<'input>, Error>> {
-        while let Some((start, ch)) = self.bump() {
-            return match ch {
-                ',' => Some(Ok(pos::spanned2(start, start.shift(ch), Token::Comma))),
-                '\\' => Some(Ok(pos::spanned2(start, start.shift(ch), Token::Lambda))),
-                '{' => Some(Ok(pos::spanned2(start, start.shift(ch), Token::LBrace))),
-                '[' => Some(Ok(pos::spanned2(start, start.shift(ch), Token::LBracket))),
-                '(' => Some(Ok(pos::spanned2(start, start.shift(ch), Token::LParen))),
-                '}' => Some(Ok(pos::spanned2(start, start.shift(ch), Token::RBrace))),
-                ']' => Some(Ok(pos::spanned2(start, start.shift(ch), Token::RBracket))),
-                ')' => Some(Ok(pos::spanned2(start, start.shift(ch), Token::RParen))),
-
-                '"' => Some(self.string_literal(start)),
-                '\'' => Some(self.char_literal(start)),
-
-                '/' if self.test_lookahead(|ch| ch == '/') => {
-                    match self.line_comment(start) {
-                        Some(token) => Some(Ok(token)),
-                        None => continue,
-                    }
-                }
-                '/' if self.test_lookahead(|ch| ch == '*') => {
-                    match self.block_comment(start) {
-                        Ok(Some(token)) => Some(Ok(token)),
-                        Ok(None) => continue,
-                        Err(err) => Some(Err(err)),
-                    }
-                }
-
-                ch if is_ident_start(ch) => Some(Ok(self.identifier(start))),
-                ch if is_digit(ch) => Some(self.numeric_literal(start)), // TODO: negative numbers?
-                ch if is_operator_char(ch) => Some(Ok(self.operator(start))),
-                ch if ch.is_whitespace() => continue,
-
-                ch => Some(self.error(start, UnexpectedChar(ch))),
-            };
-        }
-        None
-    }
-}
-
-
-#[cfg(test)]
-mod test {
-    use base::pos::{self, BytePos, Column, Line, Location};
-
-    use super::{Tokenizer, error};
-    use super::ErrorCode::*;
-    use token::Token;
-    use token::Token::*;
-
-    fn loc(byte: usize) -> Location {
-        Location {
-            line: Line::from(0),
-            column: Column::from(byte + 1),
-            absolute: BytePos::from(byte),
-        }
-    }
-
-    fn test(input: &str, expected: Vec<(&str, Token)>) {
-        let tokenizer = Tokenizer::new(input);
-        let len = expected.len();
-
-        for (token, (expected_span, expected_tok)) in tokenizer.zip(expected.into_iter()) {
-            println!("{:?}", token);
-            let start = loc(expected_span.find("~").unwrap());
-            let end = loc(expected_span.rfind("~").unwrap() + 1);
-            assert_eq!(Ok(pos::spanned2(start, end, expected_tok)), token);
-        }
-
-        // Make sure that there is nothing else to consume
-        let tokenizer = Tokenizer::new(input);
-        assert_eq!(None, tokenizer.skip(len).next());
-    }
-
-    #[test]
-    fn sample_lambda_expr() {
-        test(r#"(hi_, \a -> a ** a)"#,
-             vec![
-            (r#"~                  "#, LParen),
-            (r#" ~~~               "#, Identifier("hi_")),
-            (r#"    ~              "#, Comma),
-            (r#"      ~            "#, Lambda),
-            (r#"       ~           "#, Identifier("a")),
-            (r#"         ~~        "#, RArrow),
-            (r#"            ~      "#, Identifier("a")),
-            (r#"              ~~   "#, Operator("**")),
-            (r#"                 ~ "#, Identifier("a")),
-            (r#"                  ~"#, RParen),
-        ]);
-    }
-
-    #[test]
-    fn sample_array() {
-        test(r#"[1, a]"#,
-             vec![
-            (r#"~     "#, LBracket),
-            (r#" ~    "#, IntLiteral(1)),
-            (r#"  ~   "#, Comma),
-            (r#"    ~ "#, Identifier("a")),
-            (r#"     ~"#, RBracket),
-        ]);
-    }
-
-    #[test]
-    fn builtin_operators() {
-        test(r#". : = | ->"#,
-             vec![
-            (r#"~         "#, Dot),
-            (r#"  ~       "#, Colon),
-            (r#"    ~     "#, Equals),
-            (r#"      ~   "#, Pipe),
-            (r#"        ~~"#, RArrow),
-        ]);
-    }
-
-    #[test]
-    fn user_defined_operators() {
-        test(r#"+-* * /&|=<>: .. <->"#,
-             vec![
-            (r#"~~~                 "#, Operator("+-*")), // Horiffic!
-            (r#"    ~               "#, Operator("*")),
-            (r#"      ~~~~~~~       "#, Operator("/&|=<>:")), // Oh my...
-            (r#"              ~~    "#, Operator("..")),
-            (r#"                 ~~~"#, Operator("<->")),
-        ]);
-    }
-
-    #[test]
-    fn delimters() {
-        test(r#"{][ () }] "#,
-             vec![
-            (r#"~         "#, LBrace),
-            (r#" ~        "#, RBracket),
-            (r#"  ~       "#, LBracket),
-            (r#"    ~     "#, LParen),
-            (r#"     ~    "#, RParen),
-            (r#"       ~  "#, RBrace),
-            (r#"        ~ "#, RBracket),
-        ]);
-    }
-
-    #[test]
-    fn string_literals() {
-        test(r#"foo "bar\"\n" baz "" "\t""#,
-             vec![
-            (r#"~~~                      "#, Identifier("foo")),
-            (r#"    ~~~~~~~~~            "#, StringLiteral("bar\"\n".to_string())),
-            (r#"              ~~~        "#, Identifier("baz")),
-            (r#"                  ~~     "#, StringLiteral("".to_string())),
-            (r#"                     ~~~~"#, StringLiteral("\t".to_string())),
-        ]);
-    }
-
-    #[test]
-    fn string_literal_unexpected_escape_code() {
-        assert_eq!(Tokenizer::new(r#""\X""#).last(),
-                   Some(error(loc(2), UnexpectedEscapeCode('X'))));
-    }
-
-    #[test]
-    fn string_literal_unterminated() {
-        assert_eq!(Tokenizer::new(r#"foo "bar\"\n baz"#).last(),
-                   Some(error(loc(4), UnterminatedStringLiteral)));
-    }
-
-    #[test]
-    fn char_literals() {
-        test(r#"foo 'b' '\\' '\''"#,
-             vec![
-            (r#"~~~              "#, Identifier("foo")),
-            (r#"    ~~~          "#, CharLiteral('b')),
-            (r#"        ~~~~     "#, CharLiteral('\\')),
-            (r#"             ~~~~"#, CharLiteral('\'')),
-        ]);
-    }
-
-    #[test]
-    fn char_literal_empty() {
-        assert_eq!(Tokenizer::new(r#"foo ''"#).last(),
-                   Some(error(loc(4), EmptyCharLiteral)));
-    }
-
-    #[test]
-    fn char_literal_unexpected_escape_code() {
-        assert_eq!(Tokenizer::new(r#"'\X'"#).last(),
-                   Some(error(loc(2), UnexpectedEscapeCode('X'))));
-    }
-
-    #[test]
-    fn char_literal_unexpected_eof() {
-        assert_eq!(Tokenizer::new(r#"'"#).last(),
-                   Some(error(loc(1), UnexpectedEof)));
-        assert_eq!(Tokenizer::new(r#"  '"#).last(),
-                   Some(error(loc(3), UnexpectedEof)));
-        assert_eq!(Tokenizer::new(r#"'b"#).last(),
-                   Some(error(loc(2), UnexpectedEof)));
-        assert_eq!(Tokenizer::new(r#"'\\"#).last(),
-                   Some(error(loc(3), UnexpectedEof)));
-        assert_eq!(Tokenizer::new(r#"'\'"#).last(),
-                   Some(error(loc(3), UnexpectedEof)));
-    }
-
-    #[test]
-    fn char_literal_unterminated() {
-        assert_eq!(Tokenizer::new(r#"'frooble'"#).last(),
-                   Some(error(loc(0), UnterminatedCharLiteral)));
-    }
-
-    #[test]
-    fn int_literals() {
-        test(r#"3 1036 45"#,
-             vec![
-            (r#"~        "#, IntLiteral(3)),
-            (r#"  ~~~~   "#, IntLiteral(1036)),
-            (r#"       ~~"#, IntLiteral(45)),
-        ]);
-    }
-
-    #[test]
-    fn byte_literals() {
-        test(r#"3b 255b 45b"#,
-             vec![
-            (r#"~~         "#, ByteLiteral(3)),
-            (r#"   ~~~~    "#, ByteLiteral(255)),
-            (r#"        ~~~"#, ByteLiteral(45)),
-        ]);
-    }
-
-    #[test]
-    fn float_literals() {
-        test(r#"03.1415 1036.2"#,
-             vec![
-            (r#"~~~~~~~       "#, FloatLiteral(3.1415)),
-            (r#"        ~~~~~~"#, FloatLiteral(1036.2)),
-        ]);
-    }
-
-    #[test]
-    fn line_comments() {
-        test(r#"hi // hellooo"#,
-             vec![
-            (r#"~~           "#, Identifier("hi")),
-        ]);
-    }
-
-    #[test]
-    fn line_doc_comments() {
-        test(r#"hi ///hellooo/// hi"#,
-             vec![
-            (r#"~~                  "#, Identifier("hi")),
-            (r#"   ~~~~~~~~~~~~~~~~~"#, DocComment("hellooo/// hi".to_string())),
-        ]);
-    }
-
-    #[test]
-    fn line_doc_comments_with_space() {
-        test(r#"hi /// hellooo/// hi"#,
-             vec![
-            (r#"~~                  "#, Identifier("hi")),
-            (r#"   ~~~~~~~~~~~~~~~~~"#, DocComment("hellooo/// hi".to_string())),
-        ]);
-    }
-}
diff --git a/src/import.rs b/src/import.rs
index 8e2616f5..c79c685f 100644
--- a/src/import.rs
+++ b/src/import.rs
@@ -202,15 +202,15 @@ impl<I> Macro for Import<I>
                     };
 
                     let mut compiler = Compiler::new().implicit_prelude(modulename != "std.types");
-                    let errors = macros.errors.len();
+                    let errors = macros.errors.errors.len();
                     let macro_result =
                         file_contents.expand_macro_with(&mut compiler, macros, &modulename)?;
-                    if errors != macros.errors.len() {
+                    if errors != macros.errors.errors.len() {
                         // If macro expansion of the imported module fails we need to stop
                         // compilation of that module. To return an error we return one of the
                         // already emitted errors (which will be pushed back after this function
                         // returns)
-                        if let Some(err) = macros.errors.pop() {
+                        if let Some(err) = macros.errors.errors.pop() {
                             return Err(err);
                         }
                     }
diff --git a/src/lib.rs b/src/lib.rs
index e98f428f..fc5b0169 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -30,6 +30,7 @@ use base::error::{Errors, InFile};
 use base::metadata::Metadata;
 use base::symbol::{Symbol, Symbols, SymbolModule};
 use base::types::{ArcType, Type};
+use parser::ParseError;
 use check::typecheck::TypeError;
 use vm::Variants;
 use vm::api::{Getable, Hole, VmType, OpaqueValue};
@@ -44,7 +45,7 @@ quick_error! {
     #[derive(Debug)]
     pub enum Error {
         /// Error found when parsing gluon code
-        Parse(err: InFile<parser::Error>) {
+        Parse(err: InFile<ParseError>) {
             description(err.description())
             display("{}", err)
             from()
@@ -83,19 +84,22 @@ quick_error! {
 
 impl From<Errors<macros::Error>> for Error {
     fn from(mut errors: Errors<macros::Error>) -> Error {
-        if errors.len() == 1 {
-            let err = errors.pop().unwrap();
+        if errors.errors.len() == 1 {
+            let err = errors.errors.pop().unwrap();
             match err.downcast::<Error>() {
                 Ok(err) => *err,
                 Err(err) => Error::Macro(err),
             }
         } else {
-            Error::Multiple(errors.into_iter()
-                .map(|err| match err.downcast::<Error>() {
-                    Ok(err) => *err,
-                    Err(err) => Error::Macro(err),
-                })
-                .collect())
+            Error::Multiple(Errors {
+                errors: errors.errors
+                    .into_iter()
+                    .map(|err| match err.downcast::<Error>() {
+                        Ok(err) => *err,
+                        Err(err) => Error::Macro(err),
+                    })
+                    .collect(),
+            })
         }
     }
 }
@@ -103,10 +107,10 @@ impl From<Errors<macros::Error>> for Error {
 
 impl From<Errors<Error>> for Error {
     fn from(mut errors: Errors<Error>) -> Error {
-        if errors.len() == 1 {
-            errors.pop().unwrap()
+        if errors.errors.len() == 1 {
+            errors.errors.pop().unwrap()
         } else {
-            Error::Multiple(errors.into())
+            Error::Multiple(errors)
         }
     }
 }
@@ -140,7 +144,7 @@ impl Compiler {
     pub fn parse_expr(&mut self,
                       file: &str,
                       expr_str: &str)
-                      -> StdResult<SpannedExpr<Symbol>, InFile<parser::Error>> {
+                      -> StdResult<SpannedExpr<Symbol>, InFile<ParseError>> {
         self.parse_partial_expr(file, expr_str)
             .map_err(|(_, err)| err)
     }
@@ -150,8 +154,8 @@ impl Compiler {
         (&mut self,
          file: &str,
          expr_str: &str)
-         -> StdResult<SpannedExpr<Symbol>, (Option<SpannedExpr<Symbol>>, InFile<parser::Error>)> {
-        Ok(parser::parse_partial_expr(&mut SymbolModule::new(file.into(), &mut self.symbols),
+         -> StdResult<SpannedExpr<Symbol>, (Option<SpannedExpr<Symbol>>, InFile<ParseError>)> {
+        Ok(parser::parse_expr(&mut SymbolModule::new(file.into(), &mut self.symbols),
                                    expr_str)
             .map_err(|(expr, err)| (expr, InFile::new(file, expr_str, err)))?)
     }
diff --git a/vm/src/api.rs b/vm/src/api.rs
index d74e8653..6e16d27b 100644
--- a/vm/src/api.rs
+++ b/vm/src/api.rs
@@ -108,7 +108,7 @@ impl VmType for Hole {
     }
 }
 
-/// Type representing gluon's IO type#[derive(Debug)]
+/// Type representing gluon's IO type
 #[derive(Debug, PartialEq)]
 pub enum IO<T> {
     Value(T),
@@ -154,6 +154,19 @@ pub unsafe fn primitive_f<'vm, F>(name: &'static str,
     }
 }
 
+/// Creates a `GluonFunction` from a function implementing `VMFunction`
+///
+/// ```rust
+/// #[macro_use]
+/// extern crate gluon_vm;
+/// fn test(_x: i32, _y: String) -> f64 {
+///     panic!()
+/// }
+///
+/// fn main() {
+///     primitive!(2 test);
+/// }
+/// ```
 #[macro_export]
 macro_rules! primitive {
     (0 $name: expr) => {
@@ -1259,8 +1272,9 @@ pub mod record {
     }
 }
 
+#[doc(hidden)]
 #[macro_export]
-macro_rules! types {
+macro_rules! field_decl_inner {
     ($($field: ident),*) => {
         $(
         #[allow(non_camel_case_types)]
@@ -1275,31 +1289,54 @@ macro_rules! types {
     }
 }
 
+/// Declares fields useable by the record macros
+///
+/// ```rust
+/// #[macro_use]
+/// extern crate gluon_vm;
+/// # fn main() { }
+///
+/// field_decl! {x, y}
+/// ```
+#[macro_export]
+macro_rules! field_decl {
+    ($($field: ident),*) => {
+        mod _field { field_decl_inner!($($field),*); }
+    }
+}
+
+#[doc(hidden)]
 #[macro_export]
-macro_rules! hlist {
+macro_rules! record_no_decl_inner {
     () => { () };
     ($field: ident => $value: expr) => {
         $crate::api::record::HList((_field::$field, $value), ())
     };
     ($field: ident => $value: expr, $($field_tail: ident => $value_tail: expr),*) => {
         $crate::api::record::HList((_field::$field, $value),
-                                   hlist!($($field_tail => $value_tail),*))
-    }
-}
-
-#[macro_export]
-macro_rules! field_decl {
-    ($($field: ident),*) => {
-        mod _field { types!($($field),*); }
-    }
+                                   record_no_decl_inner!($($field_tail => $value_tail),*))
+    };
 }
 
+/// Macro that creates a record that can be passed to gluon. Reuses already declared fields
+/// instead of generating unique ones.
+///
+/// ```rust
+/// #[macro_use]
+/// extern crate gluon_vm;
+///
+/// field_decl! {x, y, name}
+///
+/// fn main() {
+///     record_no_decl!(x => 1, y => 2, name => "Gluon");
+/// }
+/// ```
 #[macro_export]
 macro_rules! record_no_decl {
     ($($field: ident => $value: expr),*) => {
         {
             $crate::api::Record {
-                fields: hlist!($($field => $value),*)
+                fields: record_no_decl_inner!($($field => $value),*)
             }
         }
     }
@@ -1307,8 +1344,12 @@ macro_rules! record_no_decl {
 
 /// Macro that creates a record that can be passed to gluon
 ///
-/// ```rust,ignore
-/// record!(x => 1, y => 2, name => "Gluon")
+/// ```rust
+/// #[macro_use]
+/// extern crate gluon_vm;
+/// fn main() {
+///     record!(x => 1, y => 2, name => "Gluon");
+/// }
 /// ```
 #[macro_export]
 macro_rules! record {
@@ -1320,6 +1361,74 @@ macro_rules! record {
     }
 }
 
+#[doc(hidden)]
+#[macro_export]
+macro_rules! record_type_inner {
+    () => { () };
+    ($field: ident => $value: ty) => {
+        $crate::api::record::HList<(_field::$field, $value), ()>
+    };
+    ($field: ident => $value: ty, $($field_tail: ident => $value_tail: ty),*) => {
+        $crate::api::record::HList<(_field::$field, $value),
+                                record_type_inner!( $($field_tail => $value_tail),*)>
+    }
+}
+
+/// Creates a Rust type compatible with the type of `record_no_decl!`
+///
+/// ```rust
+/// #[macro_use]
+/// extern crate gluon_vm;
+/// # fn main() { }
+/// // Fields used in `record_type!` needs to be forward declared
+/// field_decl! {x, y}
+/// fn new_vec(x: f64, y: f64) -> record_type!(x => f64, y => f64) {
+///     record_no_decl!(x => y, y => y)
+/// }
+/// ```
+#[macro_export]
+macro_rules! record_type {
+    ($($field: ident => $value: ty),*) => {
+        $crate::api::Record<
+            record_type_inner!($($field => $value),*)
+            >
+    }
+}
+
+#[doc(hidden)]
+#[macro_export]
+macro_rules! record_p_impl {
+    () => { () };
+    ($field: pat) => {
+        $crate::api::record::HList((_, $field), ())
+    };
+    ($field: pat, $($field_tail: pat),*) => {
+        $crate::api::record::HList((_, $field),
+                                record_p_impl!($($field_tail),*))
+    }
+}
+
+/// Creates a pattern which matches on marshalled gluon records
+///
+/// ```rust
+/// #[macro_use]
+/// extern crate gluon_vm;
+/// fn main() {
+///     match record!(x => 1, y => "y") {
+///         record_p!(a, "y") => assert_eq!(a, 1),
+///         _ => assert!(false),
+///     }
+/// }
+/// ```
+#[macro_export]
+macro_rules! record_p {
+    ($($field: pat),*) => {
+        $crate::api::Record {
+            fields: record_p_impl!($($field),*)
+        }
+    }
+}
+
 impl<'vm, F: VmType> VmType for Primitive<F> {
     type Type = F::Type;
     fn make_type(vm: &Thread) -> ArcType {
@@ -1640,13 +1749,3 @@ make_vm_function!(A, B, C, D);
 make_vm_function!(A, B, C, D, E);
 make_vm_function!(A, B, C, D, E, F);
 make_vm_function!(A, B, C, D, E, F, G);
-
-#[macro_export]
-macro_rules! vm_function {
-    ($func: expr) => ({
-        fn wrapper<'b, 'c>(vm: &Thread) {
-            $func.unpack_and_call(vm)
-        }
-        wrapper
-    })
-}
diff --git a/vm/src/channel.rs b/vm/src/channel.rs
index 6abee704..c5999d3f 100644
--- a/vm/src/channel.rs
+++ b/vm/src/channel.rs
@@ -6,7 +6,6 @@ use std::collections::VecDeque;
 use base::types::{ArcType, Type};
 
 use {Error, Result as VmResult};
-use api::record::{Record, HList};
 use api::{Generic, VmType, primitive, WithVM, Function, Pushable, RuntimeResult};
 use api::generic::A;
 use gc::{Traverseable, Gc, GcPtr};
@@ -98,7 +97,7 @@ impl<T: VmType> VmType for Receiver<T>
 field_decl!{ sender, receiver }
 
 
-pub type ChannelRecord<S, R> = Record<HList<(_field::sender, S), HList<(_field::receiver, R), ()>>>;
+pub type ChannelRecord<S, R> = record_type!(sender => S, receiver => R);
 
 /// FIXME The dummy `a` argument should not be needed to ensure that the channel can only be used
 /// with a single type
diff --git a/vm/src/compiler.rs b/vm/src/compiler.rs
index 9d6a6408..f69a71e5 100644
--- a/vm/src/compiler.rs
+++ b/vm/src/compiler.rs
@@ -526,7 +526,7 @@ impl<'a> Compiler<'a> {
                     Jump(function.function.instructions.len() as VmIndex);
             }
             Expr::Infix(ref lhs, ref op, ref rhs) => {
-                if op.value.name.as_ref() == "&&" {
+                if op.name.as_ref() == "&&" {
                     self.compile(&**lhs, function, false)?;
                     let lhs_end = function.function.instructions.len();
                     function.emit(CJump(lhs_end as VmIndex + 3));//Jump to rhs evaluation
@@ -539,7 +539,7 @@ impl<'a> Compiler<'a> {
                     // replace jump instruction
                     function.function.instructions[lhs_end + 2] =
                         Jump(function.function.instructions.len() as VmIndex);
-                } else if op.value.name.as_ref() == "||" {
+                } else if op.name.as_ref() == "||" {
                     self.compile(&**lhs, function, false)?;
                     let lhs_end = function.function.instructions.len();
                     function.emit(CJump(0));
@@ -553,7 +553,7 @@ impl<'a> Compiler<'a> {
                     let end = function.function.instructions.len();
                     function.function.instructions[end - 2] = Jump(end as VmIndex);
                 } else {
-                    let instr = match self.symbols.string(&op.value.name) {
+                    let instr = match self.symbols.string(&op.name) {
                         "#Int+" => AddInt,
                         "#Int-" => SubtractInt,
                         "#Int*" => MultiplyInt,
@@ -573,7 +573,7 @@ impl<'a> Compiler<'a> {
                         "#Float<" => FloatLT,
                         "#Float==" => FloatEQ,
                         _ => {
-                            self.load_identifier(&op.value.name, function)?;
+                            self.load_identifier(&op.name, function)?;
                             Call(2)
                         }
                     };
@@ -782,12 +782,12 @@ impl<'a> Compiler<'a> {
                 });
             }
             Expr::Block(ref exprs) => {
-                let (last, inits) = exprs.split_last().expect("Expr in block");
-                for expr in inits {
+                let (last, exprs) = exprs.split_last().expect("Expr in block");
+                for expr in exprs {
                     self.compile(expr, function, false)?;
                 }
                 self.compile(last, function, tail_position)?;
-                function.emit(Slide(inits.len() as u32));
+                function.emit(Slide(exprs.len() as u32 - 1));
             }
         }
         Ok(None)
diff --git a/vm/src/macros.rs b/vm/src/macros.rs
index d8e73dc0..d4622107 100644
--- a/vm/src/macros.rs
+++ b/vm/src/macros.rs
@@ -111,7 +111,7 @@ impl<'a> MutVisitor for MacroExpander<'a> {
                                 match m.expand(self, args) {
                                     Ok(e) => Some(e),
                                     Err(err) => {
-                                        self.errors.push(err);
+                                        self.errors.error(err);
                                         None
                                     }
                                 }
diff --git a/vm/src/value.rs b/vm/src/value.rs
index 20743817..77ed2d85 100644
--- a/vm/src/value.rs
+++ b/vm/src/value.rs
@@ -485,7 +485,6 @@ impl Repr {
     }
 }
 
-#[macro_export]
 macro_rules! on_array {
     ($array: expr, $f: expr) => {
         {


Test patch:
diff --git a/check/tests/fail.rs b/check/tests/fail.rs
index 14aabbfc..e6b24b19 100644
--- a/check/tests/fail.rs
+++ b/check/tests/fail.rs
@@ -23,16 +23,16 @@ macro_rules! assert_err {
         match $e {
             Ok(x) => assert!(false, "Expected error, got {}",
                              types::display_type(&*symbols.borrow(), &x)),
-            Err(errors) => {
-                let mut iter = (&errors).into_iter();
+            Err(err) => {
+                let mut iter = err.errors.iter();
                 $(
                 match iter.next() {
                     Some(&Spanned { value: $id, .. }) => (),
                     _ => assert!(false, "Found errors:\n{}\nbut expected {}",
-                                        errors, stringify!($id)),
+                                        err, stringify!($id)),
                 }
                 )+
-                assert!(iter.count() == 0, "Found more errors than expected\n{}", errors);
+                assert!(iter.count() == 0, "Found more errors than expected\n{}", err);
             }
         }
     }}
@@ -51,31 +51,27 @@ macro_rules! assert_unify_err {
         match $e {
             Ok(x) => assert!(false, "Expected error, got {}",
                              types::display_type(&*symbols.borrow(), &x)),
-            Err(errors) => {
-                for error in errors {
-                    match error {
+            Err(err) => {
+                for err in err.errors.iter() {
+                    match *err {
                         Spanned { value: Unification(_, _, ref errors), .. } => {
                             let mut iter = errors.iter();
                             $(
                             match iter.next() {
                                 Some(&$id) => (),
-                                Some(error2) => {
-                                    assert!(false, "Found errors:\n{}\nExpected:\n{}\nFound\n:{:?}",
-                                            error, stringify!($id), error2);
-                                }
-                                None => {
-                                    assert!(false, "Found errors:\n{}\nbut expected {}",
-                                            error, stringify!($id));
-                                }
+                                Some(err2) => assert!(false, "Found errors:\n{}\nExpected:\n{}\nFound\n:{:?}",
+                                                    err, stringify!($id), err2),
+                                None => assert!(false, "Found errors:\n{}\nbut expected {}",
+                                                    err, stringify!($id))
                             }
                             )+
                             assert!(iter.count() == 0,
                                     "Found more errors than expected\n{}",
-                                    error);
+                                    err);
                         }
                         _ => assert!(false,
                                      "Found errors:\n{}\nbut expected an unification error",
-                                     error)
+                                     err)
                     }
                 }
             }
diff --git a/check/tests/pass.rs b/check/tests/pass.rs
index 11cd4a3b..ab178ac0 100644
--- a/check/tests/pass.rs
+++ b/check/tests/pass.rs
@@ -731,9 +731,10 @@ in f "123"
     let result = support::typecheck(text);
 
     assert!(result.is_err());
-    let errors: Vec<_> = result.unwrap_err().into();
-    assert_eq!(errors.len(), 1);
-    assert_eq!(errors[0].span, Span::new(BytePos::from(26), BytePos::from(31)));
+    let err = result.unwrap_err();
+    assert_eq!(err.errors.len(), 1);
+    assert_eq!(err.errors[0].span,
+               Span::new(BytePos::from(26), BytePos::from(31)));
 }
 
 /// Test that overload resolution selects the closest implementation that matches even if another
diff --git a/check/tests/support/mod.rs b/check/tests/support/mod.rs
index ee19aade..308d1936 100644
--- a/check/tests/support/mod.rs
+++ b/check/tests/support/mod.rs
@@ -3,7 +3,7 @@ use base::kind::{ArcKind, Kind, KindEnv};
 use base::symbol::{Symbols, SymbolModule, Symbol, SymbolRef};
 use base::types::{self, Alias, ArcType, Generic, PrimitiveEnv, Type, TypeEnv};
 use check::typecheck::{self, Typecheck};
-use parser::{parse_partial_expr, ParseErrors};
+use parser;
 
 use std::cell::RefCell;
 use std::marker::PhantomData;
@@ -37,11 +37,11 @@ pub fn intern(s: &str) -> Symbol {
 }
 
 pub fn parse_new(s: &str)
-                 -> Result<SpannedExpr<Symbol>, (Option<SpannedExpr<Symbol>>, ParseErrors)> {
+                 -> Result<SpannedExpr<Symbol>, (Option<SpannedExpr<Symbol>>, ::parser::Error)> {
     let symbols = get_local_interner();
     let mut symbols = symbols.borrow_mut();
     let mut module = SymbolModule::new("test".into(), &mut symbols);
-    parse_partial_expr(&mut module, &s)
+    parser::parse_expr(&mut module, &s)
 }
 
 #[allow(dead_code)]
diff --git a/parser/tests/basic.rs b/parser/tests/basic.rs
index e1949174..9d0963c0 100644
--- a/parser/tests/basic.rs
+++ b/parser/tests/basic.rs
@@ -6,13 +6,162 @@ extern crate log;
 #[macro_use]
 extern crate collect_mac;
 
-#[macro_use]
 mod support;
 
 use base::ast::*;
-use base::pos::{BytePos, Span, Spanned};
-use base::types::{Alias, Field, Type};
-use support::*;
+use base::kind::Kind;
+use base::pos::{self, BytePos, Span, Spanned};
+use base::types::{Alias, ArcType, Field, Generic, Type};
+use parser::{parse_string, Error};
+use support::MockEnv;
+
+pub fn intern(s: &str) -> String {
+    String::from(s)
+}
+
+type SpExpr = SpannedExpr<String>;
+
+fn no_loc<T>(value: T) -> Spanned<T, BytePos> {
+    pos::spanned(Span::default(), value)
+}
+
+fn binop(l: SpExpr, s: &str, r: SpExpr) -> SpExpr {
+    no_loc(Expr::Infix(Box::new(l), TypedIdent::new(intern(s)), Box::new(r)))
+}
+
+fn int(i: i64) -> SpExpr {
+    no_loc(Expr::Literal(Literal::Int(i)))
+}
+
+fn let_(s: &str, e: SpExpr, b: SpExpr) -> SpExpr {
+    let_a(s, &[], e, b)
+}
+
+fn let_a(s: &str, args: &[&str], e: SpExpr, b: SpExpr) -> SpExpr {
+    no_loc(Expr::LetBindings(vec![ValueBinding {
+                                      comment: None,
+                                      name: no_loc(Pattern::Ident(TypedIdent::new(intern(s)))),
+                                      typ: Type::hole(),
+                                      args: args.iter()
+                                          .map(|i| TypedIdent::new(intern(i)))
+                                          .collect(),
+                                      expr: e,
+                                  }],
+                             Box::new(b)))
+}
+
+fn id(s: &str) -> SpExpr {
+    no_loc(Expr::Ident(TypedIdent::new(intern(s))))
+}
+
+fn field(s: &str, typ: ArcType<String>) -> Field<String> {
+    Field {
+        name: intern(s),
+        typ: typ,
+    }
+}
+
+fn typ(s: &str) -> ArcType<String> {
+    assert!(s.len() != 0);
+    match s.parse() {
+        Ok(b) => Type::builtin(b),
+        Err(()) if s.starts_with(char::is_lowercase) => generic_ty(s),
+        Err(()) => Type::ident(intern(s)),
+    }
+}
+
+fn generic_ty(s: &str) -> ArcType<String> {
+    Type::generic(generic(s))
+}
+
+fn generic(s: &str) -> Generic<String> {
+    Generic {
+        kind: Kind::variable(0),
+        id: intern(s),
+    }
+}
+
+fn app(e: SpExpr, args: Vec<SpExpr>) -> SpExpr {
+    no_loc(Expr::App(Box::new(e), args))
+}
+
+fn if_else(p: SpExpr, if_true: SpExpr, if_false: SpExpr) -> SpExpr {
+    no_loc(Expr::IfElse(Box::new(p), Box::new(if_true), Box::new(if_false)))
+}
+
+fn case(e: SpExpr, alts: Vec<(Pattern<String>, SpExpr)>) -> SpExpr {
+    no_loc(Expr::Match(Box::new(e),
+                       alts.into_iter()
+                           .map(|(p, e)| {
+                               Alternative {
+                                   pattern: no_loc(p),
+                                   expr: e,
+                               }
+                           })
+                           .collect()))
+}
+
+fn lambda(name: &str, args: Vec<String>, body: SpExpr) -> SpExpr {
+    no_loc(Expr::Lambda(Lambda {
+        id: TypedIdent::new(intern(name)),
+        args: args.into_iter().map(|id| TypedIdent::new(id)).collect(),
+        body: Box::new(body),
+    }))
+}
+
+fn type_decl(name: String,
+             args: Vec<Generic<String>>,
+             typ: ArcType<String>,
+             body: SpExpr)
+             -> SpExpr {
+    type_decls(vec![TypeBinding {
+                        comment: None,
+                        name: name.clone(),
+                        alias: Alias::new(name, args, typ),
+                    }],
+               body)
+}
+
+fn type_decls(binds: Vec<TypeBinding<String>>, body: SpExpr) -> SpExpr {
+    no_loc(Expr::TypeBindings(binds, Box::new(body)))
+}
+
+fn record(fields: Vec<(String, Option<SpExpr>)>) -> SpExpr {
+    record_a(Vec::new(), fields)
+}
+
+fn record_a(types: Vec<(String, Option<ArcType<String>>)>,
+            fields: Vec<(String, Option<SpExpr>)>)
+            -> SpExpr {
+    no_loc(Expr::Record {
+        typ: Type::hole(),
+        types: types,
+        exprs: fields,
+    })
+}
+
+fn field_access(expr: SpExpr, field: &str) -> SpExpr {
+    no_loc(Expr::Projection(Box::new(expr), intern(field), Type::hole()))
+}
+
+fn array(fields: Vec<SpExpr>) -> SpExpr {
+    no_loc(Expr::Array(Array {
+        typ: Type::hole(),
+        exprs: fields,
+    }))
+}
+
+fn parse(input: &str) -> Result<SpannedExpr<String>, (Option<SpannedExpr<String>>, Error)> {
+    parse_string(&mut MockEnv::new(), input)
+}
+
+macro_rules! parse_new {
+    ($input:expr) => {{
+        // Replace windows line endings so that byte positins match up on multiline expressions
+        let input = $input.replace("\r\n", "\n");
+        parse(&input).unwrap_or_else(|(_, err)| panic!("{}", err))
+    }}
+}
 
 #[test]
 fn dangling_in() {
@@ -236,6 +385,26 @@ fn let_pattern() {
                                         Box::new(id("x")))));
 }
 
+#[test]
+fn associated_record() {
+    let _ = ::env_logger::init();
+    let e = parse_new!("type Test a = { Fn, x: a } in { Fn = Int -> Array Int, Test, x = 1 }");
+
+    let test_type = Type::record(vec![Field {
+                                          name: String::from("Fn"),
+                                          typ: Alias::new(String::from("Fn"), vec![], typ("Fn")),
+                                      }],
+                                 vec![Field {
+                                          name: intern("x"),
+                                          typ: typ("a"),
+                                      }]);
+    let fn_type = Type::function(vec![typ("Int")], Type::array(typ("Int")));
+    let record = record_a(vec![(intern("Fn"), Some(fn_type)), (intern("Test"), None)],
+                          vec![(intern("x"), Some(int(1)))]);
+    assert_eq!(e,
+               type_decl(intern("Test"), vec![generic("a")], test_type, record));
+}
+
 #[test]
 fn span_identifier() {
     let _ = ::env_logger::init();
@@ -252,7 +421,9 @@ fn span_integer() {
     assert_eq!(e.span, Span::new(BytePos::from(0), BytePos::from(4)));
 }
 
+// FIXME The span of string literals includes the spaces after them
 #[test]
+#[ignore]
 fn span_string_literal() {
     let _ = ::env_logger::init();
 
@@ -396,7 +567,7 @@ id
 }
 
 #[test]
-fn partial_field_access_simple() {
+fn partial_field_access() {
     let _ = ::env_logger::init();
     let text = r#"test."#;
     let e = parse(text);
@@ -461,44 +632,3 @@ fn quote_in_identifier() {
                  app(id("f'"), vec![int(1), int(2)]));
     assert_eq!(e, a);
 }
-
-// Test that this is `let x = 1 in {{ a; b }}` and not `{{ (let x = 1 in a) ; b }}`
-#[test]
-fn block_open_after_let_in() {
-    let _ = ::env_logger::init();
-    let text = r#"
-        let x = 1
-        a
-        b
-        "#;
-    let e = parse_new!(text);
-    match e.value {
-        Expr::LetBindings(..) => (),
-        _ => panic!("{:?}", e),
-    }
-}
-
-#[test]
-fn block_open_after_explicit_let_in() {
-    let _ = ::env_logger::init();
-    let text = r#"
-        let x = 1
-        in
-        a
-        b
-        "#;
-    let e = parse_new!(text);
-    match e.value {
-        Expr::LetBindings(..) => (),
-        _ => panic!("{:?}", e),
-    }
-}
-
-#[test]
-fn record_type_field() {
-    let _ = ::env_logger::init();
-    let text = r"{ Test, x }";
-    let e = parse_new!(text);
-    assert_eq!(e,
-               record_a(vec![("Test".into(), None)], vec![("x".into(), None)]))
-}
diff --git a/parser/tests/indentation.rs b/parser/tests/indentation.rs
index 634996ab..493600de 100644
--- a/parser/tests/indentation.rs
+++ b/parser/tests/indentation.rs
@@ -4,46 +4,49 @@ extern crate log;
 
 extern crate gluon_base as base;
 extern crate gluon_parser as parser;
+extern crate combine;
 
 mod support;
 
+use combine::primitives::{Error, Info};
 use base::ast::*;
+use base::error::Errors;
 use base::pos::{self, BytePos};
-use parser::{Error, parse_string, ParseErrors};
+use parser::{parse_string, ParseError};
+use parser::lexer::Token;
 use support::MockEnv;
 
-fn parse(text: &str) -> Result<SpannedExpr<String>, ParseErrors> {
+fn parse(text: &str) -> Result<SpannedExpr<String>, ::parser::Error> {
     parse_string(&mut MockEnv::new(), text).map_err(|(_, err)| err)
 }
 
 #[test]
 fn unclosed_let() {
     let _ = ::env_logger::init();
-
-    let result = parse(r#"
+    let text = r#"
 let y =
     let x = 1
 y
-"#);
-
+"#;
+    let result = parse(text);
     assert!(result.is_err(), "{}", result.unwrap_err());
 }
 
 #[test]
 fn sequence_expressions() {
     let _ = ::env_logger::init();
-
-    let result = parse(r#"
+    let text = r#"
 f 1 2
 g ""
-"#);
-
+"#;
+    let result = parse(text);
     match result {
         Ok(expr) => {
-            if let Expr::Block(ref exprs) = expr.value {
-                assert_eq!(exprs.len(), 2);
-            } else {
-                assert!(false, "Expected block, found {:?}", expr);
+            match expr.value {
+                Expr::Block(ref exprs) => {
+                    assert_eq!(exprs.len(), 2);
+                }
+                _ => assert!(false, "Expected block, found {:?}", expr),
             }
         }
         Err(err) => assert!(false, "{}", err),
@@ -53,69 +56,69 @@ g ""
 #[test]
 fn wrong_indent_expression() {
     let _ = ::env_logger::init();
-
-    let result = parse(r#"
+    let text = r#"
 let y =
     let x = 1
     x
    2
 y
-"#);
-
-    let error = Error::UnexpectedToken("IntLiteral".into());
-    let span = pos::span(BytePos::from(32), BytePos::from(32));
-    let errors = ParseErrors::from(vec![pos::spanned(span, error)]);
-
-    assert_eq!(result, Err(errors));
+"#;
+    let result = parse(text);
+    assert_eq!(result,
+               Err(Errors {
+                   errors: vec![pos::spanned2(BytePos::from(32), BytePos::from(32),
+                    ParseError {
+                                    errors: vec![Error::Unexpected(Info::Token(Token::Int(2))),
+                                                 Error::Expected("`in` or an expression in the \
+                                                                  same column as the `let`"
+                                                     .into())],
+                   })],
+               }));
 }
 
 #[test]
 fn let_in_let_args() {
     let _ = ::env_logger::init();
-
-    let result = parse(r#"
+    let text = r#"
 let x =
     let y = 1
     let z = ""
     y + 1
 in x
-"#);
-
+"#;
+    let result = parse(text);
     assert!(result.is_ok(), "{}", result.unwrap_err());
 }
 #[test]
 fn and_on_same_line_as_type() {
     let _ = ::env_logger::init();
-
-    let result = parse(r#"
+    let text = r#"
 type M a = | M a
 and M2 a = M a
 and HKT m = { x: m Int }
 in 1
-"#);
-
+"#;
+    let result = parse(text);
     assert!(result.is_ok(), "{}", result.unwrap_err());
 }
 
 #[test]
 fn close_brace_on_same_line_as_type() {
     let _ = ::env_logger::init();
-
-    let result = parse(r#"
+    let text = r#"
 type M = {
     x: Int
 }
 
 { M }
-"#);
-
+"#;
+    let result = parse(text);
     assert!(result.is_ok(), "{}", result.unwrap_err());
 }
 #[test]
 fn record_unindented_fields() {
     let _ = ::env_logger::init();
-
-    let result = parse(r#"
+    let text = r#"
 let monad_Test: Monad Test = {
     (>>=) = \ta f ->
         match ta with
@@ -123,8 +126,8 @@ let monad_Test: Monad Test = {
     return = \x -> T x
 }
 in 1
-"#);
-
+"#;
+    let result = parse(text);
     assert!(result.is_ok(), "{}", result.unwrap_err());
 }
 
@@ -132,33 +135,30 @@ in 1
 #[test]
 fn to_much_unindented_case_of() {
     let _ = ::env_logger::init();
-
-    let result = parse(r#"
+    let text = r#"
 let test x =
     match x with
   | Some y -> y
   | None -> 0
 in test
-"#);
-
+"#;
+    let result = parse(text);
     assert!(result.is_err(), "{:?}", result.unwrap());
 }
 
 #[test]
 fn match_with_alignment() {
     let _ = ::env_logger::init();
-
-    let result = parse(r#"
+    let text = r#"
 match x with
     | Some y ->
         match x with
             | Some y2 -> y2
             | None -> 0
     | None -> 0
-"#);
-
+"#;
+    let result = parse(text);
     assert!(result.is_ok(), "{}", result.unwrap_err());
-
     match result.as_ref().unwrap().value {
         Expr::Match(_, ref alts) => assert_eq!(alts.len(), 2),
         ref x => panic!("{:?}", x),
@@ -168,29 +168,26 @@ match x with
 #[test]
 fn allow_unindented_lambda() {
     let _ = ::env_logger::init();
-
-    let result = parse(r#"
+    let text = r#"
 let f = \x ->
     let y = x + 1
     y
 
 f
-"#);
-
+"#;
+    let result = parse(text);
     assert!(result.is_ok(), "{}", result.unwrap_err());
 }
 
 #[test]
 fn close_lambda_on_implicit_statement() {
     let _ = ::env_logger::init();
-
-    let result = parse(r#"
+    let text = r#"
 \x -> x
 1
-"#);
-
+"#;
+    let result = parse(text);
     assert!(result.is_ok(), "{}", result.unwrap_err());
-
     match result.unwrap().value {
         Expr::Block(ref exprs) if exprs.len() == 2 => (),
         expr => assert!(false, "{:?}", expr),
@@ -200,18 +197,16 @@ fn close_lambda_on_implicit_statement() {
 #[test]
 fn if_expr_else_is_block() {
     let _ = ::env_logger::init();
-
-    let result = parse(r#"
+    let text = r#"
 let f x = ()
 if True then
     1
 else
     f 2
     2
-"#);
-
+"#;
+    let result = parse(text);
     assert!(result.is_ok(), "{}", result.unwrap_err());
-
     if let Expr::LetBindings(_, ref expr) = result.as_ref().unwrap().value {
         if let Expr::IfElse(_, _, ref if_false) = expr.value {
             if let Expr::Block(_) = if_false.as_ref().value {
@@ -219,43 +214,38 @@ else
             }
         }
     }
-
     assert!(false, "{:?}", result.unwrap());
 }
 
 #[test]
 fn if_else_if_else() {
     let _ = ::env_logger::init();
-
-    let result = parse(r#"
+    let text = r#"
 if True then
     1
 else if True then
     2
 else
     3
-"#);
-
+"#;
+    let result = parse(text);
     assert!(result.is_ok(), "{}", result.unwrap_err());
 }
 
 #[test]
 fn block_match() {
     let _ = ::env_logger::init();
-
-    let result = parse(r#"
+    let text = r#"
 match True with
 | True -> 1
 | False -> 0
 2
-"#);
-
+"#;
+    let result = parse(text);
     assert!(result.is_ok(), "{}", result.unwrap_err());
-
     if let Expr::Block(ref exprs) = result.as_ref().unwrap().value {
         assert_eq!(2, exprs.len());
         return;
     }
-
     assert!(false, "{:?}", result.unwrap());
 }
diff --git a/parser/tests/stack_overflow.rs b/parser/tests/stack_overflow.rs
index 5baf364c..67d164ac 100644
--- a/parser/tests/stack_overflow.rs
+++ b/parser/tests/stack_overflow.rs
@@ -4,12 +4,12 @@ extern crate gluon_base as base;
 extern crate gluon_parser as parser;
 
 use base::ast::SpannedExpr;
-use parser::{parse_string, ParseErrors};
+use parser::{parse_string, Error};
 use support::MockEnv;
 
 mod support;
 
-fn parse(text: &str) -> Result<SpannedExpr<String>, ParseErrors> {
+fn parse(text: &str) -> Result<SpannedExpr<String>, Error> {
     parse_string(&mut MockEnv::new(), text).map_err(|(_, err)| err)
 }
 
diff --git a/parser/tests/support/mod.rs b/parser/tests/support/mod.rs
index a8323e6c..4e485949 100644
--- a/parser/tests/support/mod.rs
+++ b/parser/tests/support/mod.rs
@@ -1,12 +1,4 @@
-#![allow(unused)]
-
-use base::ast::{Alternative, Array, DisplayEnv, Expr, IdentEnv, Lambda, Literal, Pattern,
-                SpannedExpr, TypeBinding, TypedIdent, ValueBinding};
-use base::error::Errors;
-use base::pos::{self, BytePos, Span, Spanned};
-use base::kind::Kind;
-use base::types::{Alias, ArcType, Field, Generic, Type};
-use parser::{Error, ParseErrors, parse_string};
+use base::ast::{DisplayEnv, IdentEnv};
 use std::marker::PhantomData;
 
 pub struct MockEnv<T>(PhantomData<T>);
@@ -32,152 +24,3 @@ impl<T> IdentEnv for MockEnv<T>
         T::from(s)
     }
 }
-
-pub fn parse(input: &str)
-             -> Result<SpannedExpr<String>, (Option<SpannedExpr<String>>, ParseErrors)> {
-    parse_string(&mut MockEnv::new(), input)
-}
-
-macro_rules! parse_new {
-    ($input:expr) => {{
-        // Replace windows line endings so that byte positins match up on multiline expressions
-        let input = $input.replace("\r\n", "\n");
-        parse(&input).unwrap_or_else(|(_, err)| panic!("{}", err))
-    }}
-}
-
-pub fn intern(s: &str) -> String {
-    String::from(s)
-}
-
-pub type SpExpr = SpannedExpr<String>;
-
-pub fn no_loc<T>(value: T) -> Spanned<T, BytePos> {
-    pos::spanned(Span::default(), value)
-}
-
-pub fn binop(l: SpExpr, s: &str, r: SpExpr) -> SpExpr {
-    no_loc(Expr::Infix(Box::new(l), no_loc(TypedIdent::new(intern(s))), Box::new(r)))
-}
-
-pub fn int(i: i64) -> SpExpr {
-    no_loc(Expr::Literal(Literal::Int(i)))
-}
-
-pub fn let_(s: &str, e: SpExpr, b: SpExpr) -> SpExpr {
-    let_a(s, &[], e, b)
-}
-
-pub fn let_a(s: &str, args: &[&str], e: SpExpr, b: SpExpr) -> SpExpr {
-    no_loc(Expr::LetBindings(vec![ValueBinding {
-                                      comment: None,
-                                      name: no_loc(Pattern::Ident(TypedIdent::new(intern(s)))),
-                                      typ: Type::hole(),
-                                      args: args.iter()
-                                          .map(|i| TypedIdent::new(intern(i)))
-                                          .collect(),
-                                      expr: e,
-                                  }],
-                             Box::new(b)))
-}
-
-pub fn id(s: &str) -> SpExpr {
-    no_loc(Expr::Ident(TypedIdent::new(intern(s))))
-}
-
-pub fn field(s: &str, typ: ArcType<String>) -> Field<String> {
-    Field {
-        name: intern(s),
-        typ: typ,
-    }
-}
-
-pub fn typ(s: &str) -> ArcType<String> {
-    assert!(s.len() != 0);
-    match s.parse() {
-        Ok(b) => Type::builtin(b),
-        Err(()) if s.starts_with(char::is_lowercase) => generic_ty(s),
-        Err(()) => Type::ident(intern(s)),
-    }
-}
-
-pub fn generic_ty(s: &str) -> ArcType<String> {
-    Type::generic(generic(s))
-}
-
-pub fn generic(s: &str) -> Generic<String> {
-    Generic {
-        kind: Kind::variable(0),
-        id: intern(s),
-    }
-}
-
-pub fn app(e: SpExpr, args: Vec<SpExpr>) -> SpExpr {
-    no_loc(Expr::App(Box::new(e), args))
-}
-
-pub fn if_else(p: SpExpr, if_true: SpExpr, if_false: SpExpr) -> SpExpr {
-    no_loc(Expr::IfElse(Box::new(p), Box::new(if_true), Box::new(if_false)))
-}
-
-pub fn case(e: SpExpr, alts: Vec<(Pattern<String>, SpExpr)>) -> SpExpr {
-    no_loc(Expr::Match(Box::new(e),
-                       alts.into_iter()
-                           .map(|(p, e)| {
-                               Alternative {
-                                   pattern: no_loc(p),
-                                   expr: e,
-                               }
-                           })
-                           .collect()))
-}
-
-pub fn lambda(name: &str, args: Vec<String>, body: SpExpr) -> SpExpr {
-    no_loc(Expr::Lambda(Lambda {
-        id: TypedIdent::new(intern(name)),
-        args: args.into_iter().map(|id| TypedIdent::new(id)).collect(),
-        body: Box::new(body),
-    }))
-}
-
-pub fn type_decl(name: String,
-                 args: Vec<Generic<String>>,
-                 typ: ArcType<String>,
-                 body: SpExpr)
-                 -> SpExpr {
-    type_decls(vec![TypeBinding {
-                        comment: None,
-                        name: name.clone(),
-                        alias: Alias::new(name, args, typ),
-                    }],
-               body)
-}
-
-pub fn type_decls(binds: Vec<TypeBinding<String>>, body: SpExpr) -> SpExpr {
-    no_loc(Expr::TypeBindings(binds, Box::new(body)))
-}
-
-pub fn record(fields: Vec<(String, Option<SpExpr>)>) -> SpExpr {
-    record_a(Vec::new(), fields)
-}
-
-pub fn record_a(types: Vec<(String, Option<ArcType<String>>)>,
-                fields: Vec<(String, Option<SpExpr>)>)
-                -> SpExpr {
-    no_loc(Expr::Record {
-        typ: Type::hole(),
-        types: types,
-        exprs: fields,
-    })
-}
-
-pub fn field_access(expr: SpExpr, field: &str) -> SpExpr {
-    no_loc(Expr::Projection(Box::new(expr), intern(field), Type::hole()))
-}
-
-pub fn array(fields: Vec<SpExpr>) -> SpExpr {
-    no_loc(Expr::Array(Array {
-        typ: Type::hole(),
-        exprs: fields,
-    }))
-}
diff --git a/parser/tests/types.rs b/parser/tests/types.rs
deleted file mode 100644
index fa466b71..00000000
--- a/parser/tests/types.rs
+++ /dev/null
@@ -1,26 +0,0 @@
-extern crate env_logger;
-
-extern crate gluon_base as base;
-extern crate gluon_parser as parser;
-
-use base::ast::Expr;
-use base::types::Type;
-use support::{parse, typ};
-
-mod support;
-
-#[test]
-fn function_type() {
-    let _ = env_logger::init();
-
-    let input = "let _ : Int -> Float -> String = 1 in 1";
-    let expr = parse(input).unwrap_or_else(|err| panic!("{}", err.1));
-    match expr.value {
-        Expr::LetBindings(ref bindings, _) => {
-            assert_eq!(bindings[0].typ,
-                       Type::function(vec![typ("Int")],
-                                      Type::function(vec![typ("Float")], typ("String"))));
-        }
-        _ => panic!("Expected let"),
-    }
-}
diff --git a/tests/pass/deep_clone_userdata.glu b/tests/pass/deep_clone_userdata.glu
index 08a94031..dd21a61c 100644
--- a/tests/pass/deep_clone_userdata.glu
+++ b/tests/pass/deep_clone_userdata.glu
@@ -4,14 +4,14 @@ let { (*>) } = prelude.make_Applicative writer.applicative
 
 
 let _ =
-    let { sender, receiver } = channel (lazy (\_ -> 0))
+    let { sender, receiver } = channel (lazy \_ -> 0)
 
-    let thread = spawn (\_ ->
-        send sender (lazy (\_ -> 1))
-        let l = lazy (\_ -> 2)
+    let thread = spawn \_ ->
+        send sender (lazy \_ -> 1)
+        let l = lazy \_ -> 2
         force l
         send sender l
-        ())
+        ()
     
     resume thread
 
@@ -26,9 +26,9 @@ let _ =
 let _ =
     let { sender, receiver } = channel (ref 0)
 
-    let thread = spawn (\_ ->
+    let thread = spawn \_ ->
         send sender (ref 3)
-        ())
+        ()
         
     resume thread
 
diff --git a/tests/pass/lazy.glu b/tests/pass/lazy.glu
index 55909102..5b7b94c3 100644
--- a/tests/pass/lazy.glu
+++ b/tests/pass/lazy.glu
@@ -6,6 +6,6 @@ let { (+), (-), (*) } = prelude.num_Int
 
 let l = lazy (\_ -> 123 + 57)
 
-assert_ieq (force (lazy (\_ -> 2))) 2
+assert_ieq (force (lazy \_ -> 2)) 2
     *> pure ()
     *> assert_ieq 180 (force l)
diff --git a/tests/vm.rs b/tests/vm.rs
index f2daecc1..4aff4983 100644
--- a/tests/vm.rs
+++ b/tests/vm.rs
@@ -368,7 +368,7 @@ in y
 
 test_expr!{ let_not_in_tail_position,
 r#"
-1 #Int+ (let x = 2 in x)
+1 #Int+ let x = 2 in x
 "#,
 3i32
 }