diff --git a/.gitignore b/.gitignore
index 6b61812fdf..f6fb025b5c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -46,6 +46,11 @@ libsass/*
 *.a
 a.out
 libsass.js
+tester
+tester.exe
+build/
+config.h.in*
+lib/pkgconfig/
 
 bin/*
 .deps/
diff --git a/Makefile b/Makefile
index d8e70d112c..9c24ab8da3 100644
--- a/Makefile
+++ b/Makefile
@@ -114,8 +114,8 @@ SOURCES = \
 	inspect.cpp \
 	node.cpp \
 	json.cpp \
-	output_compressed.cpp \
-	output_nested.cpp \
+	emitter.cpp \
+	output.cpp \
 	parser.cpp \
 	position.cpp \
 	prelexer.cpp \
diff --git a/Makefile.am b/Makefile.am
index 4c294924ce..9b8526e2ba 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -65,8 +65,8 @@ libsass_la_SOURCES = \
 	inspect.cpp inspect.hpp \
 	node.cpp node.hpp \
 	json.cpp json.hpp \
-	output_compressed.cpp output_compressed.hpp \
-	output_nested.cpp output_nested.hpp \
+	emitter.cpp emitter.hpp \
+	output.cpp output.hpp \
 	parser.cpp parser.hpp \
 	prelexer.cpp prelexer.hpp \
 	remove_placeholders.cpp remove_placeholders.hpp \
diff --git a/ast.cpp b/ast.cpp
index 0879e8a895..51801f8ba0 100644
--- a/ast.cpp
+++ b/ast.cpp
@@ -89,7 +89,7 @@ namespace Sass {
 
   Compound_Selector* Simple_Selector::unify_with(Compound_Selector* rhs, Context& ctx)
   {
-    To_String to_string;
+    To_String to_string(&ctx);
     for (size_t i = 0, L = rhs->length(); i < L; ++i)
     { if (perform(&to_string) == (*rhs)[i]->perform(&to_string)) return rhs; }
 
@@ -183,6 +183,7 @@ namespace Sass {
           return 0;
       }
     }
+    rhs->has_line_break(has_line_break());
     return Simple_Selector::unify_with(rhs, ctx);
   }
 
@@ -451,7 +452,7 @@ namespace Sass {
   {
     Complex_Selector* cpy = new (ctx.mem) Complex_Selector(*this);
 
-		if (head()) {
+    if (head()) {
     	cpy->head(head()->clone(ctx));
     }
 
@@ -470,10 +471,11 @@ namespace Sass {
 
 
 
+  /* not used anymore - remove?
   Selector_Placeholder* Selector::find_placeholder()
   {
     return 0;
-  }
+  }*/
 
   void Selector_List::adjust_after_pushing(Complex_Selector* c)
   {
@@ -486,6 +488,7 @@ namespace Sass {
 #endif
   }
 
+  /* not used anymore - remove?
   Selector_Placeholder* Selector_List::find_placeholder()
   {
     if (has_placeholder()) {
@@ -494,8 +497,9 @@ namespace Sass {
       }
     }
     return 0;
-  }
+  }*/
 
+  /* not used anymore - remove?
   Selector_Placeholder* Complex_Selector::find_placeholder()
   {
     if (has_placeholder()) {
@@ -503,8 +507,9 @@ namespace Sass {
       else if (tail() && tail()->has_placeholder()) return tail()->find_placeholder();
     }
     return 0;
-  }
+  }*/
 
+  /* not used anymore - remove?
   Selector_Placeholder* Compound_Selector::find_placeholder()
   {
     if (has_placeholder()) {
@@ -514,12 +519,13 @@ namespace Sass {
       // return this;
     }
     return 0;
-  }
+  }*/
 
+  /* not used anymore - remove?
   Selector_Placeholder* Selector_Placeholder::find_placeholder()
   {
     return this;
-  }
+  }*/
 
   vector<string> Compound_Selector::to_str_vec()
   {
@@ -533,7 +539,7 @@ namespace Sass {
 
   Compound_Selector* Compound_Selector::minus(Compound_Selector* rhs, Context& ctx)
   {
-    To_String to_string;
+    To_String to_string(&ctx);
     Compound_Selector* result = new (ctx.mem) Compound_Selector(pstate());
 
     // not very efficient because it needs to preserve order
@@ -562,6 +568,7 @@ namespace Sass {
     }
   }
 
+  /* not used anymore - remove?
   vector<Compound_Selector*> Complex_Selector::to_vector()
   {
     vector<Compound_Selector*> result;
@@ -575,7 +582,7 @@ namespace Sass {
       if (h) result.push_back(h);
     }
     return result;
-  }
+  }*/
 
 }
 
diff --git a/ast.hpp b/ast.hpp
index 7281b384a9..c69b32c16d 100644
--- a/ast.hpp
+++ b/ast.hpp
@@ -30,8 +30,10 @@
 
 #endif
 
+#include "util.hpp"
 #include "units.hpp"
-#include "token.hpp"
+#include "context.hpp"
+#include "position.hpp"
 #include "constants.hpp"
 #include "operation.hpp"
 #include "position.hpp"
@@ -40,7 +42,8 @@
 #include "environment.hpp"
 #include "error_handling.hpp"
 #include "ast_def_macros.hpp"
- #include "to_string.hpp"
+#include "ast_fwd_decl.hpp"
+#include "to_string.hpp"
 
 #include "sass.h"
 #include "sass_values.h"
@@ -52,14 +55,12 @@ namespace Sass {
   //////////////////////////////////////////////////////////
   // Abstract base class for all abstract syntax tree nodes.
   //////////////////////////////////////////////////////////
-  class Block;
-  class Statement;
-  class Expression;
-  class Selector;
   class AST_Node {
     ADD_PROPERTY(ParserState, pstate);
   public:
-    AST_Node(ParserState pstate) : pstate_(pstate) { }
+    AST_Node(ParserState pstate)
+    : pstate_(pstate)
+    { }
     virtual ~AST_Node() = 0;
     // virtual Block* block() { return 0; }
   public:
@@ -98,7 +99,10 @@ namespace Sass {
     Expression(ParserState pstate,
                bool d = false, bool e = false, bool i = false, Concrete_Type ct = NONE)
     : AST_Node(pstate),
-      is_delayed_(d), is_expanded_(d), is_interpolant_(i), concrete_type_(ct)
+      is_delayed_(d),
+      is_expanded_(d),
+      is_interpolant_(i),
+      concrete_type_(ct)
     { }
     virtual operator bool() { return true; }
     virtual ~Expression() { };
@@ -184,7 +188,7 @@ namespace Sass {
   inline Vectorized<T>::~Vectorized() { }
 
   /////////////////////////////////////////////////////////////////////////////
-  // Mixin class for AST nodes that should behave like ahash table. Uses an
+  // Mixin class for AST nodes that should behave like a hash table. Uses an
   // extra <vector> internally to maintain insertion order for interation.
   /////////////////////////////////////////////////////////////////////////////
   class Hashed {
@@ -316,7 +320,6 @@ namespace Sass {
   // Rulesets (i.e., sets of styles headed by a selector and containing a block
   // of style declarations.
   /////////////////////////////////////////////////////////////////////////////
-  class Selector;
   class Ruleset : public Has_Block {
     ADD_PROPERTY(Selector*, selector);
   public:
@@ -332,7 +335,6 @@ namespace Sass {
   /////////////////////////////////////////////////////////
   // Nested declaration sets (i.e., namespaced properties).
   /////////////////////////////////////////////////////////
-  class String;
   class Propset : public Has_Block {
     ADD_PROPERTY(String*, property_fragment);
   public:
@@ -359,7 +361,6 @@ namespace Sass {
   /////////////////
   // Media queries.
   /////////////////
-  class List;
   class Media_Block : public Has_Block {
     ADD_PROPERTY(List*, media_queries);
     ADD_PROPERTY(Selector*, selector);
@@ -448,8 +449,6 @@ namespace Sass {
   /////////////////////////////////////
   // Assignments -- variable and value.
   /////////////////////////////////////
-  class Variable;
-  class Expression;
   class Assignment : public Statement {
     ADD_PROPERTY(string, variable);
     ADD_PROPERTY(Expression*, value);
@@ -471,7 +470,7 @@ namespace Sass {
   ////////////////////////////////////////////////////////////////////////////
   class Import : public Statement {
     vector<string>         files_;
-    vector<Expression*> urls_;
+    vector<Expression*>    urls_;
   public:
     Import(ParserState pstate)
     : Statement(pstate),
@@ -532,9 +531,10 @@ namespace Sass {
   ///////////////////////////////////////////
   class Comment : public Statement {
     ADD_PROPERTY(String*, text);
+    ADD_PROPERTY(bool, is_important);
   public:
-    Comment(ParserState pstate, String* txt)
-    : Statement(pstate), text_(txt)
+    Comment(ParserState pstate, String* txt, bool is_important)
+    : Statement(pstate), text_(txt), is_important_(is_important)
     { }
     ATTACH_OPERATIONS();
   };
@@ -623,9 +623,7 @@ namespace Sass {
   // Definitions for both mixins and functions. The two cases are distinguished
   // by a type tag.
   /////////////////////////////////////////////////////////////////////////////
-  struct Context;
   struct Backtrace;
-  class Parameters;
   typedef Environment<AST_Node*> Env;
   typedef const char* Signature;
   typedef Expression* (*Native_Function)(Env&, Env&, Context&, Signature, ParserState, Backtrace*);
@@ -701,7 +699,6 @@ namespace Sass {
   //////////////////////////////////////
   // Mixin calls (i.e., `@include ...`).
   //////////////////////////////////////
-  class Arguments;
   class Mixin_Call : public Has_Block {
     ADD_PROPERTY(string, name);
     ADD_PROPERTY(Arguments*, arguments);
@@ -780,7 +777,6 @@ namespace Sass {
   ///////////////////////////////////////////////////////////////////////
   // Key value paris.
   ///////////////////////////////////////////////////////////////////////
-
   class Map : public Expression, public Hashed {
     void adjust_after_pushing(std::pair<Expression*, Expression*> p) { is_expanded(false); }
   public:
@@ -823,8 +819,6 @@ namespace Sass {
     ATTACH_OPERATIONS();
   };
 
-
-
   //////////////////////////////////////////////////////////////////////////
   // Binary expressions. Represents logical, relational, and arithmetic
   // operations. Templatized to avoid large switch statements and repetitive
@@ -1326,10 +1320,10 @@ namespace Sass {
   // "flat" strings.
   ////////////////////////////////////////////////////////////////////////
   class String : public Expression {
-    ADD_PROPERTY(bool, needs_unquoting);
+    ADD_PROPERTY(bool, sass_fix_1291);
   public:
-    String(ParserState pstate, bool unq = false, bool delayed = false)
-    : Expression(pstate, delayed), needs_unquoting_(unq)
+    String(ParserState pstate, bool delayed = false, bool sass_fix_1291 = false)
+    : Expression(pstate, delayed), sass_fix_1291_(sass_fix_1291)
     { concrete_type(STRING); }
     static string type_name() { return "string"; }
     virtual ~String() = 0;
@@ -1342,12 +1336,11 @@ namespace Sass {
   // evaluation phase.
   ///////////////////////////////////////////////////////////////////////
   class String_Schema : public String, public Vectorized<Expression*> {
-    ADD_PROPERTY(char, quote_mark);
     ADD_PROPERTY(bool, has_interpolants);
     size_t hash_;
   public:
-    String_Schema(ParserState pstate, size_t size = 0, bool unq = false, char qm = '\0', bool i = false)
-    : String(pstate, unq), Vectorized<Expression*>(size), quote_mark_(qm), has_interpolants_(i), hash_(0)
+    String_Schema(ParserState pstate, size_t size = 0, bool has_interpolants = false)
+    : String(pstate), Vectorized<Expression*>(size), has_interpolants_(has_interpolants), hash_(0)
     { }
     string type() { return "string"; }
     static string type_name() { return "string"; }
@@ -1386,22 +1379,23 @@ namespace Sass {
   // Flat strings -- the lowest level of raw textual data.
   ////////////////////////////////////////////////////////
   class String_Constant : public String {
+    ADD_PROPERTY(char, quote_mark);
     ADD_PROPERTY(string, value);
-    string unquoted_;
+  protected:
     size_t hash_;
   public:
-    String_Constant(ParserState pstate, string val, bool unq = false)
-    : String(pstate, unq, true), value_(val), hash_(0)
-    { unquoted_ = unquote(value_); }
-    String_Constant(ParserState pstate, const char* beg, bool unq = false)
-    : String(pstate, unq, true), value_(string(beg)), hash_(0)
-    { unquoted_ = unquote(value_); }
-    String_Constant(ParserState pstate, const char* beg, const char* end, bool unq = false)
-    : String(pstate, unq, true), value_(string(beg, end-beg)), hash_(0)
-    { unquoted_ = unquote(value_); }
-    String_Constant(ParserState pstate, const Token& tok, bool unq = false)
-    : String(pstate, unq, true), value_(string(tok.begin, tok.end)), hash_(0)
-    { unquoted_ = unquote(value_); }
+    String_Constant(ParserState pstate, string val)
+    : String(pstate), quote_mark_(0), value_(val), hash_(0)
+    { }
+    String_Constant(ParserState pstate, const char* beg)
+    : String(pstate), quote_mark_(0), value_(string(beg)), hash_(0)
+    { }
+    String_Constant(ParserState pstate, const char* beg, const char* end)
+    : String(pstate), quote_mark_(0), value_(string(beg, end-beg)), hash_(0)
+    { }
+    String_Constant(ParserState pstate, const Token& tok)
+    : String(pstate), quote_mark_(0), value_(string(tok.begin, tok.end)), hash_(0)
+    { }
     string type() { return "string"; }
     static string type_name() { return "string"; }
 
@@ -1410,7 +1404,7 @@ namespace Sass {
       try
       {
         String_Constant& e = dynamic_cast<String_Constant&>(rhs);
-        return e && unquoted_ == e.unquoted_;
+        return e && value_ == e.value_;
       }
       catch (std::bad_cast&)
       {
@@ -1421,15 +1415,27 @@ namespace Sass {
 
     virtual size_t hash()
     {
-      if (hash_ == 0) hash_ = std::hash<string>()(unquoted_);
+      if (hash_ == 0) hash_ = std::hash<string>()(value_);
       return hash_;
     }
 
-    static char single_quote() { return '\''; }
+    // static char auto_quote() { return '*'; }
     static char double_quote() { return '"'; }
+    static char single_quote() { return '\''; }
+
+    ATTACH_OPERATIONS();
+  };
 
-    bool is_quoted() { return value_.length() && (value_[0] == '"' || value_[0] == '\''); }
-    char quote_mark() { return is_quoted() ? value_[0] : '\0'; }
+  ////////////////////////////////////////////////////////
+  // Possibly quoted string (unquote on instantiation)
+  ////////////////////////////////////////////////////////
+  class String_Quoted : public String_Constant {
+  public:
+    String_Quoted(ParserState pstate, string val)
+    : String_Constant(pstate, val)
+    {
+      value_ = unquote(value_, &quote_mark_);
+    }
     ATTACH_OPERATIONS();
   };
 
@@ -1688,12 +1694,20 @@ namespace Sass {
   class Selector : public AST_Node {
     ADD_PROPERTY(bool, has_reference);
     ADD_PROPERTY(bool, has_placeholder);
+    // line break before list separator
+    ADD_PROPERTY(bool, has_line_feed);
+    // line break after list separator
+    ADD_PROPERTY(bool, has_line_break);
   public:
     Selector(ParserState pstate, bool r = false, bool h = false)
-    : AST_Node(pstate), has_reference_(r), has_placeholder_(h)
+    : AST_Node(pstate),
+      has_reference_(r),
+      has_placeholder_(h),
+      has_line_feed_(false),
+      has_line_break_(false)
     { }
     virtual ~Selector() = 0;
-    virtual Selector_Placeholder* find_placeholder();
+    // virtual Selector_Placeholder* find_placeholder();
     virtual int specificity() { return Constants::SPECIFICITY_BASE; }
   };
   inline Selector::~Selector() { }
@@ -1756,7 +1770,7 @@ namespace Sass {
     Selector_Placeholder(ParserState pstate, string n)
     : Simple_Selector(pstate), name_(n)
     { has_placeholder(true); }
-    virtual Selector_Placeholder* find_placeholder();
+    // virtual Selector_Placeholder* find_placeholder();
     ATTACH_OPERATIONS();
   };
 
@@ -1886,7 +1900,7 @@ namespace Sass {
     { }
 
     Compound_Selector* unify_with(Compound_Selector* rhs, Context& ctx);
-    virtual Selector_Placeholder* find_placeholder();
+    // virtual Selector_Placeholder* find_placeholder();
     Simple_Selector* base()
     {
       // Implement non-const in terms of const. Safe to const_cast since this method is non-const
@@ -1933,7 +1947,6 @@ namespace Sass {
   // CSS selector combinators (">", "+", "~", and whitespace). Essentially a
   // linked list.
   ////////////////////////////////////////////////////////////////////////////
-  struct Context;
   class Complex_Selector : public Selector {
   public:
     enum Combinator { ANCESTOR_OF, PARENT_OF, PRECEDES, ADJACENT_TO };
@@ -1957,7 +1970,7 @@ namespace Sass {
     size_t length();
     bool is_superselector_of(Compound_Selector*);
     bool is_superselector_of(Complex_Selector*);
-    virtual Selector_Placeholder* find_placeholder();
+    // virtual Selector_Placeholder* find_placeholder();
     Combinator clear_innermost();
     void set_innermost(Complex_Selector*, Combinator);
     virtual int specificity() const
@@ -2020,7 +2033,7 @@ namespace Sass {
     }
     Complex_Selector* clone(Context&) const;      // does not clone Compound_Selector*s
     Complex_Selector* cloneFully(Context&) const; // clones Compound_Selector*s
-    vector<Compound_Selector*> to_vector();
+    // vector<Compound_Selector*> to_vector();
     ATTACH_OPERATIONS();
   };
 
@@ -2029,18 +2042,18 @@ namespace Sass {
   ///////////////////////////////////
   // Comma-separated selector groups.
   ///////////////////////////////////
-  class Selector_List
-      : public Selector, public Vectorized<Complex_Selector*> {
+  class Selector_List : public Selector, public Vectorized<Complex_Selector*> {
 #ifdef DEBUG
     ADD_PROPERTY(string, mCachedSelector);
 #endif
+    ADD_PROPERTY(vector<string>, wspace);
   protected:
     void adjust_after_pushing(Complex_Selector* c);
   public:
     Selector_List(ParserState pstate, size_t s = 0)
-    : Selector(pstate), Vectorized<Complex_Selector*>(s)
+    : Selector(pstate), Vectorized<Complex_Selector*>(s), wspace_(0)
     { }
-    virtual Selector_Placeholder* find_placeholder();
+    // virtual Selector_Placeholder* find_placeholder();
     virtual int specificity()
     {
       int sum = 0;
diff --git a/ast_fwd_decl.hpp b/ast_fwd_decl.hpp
index 20ae667632..83b46d0fc0 100644
--- a/ast_fwd_decl.hpp
+++ b/ast_fwd_decl.hpp
@@ -6,6 +6,8 @@
 /////////////////////////////////////////////
 namespace Sass {
 
+  enum Output_Style { NESTED, EXPANDED, COMPACT, COMPRESSED, FORMATTED };
+
   class AST_Node;
   // statements
   class Statement;
@@ -51,6 +53,7 @@ namespace Sass {
   class String_Schema;
   class String;
   class String_Constant;
+  class String_Quoted;
   class Media_Query;
   class Media_Query_Expression;
   class Feature_Query;
diff --git a/bind.cpp b/bind.cpp
index aeba077d5e..d0cba9e719 100644
--- a/bind.cpp
+++ b/bind.cpp
@@ -145,7 +145,7 @@ namespace Sass {
     // That's only okay if they have default values, or were already bound by
     // named arguments, or if it's a single rest-param.
     for (size_t i = ip; i < LP; ++i) {
-      To_String to_string;
+      To_String to_string(&ctx);
       Parameter* leftover = (*ps)[i];
       // cerr << "env for default params:" << endl;
       // env->print();
diff --git a/context.cpp b/context.cpp
index 664898f9fb..00d978b5c1 100644
--- a/context.cpp
+++ b/context.cpp
@@ -10,8 +10,7 @@
 #include "parser.hpp"
 #include "file.hpp"
 #include "inspect.hpp"
-#include "output_nested.hpp"
-#include "output_compressed.hpp"
+#include "output.hpp"
 #include "expand.hpp"
 #include "eval.hpp"
 #include "contextualize.hpp"
@@ -24,11 +23,14 @@
 #include "backtrace.hpp"
 #include "sass2scss.h"
 #include "prelexer.hpp"
+#include "emitter.hpp"
 
-#include <iomanip>
-#include <iostream>
+#include <string>
+#include <cstdlib>
 #include <cstring>
+#include <iomanip>
 #include <sstream>
+#include <iostream>
 
 namespace Sass {
   using namespace Constants;
@@ -45,13 +47,14 @@ namespace Sass {
 
 
   Context::Context(Context::Data initializers)
-  : mem(Memory_Manager<AST_Node>()),
+  : // Output(this),
+    mem(Memory_Manager<AST_Node>()),
     source_c_str            (initializers.source_c_str()),
     sources                 (vector<const char*>()),
     include_paths           (initializers.include_paths()),
     queue                   (vector<Sass_Queued>()),
     style_sheets            (map<string, Block*>()),
-    source_map              (resolve_relative_path(initializers.output_path(), initializers.source_map_file(), get_cwd())),
+    emitter (this),
     c_functions             (vector<Sass_C_Function_Callback>()),
     indent                  (initializers.indent()),
     linefeed                (initializers.linefeed()),
@@ -68,7 +71,6 @@ namespace Sass {
     names_to_colors         (map<string, Color*>()),
     colors_to_names         (map<int, string>()),
     precision               (initializers.precision()),
-    _skip_source_map_update (initializers._skip_source_map_update()),
     subset_map              (Subset_Map<string, pair<Complex_Selector*, Compound_Selector*> >())
   {
     cwd = get_cwd();
@@ -91,6 +93,9 @@ namespace Sass {
         throw "File to read not found or unreadable: " + entry_point;
       }
     }
+
+    emitter.set_filename(output_path);
+
   }
 
   Context::~Context()
@@ -163,7 +168,7 @@ namespace Sass {
     sources.push_back(contents);
     included_files.push_back(abs_path);
     queue.push_back(Sass_Queued(load_path, abs_path, contents));
-    source_map.source_index.push_back(sources.size() - 1);
+    emitter.add_source_index(sources.size() - 1);
     include_links.push_back(resolve_relative_path(abs_path, source_map_file, cwd));
   }
 
@@ -222,31 +227,14 @@ namespace Sass {
 
   char* Context::compile_block(Block* root)
   {
-    char* result = 0;
     if (!root) return 0;
-    switch (output_style) {
-      case COMPRESSED: {
-        Output_Compressed output_compressed(this);
-        root->perform(&output_compressed);
-        string output = output_compressed.get_buffer();
-        if (source_map_file != "" && !omit_source_map_url) {
-          output += format_source_mapping_url(source_map_file);
-        }
-        result = copy_c_str(output.c_str());
-      } break;
-
-      default: {
-        Output_Nested output_nested(source_comments, this);
-        root->perform(&output_nested);
-        string output = output_nested.get_buffer();
-        if (source_map_file != "" && !omit_source_map_url) {
-          output += linefeed + format_source_mapping_url(source_map_file);
-        }
-        result = copy_c_str(output.c_str());
-
-      } break;
+    root->perform(&emitter);
+    emitter.finalize();
+    string output = emitter.get_buffer();
+    if (source_map_file != "" && !omit_source_map_url) {
+      output += linefeed + format_source_mapping_url(source_map_file);
     }
-    return result;
+    return copy_c_str(output.c_str());
   }
 
   Block* Context::parse_file()
@@ -277,9 +265,6 @@ namespace Sass {
     Contextualize contextualize(*this, &eval, &tge, &backtrace);
     Expand expand(*this, &eval, &contextualize, &tge, &backtrace);
     Cssize cssize(*this, &tge, &backtrace);
-    // Inspect inspect(this);
-    // Output_Nested output_nested(*this);
-
     root = root->perform(&expand)->block();
     root = root->perform(&cssize)->block();
     if (!subset_map.empty()) {
@@ -322,7 +307,7 @@ namespace Sass {
   {
     string url = resolve_relative_path(file, output_path, cwd);
     if (source_map_embed) {
-      string map = source_map.generate_source_map(*this);
+      string map = emitter.generate_source_map(*this);
       istringstream is( map );
       ostringstream buffer;
       base64::encoder E;
@@ -337,7 +322,7 @@ namespace Sass {
   {
     if (source_map_file == "") return 0;
     char* result = 0;
-    string map = source_map.generate_source_map(*this);
+    string map = emitter.generate_source_map(*this);
     result = copy_c_str(map.c_str());
     return result;
   }
diff --git a/context.hpp b/context.hpp
index 8ff8427cb5..98ee5c7cee 100644
--- a/context.hpp
+++ b/context.hpp
@@ -8,29 +8,19 @@
 #define BUFFERSIZE 255
 #include "b64/encode.h"
 
+#include "ast_fwd_decl.hpp"
 #include "kwd_arg_macros.hpp"
 #include "memory_manager.hpp"
 #include "environment.hpp"
 #include "source_map.hpp"
 #include "subset_map.hpp"
+#include "output.hpp"
 #include "sass_functions.h"
 
 struct Sass_C_Function_Descriptor;
 
 namespace Sass {
   using namespace std;
-  class AST_Node;
-  class Block;
-  class Expression;
-  class Color;
-  struct Backtrace;
-  // typedef const char* Signature;
-  // struct Context;
-  // typedef Environment<AST_Node*> Env;
-  // typedef Expression* (*Native_Function)(Env&, Context&, Signature, string, size_t);
-
-  enum Output_Style { NESTED, EXPANDED, COMPACT, COMPRESSED, FORMATTED };
-
   struct Sass_Queued {
     string abs_path;
     string load_path;
@@ -39,7 +29,8 @@ namespace Sass {
     Sass_Queued(const string& load_path, const string& abs_path, const char* source);
   };
 
-  struct Context {
+  class Context {
+  public:
     Memory_Manager<AST_Node> mem;
 
     const char* source_c_str;
@@ -56,7 +47,8 @@ namespace Sass {
     vector<string> include_paths; // lookup paths for includes
     vector<Sass_Queued> queue; // queue of files to be parsed
     map<string, Block*> style_sheets; // map of paths to ASTs
-    SourceMap source_map;
+    // SourceMap source_map;
+    Output emitter;
     vector<Sass_C_Function_Callback> c_functions;
 
     string       indent; // String to be used for indentation
@@ -79,7 +71,6 @@ namespace Sass {
     map<int, string>    colors_to_names;
 
     size_t precision; // precision for outputting fractional numbers
-    bool _skip_source_map_update; // status flag to skip source map updates
 
     KWD_ARG_SET(Data) {
       KWD_ARG(Data, const char*,     source_c_str);
@@ -97,7 +88,6 @@ namespace Sass {
       KWD_ARG(Data, bool,            omit_source_map_url);
       KWD_ARG(Data, bool,            is_indented_syntax_src);
       KWD_ARG(Data, size_t,          precision);
-      KWD_ARG(Data, bool,            _skip_source_map_update);
       KWD_ARG(Data, bool,            source_map_embed);
       KWD_ARG(Data, bool,            source_map_contents);
       KWD_ARG(Data, Sass_C_Import_Callback, importer);
diff --git a/contextualize.cpp b/contextualize.cpp
index 9a762b1e3e..9e7d8a4985 100644
--- a/contextualize.cpp
+++ b/contextualize.cpp
@@ -28,7 +28,7 @@ namespace Sass {
 
   Selector* Contextualize::operator()(Selector_Schema* s)
   {
-    To_String to_string;
+    To_String to_string(&ctx);
     string result_str(s->contents()->perform(eval->with(env, backtrace))->perform(&to_string));
     result_str += '{'; // the parser looks for a brace to end the selector
     Selector* result_sel = Parser::from_c_str(result_str.c_str(), ctx, s->pstate()).parse_selector_group();
@@ -45,6 +45,7 @@ namespace Sass {
         for (size_t j = 0, L = s->length(); j < L; ++j) {
           parent = (*p)[i];
           Complex_Selector* comb = static_cast<Complex_Selector*>((*s)[j]->perform(this));
+          if (parent->has_line_feed()) comb->has_line_feed(true);
           if (comb) *ss << comb;
         }
       }
@@ -61,7 +62,7 @@ namespace Sass {
 
   Selector* Contextualize::operator()(Complex_Selector* s)
   {
-    To_String to_string;
+    To_String to_string(&ctx);
     Complex_Selector* ss = new (ctx.mem) Complex_Selector(*s);
     Compound_Selector* new_head = 0;
     Complex_Selector* new_tail = 0;
@@ -89,11 +90,12 @@ namespace Sass {
 
   Selector* Contextualize::operator()(Compound_Selector* s)
   {
-    To_String to_string;
+    To_String to_string(&ctx);
     if (placeholder && extender && s->perform(&to_string) == placeholder->perform(&to_string)) {
       return extender;
     }
     Compound_Selector* ss = new (ctx.mem) Compound_Selector(s->pstate(), s->length());
+    ss->has_line_break(s->has_line_break());
     for (size_t i = 0, L = s->length(); i < L; ++i) {
       Simple_Selector* simp = static_cast<Simple_Selector*>((*s)[i]->perform(this));
       if (simp) *ss << simp;
@@ -135,7 +137,7 @@ namespace Sass {
 
   Selector* Contextualize::operator()(Selector_Placeholder* p)
   {
-    To_String to_string;
+    To_String to_string(&ctx);
     if (placeholder && extender && p->perform(&to_string) == placeholder->perform(&to_string)) {
       return extender;
     }
diff --git a/contextualize.hpp b/contextualize.hpp
index 2a814d06e7..49d27e6da6 100644
--- a/contextualize.hpp
+++ b/contextualize.hpp
@@ -1,26 +1,13 @@
 #ifndef SASS_CONTEXTUALIZE_H
 #define SASS_CONTEXTUALIZE_H
 
+#include "eval.hpp"
+#include "context.hpp"
 #include "operation.hpp"
 #include "environment.hpp"
+#include "ast_fwd_decl.hpp"
 
 namespace Sass {
-  class AST_Node;
-  class Selector;
-  class Selector_Schema;
-  class Selector_List;
-  class Complex_Selector;
-  class Compound_Selector;
-  class Wrapped_Selector;
-  class Pseudo_Selector;
-  class Attribute_Selector;
-  class Selector_Qualifier;
-  class Type_Selector;
-  class Selector_Placeholder;
-  class Selector_Reference;
-  class Simple_Selector;
-  struct Context;
-  class Eval;
   struct Backtrace;
 
   typedef Environment<AST_Node*> Env;
diff --git a/cssize.cpp b/cssize.cpp
index fd8c437507..444811d718 100644
--- a/cssize.cpp
+++ b/cssize.cpp
@@ -27,6 +27,7 @@ namespace Sass {
     new_env.link(*env);
     env = &new_env;
     Block* bb = new (ctx.mem) Block(b->pstate(), b->length(), b->is_root());
+    // bb->tabs(b->tabs());
     block_stack.push_back(bb);
     append_block(b);
     block_stack.pop_back();
@@ -97,6 +98,7 @@ namespace Sass {
     Ruleset* rr = new (ctx.mem) Ruleset(r->pstate(),
                                         r->selector(),
                                         r->block()->perform(this)->block());
+    // rr->tabs(r->block()->tabs());
     p_stack.pop_back();
 
     Block* props = new Block(rr->block()->pstate());
@@ -191,6 +193,7 @@ namespace Sass {
     {
       Block* bb = m->block()->perform(this)->block();
       for (size_t i = 0, L = bb->length(); i < L; ++i) {
+        // (bb->elements())[i]->tabs(m->tabs());
         if (bubblable((*bb)[i])) (*bb)[i]->tabs((*bb)[i]->tabs() + m->tabs());
       }
       if (bb->length() && bubblable(bb->last())) bb->last()->group_end(m->group_end());
@@ -295,6 +298,8 @@ namespace Sass {
                                                 wrapper_block,
                                                 m->selector());
 
+    mm->tabs(m->tabs());
+
     Bubble* bubble = new (ctx.mem) Bubble(mm->pstate(), mm);
 
     return bubble;
@@ -496,7 +501,7 @@ namespace Sass {
 
   Media_Query* Cssize::merge_media_query(Media_Query* mq1, Media_Query* mq2)
   {
-    To_String to_string;
+    To_String to_string(&ctx);
 
     string type;
     string mod;
diff --git a/cssize.hpp b/cssize.hpp
index c505680299..1389965393 100644
--- a/cssize.hpp
+++ b/cssize.hpp
@@ -5,13 +5,13 @@
 #include <iostream>
 
 #include "ast.hpp"
+#include "context.hpp"
 #include "operation.hpp"
 #include "environment.hpp"
 
 namespace Sass {
   using namespace std;
 
-  struct Context;
   typedef Environment<AST_Node*> Env;
   struct Backtrace;
 
diff --git a/debugger.hpp b/debugger.hpp
new file mode 100644
index 0000000000..a2648d4e73
--- /dev/null
+++ b/debugger.hpp
@@ -0,0 +1,298 @@
+#ifndef SASS_DEBUGGER_H
+#define SASS_DEBUGGER_H
+
+#include "ast_fwd_decl.hpp"
+
+using namespace std;
+using namespace Sass;
+
+inline string str_replace(std::string str, const std::string& oldStr, const std::string& newStr)
+{
+  size_t pos = 0;
+  while((pos = str.find(oldStr, pos)) != std::string::npos)
+  {
+     str.replace(pos, oldStr.length(), newStr);
+     pos += newStr.length();
+  }
+  return str;
+}
+
+inline string prettyprint(const string& str) {
+  string clean = str_replace(str, "\n", "\\n");
+  clean = str_replace(clean, "	", "\\t");
+  clean = str_replace(clean, "\r", "\\r");
+  return clean;
+}
+
+inline void debug_ast(AST_Node* node, string ind = "", Env* env = 0)
+{
+
+  if (ind == "") cerr << "####################################################################\n";
+  if (dynamic_cast<Bubble*>(node)) {
+    Bubble* bubble = dynamic_cast<Bubble*>(node);
+    cerr << ind << "Bubble " << bubble << " " << bubble->tabs() << endl;
+  } else if (dynamic_cast<At_Root_Block*>(node)) {
+    At_Root_Block* root_block = dynamic_cast<At_Root_Block*>(node);
+    cerr << ind << "At_Root_Block " << root_block << " " << root_block->tabs() << endl;
+    if (root_block->block()) for(auto i : root_block->block()->elements()) { debug_ast(i, ind + " ", env); }
+  } else if (dynamic_cast<Selector_List*>(node)) {
+    Selector_List* selector = dynamic_cast<Selector_List*>(node);
+    cerr << ind << "Selector_List " << selector << (selector->has_line_break() ? " [line-break]": " -") << (selector->has_line_feed() ? " [line-feed]": " -") << endl;
+    for(auto i : selector->elements()) { debug_ast(i, ind + " ", env); }
+
+//  } else if (dynamic_cast<Expression*>(node)) {
+//    Expression* expression = dynamic_cast<Expression*>(node);
+//    cerr << ind << "Expression " << expression << " " << expression->concrete_type() << endl;
+
+  } else if (dynamic_cast<Complex_Selector*>(node)) {
+    Complex_Selector* selector = dynamic_cast<Complex_Selector*>(node);
+    cerr << ind << "Complex_Selector " << selector << (selector->has_line_break() ? " [line-break]": " -") << (selector->has_line_feed() ? " [line-feed]": " -") << " -> ";
+      switch (selector->combinator()) {
+        case Complex_Selector::PARENT_OF:   cerr << "{>}"; break;
+        case Complex_Selector::PRECEDES:    cerr << "{~}"; break;
+        case Complex_Selector::ADJACENT_TO: cerr << "{+}"; break;
+        case Complex_Selector::ANCESTOR_OF: cerr << "{ }"; break;
+      }
+    cerr << " <" << prettyprint(selector->pstate().token.ws_before()) << "> X <" << prettyprint(selector->pstate().token.ws_after()) << ">" << endl;
+    debug_ast(selector->head(), ind + " ", env);
+    debug_ast(selector->tail(), ind + "-", env);
+  } else if (dynamic_cast<Compound_Selector*>(node)) {
+    Compound_Selector* selector = dynamic_cast<Compound_Selector*>(node);
+    cerr << ind << "Compound_Selector " << selector << (selector->has_line_break() ? " [line-break]": " -") << (selector->has_line_feed() ? " [line-feed]": " -") <<
+      " <" << prettyprint(selector->pstate().token.ws_before()) << "> X <" << prettyprint(selector->pstate().token.ws_after()) << ">" << endl;
+    for(auto i : selector->elements()) { debug_ast(i, ind + " ", env); }
+  } else if (dynamic_cast<Propset*>(node)) {
+    Propset* selector = dynamic_cast<Propset*>(node);
+    cerr << ind << "Propset " << selector << " " << selector->tabs() << endl;
+    if (selector->block()) for(auto i : selector->block()->elements()) { debug_ast(i, ind + " ", env); }
+  } else if (dynamic_cast<Wrapped_Selector*>(node)) {
+    Wrapped_Selector* selector = dynamic_cast<Wrapped_Selector*>(node);
+    cerr << ind << "Wrapped_Selector " << selector << " <<" << selector->name() << ">>" << (selector->has_line_break() ? " [line-break]": " -") << (selector->has_line_feed() ? " [line-feed]": " -") << endl;
+    debug_ast(selector->selector(), ind + " () ", env);
+  } else if (dynamic_cast<Pseudo_Selector*>(node)) {
+    Pseudo_Selector* selector = dynamic_cast<Pseudo_Selector*>(node);
+    cerr << ind << "Pseudo_Selector " << selector << " <<" << selector->name() << ">>" << (selector->has_line_break() ? " [line-break]": " -") << (selector->has_line_feed() ? " [line-feed]": " -") << endl;
+    debug_ast(selector->expression(), ind + " <= ", env);
+  } else if (dynamic_cast<Attribute_Selector*>(node)) {
+    Attribute_Selector* selector = dynamic_cast<Attribute_Selector*>(node);
+    cerr << ind << "Attribute_Selector " << selector << " <<" << selector->name() << ">>" << (selector->has_line_break() ? " [line-break]": " -") << (selector->has_line_feed() ? " [line-feed]": " -") << endl;
+    debug_ast(selector->value(), ind + "[" + selector->matcher() + "] ", env);
+  } else if (dynamic_cast<Selector_Qualifier*>(node)) {
+    Selector_Qualifier* selector = dynamic_cast<Selector_Qualifier*>(node);
+    cerr << ind << "Selector_Qualifier " << selector << " <<" << selector->name() << ">>" << (selector->has_line_break() ? " [line-break]": " -") << (selector->has_line_feed() ? " [line-feed]": " -") << endl;
+  } else if (dynamic_cast<Type_Selector*>(node)) {
+    Type_Selector* selector = dynamic_cast<Type_Selector*>(node);
+    cerr << ind << "Type_Selector " << selector << " <<" << selector->name() << ">>" << (selector->has_line_break() ? " [line-break]": " -") <<
+      " <" << prettyprint(selector->pstate().token.ws_before()) << "> X <" << prettyprint(selector->pstate().token.ws_after()) << ">" << endl;
+  } else if (dynamic_cast<Selector_Placeholder*>(node)) {
+    Selector_Placeholder* selector = dynamic_cast<Selector_Placeholder*>(node);
+    cerr << ind << "Selector_Placeholder " << selector << (selector->has_line_break() ? " [line-break]": " -") << (selector->has_line_feed() ? " [line-feed]": " -") << endl;
+  } else if (dynamic_cast<Selector_Reference*>(node)) {
+    Selector_Reference* selector = dynamic_cast<Selector_Reference*>(node);
+    cerr << ind << "Selector_Reference " << selector << " @ref " << selector->selector() << endl;
+  } else if (dynamic_cast<Simple_Selector*>(node)) {
+    Simple_Selector* selector = dynamic_cast<Simple_Selector*>(node);
+    cerr << ind << "Simple_Selector " << selector << (selector->has_line_break() ? " [line-break]": " -") << (selector->has_line_feed() ? " [line-feed]": " -") << endl;
+
+  } else if (dynamic_cast<Selector_Schema*>(node)) {
+    Selector_Schema* selector = dynamic_cast<Selector_Schema*>(node);
+    cerr << ind << "Selector_Schema " << selector << (selector->has_line_break() ? " [line-break]": " -") << (selector->has_line_feed() ? " [line-feed]": " -") << endl;
+    debug_ast(selector->contents(), ind + " ");
+    // for(auto i : selector->elements()) { debug_ast(i, ind + " ", env); }
+
+  } else if (dynamic_cast<Selector*>(node)) {
+    Selector* selector = dynamic_cast<Selector*>(node);
+    cerr << ind << "Selector " << selector << (selector->has_line_break() ? " [line-break]": " -") << (selector->has_line_feed() ? " [line-feed]": " -") << endl;
+  } else if (dynamic_cast<Media_Block*>(node)) {
+    Media_Block* block = dynamic_cast<Media_Block*>(node);
+    cerr << ind << "Media_Block " << block << " " << block->tabs() << endl;
+    if (block->block()) for(auto i : block->block()->elements()) { debug_ast(i, ind + " ", env); }
+  } else if (dynamic_cast<Feature_Block*>(node)) {
+    Feature_Block* block = dynamic_cast<Feature_Block*>(node);
+    cerr << ind << "Feature_Block " << block << " " << block->tabs() << endl;
+    if (block->block()) for(auto i : block->block()->elements()) { debug_ast(i, ind + " ", env); }
+  } else if (dynamic_cast<Block*>(node)) {
+    Block* root_block = dynamic_cast<Block*>(node);
+    cerr << ind << "Block " << root_block << " " << root_block->tabs() << endl;
+    if (root_block->block()) for(auto i : root_block->block()->elements()) { debug_ast(i, ind + " ", env); }
+  } else if (dynamic_cast<Warning*>(node)) {
+    Warning* block = dynamic_cast<Warning*>(node);
+    cerr << ind << "Warning " << block << " " << block->tabs() << endl;
+  } else if (dynamic_cast<Error*>(node)) {
+    Error* block = dynamic_cast<Error*>(node);
+    cerr << ind << "Error " << block << " " << block->tabs() << endl;
+  } else if (dynamic_cast<Debug*>(node)) {
+    Debug* block = dynamic_cast<Debug*>(node);
+    cerr << ind << "Debug " << block << " " << block->tabs() << endl;
+  } else if (dynamic_cast<Comment*>(node)) {
+    Comment* block = dynamic_cast<Comment*>(node);
+    cerr << ind << "Comment " << block << " " << block->tabs() <<
+      " <" << prettyprint(block->pstate().token.ws_before()) << "> X <" << prettyprint(block->pstate().token.ws_after()) << ">" << endl;
+    debug_ast(block->text(), ind + "// ", env);
+  } else if (dynamic_cast<If*>(node)) {
+    If* block = dynamic_cast<If*>(node);
+    cerr << ind << "If " << block << " " << block->tabs() << endl;
+  } else if (dynamic_cast<Return*>(node)) {
+    Return* block = dynamic_cast<Return*>(node);
+    cerr << ind << "Return " << block << " " << block->tabs() << endl;
+  } else if (dynamic_cast<Extension*>(node)) {
+    Extension* block = dynamic_cast<Extension*>(node);
+    cerr << ind << "Extension " << block << " " << block->tabs() << endl;
+    debug_ast(block->selector(), ind + "-> ", env);
+  } else if (dynamic_cast<Content*>(node)) {
+    Content* block = dynamic_cast<Content*>(node);
+    cerr << ind << "Content " << block << " " << block->tabs() << endl;
+  } else if (dynamic_cast<Import_Stub*>(node)) {
+    Import_Stub* block = dynamic_cast<Import_Stub*>(node);
+    cerr << ind << "Import_Stub " << block << " " << block->tabs() << endl;
+  } else if (dynamic_cast<Import*>(node)) {
+    Import* block = dynamic_cast<Import*>(node);
+    cerr << ind << "Import " << block << " " << block->tabs() << endl;
+    // vector<string>         files_;
+    for (auto imp : block->urls()) debug_ast(imp, "@ ", env);
+  } else if (dynamic_cast<Assignment*>(node)) {
+    Assignment* block = dynamic_cast<Assignment*>(node);
+    cerr << ind << "Assignment " << block << " <<" << block->variable() << ">> " << block->tabs() << endl;
+    debug_ast(block->value(), ind + "=", env);
+  } else if (dynamic_cast<Declaration*>(node)) {
+    Declaration* block = dynamic_cast<Declaration*>(node);
+    cerr << ind << "Declaration " << block << " " << block->tabs() << endl;
+    debug_ast(block->property(), ind + " prop: ", env);
+    debug_ast(block->value(), ind + " value: ", env);
+  } else if (dynamic_cast<At_Rule*>(node)) {
+    At_Rule* block = dynamic_cast<At_Rule*>(node);
+    cerr << ind << "At_Rule " << block << " " << block->tabs() << endl;
+    debug_ast(block->value(), ind + "+", env);
+    debug_ast(block->selector(), ind + "~", env);
+    if (block->block()) for(auto i : block->block()->elements()) { debug_ast(i, ind + " ", env); }
+  } else if (dynamic_cast<Each*>(node)) {
+    Each* block = dynamic_cast<Each*>(node);
+    cerr << ind << "Each " << block << " " << block->tabs() << endl;
+    if (block->block()) for(auto i : block->block()->elements()) { debug_ast(i, ind + " ", env); }
+  } else if (dynamic_cast<For*>(node)) {
+    For* block = dynamic_cast<For*>(node);
+    cerr << ind << "For " << block << " " << block->tabs() << endl;
+    if (block->block()) for(auto i : block->block()->elements()) { debug_ast(i, ind + " ", env); }
+  } else if (dynamic_cast<While*>(node)) {
+    While* block = dynamic_cast<While*>(node);
+    cerr << ind << "While " << block << " " << block->tabs() << endl;
+    if (block->block()) for(auto i : block->block()->elements()) { debug_ast(i, ind + " ", env); }
+  } else if (dynamic_cast<Definition*>(node)) {
+    Definition* block = dynamic_cast<Definition*>(node);
+    cerr << ind << "Definition " << block << " " << block->tabs() << endl;
+    if (block->block()) for(auto i : block->block()->elements()) { debug_ast(i, ind + " ", env); }
+  } else if (dynamic_cast<Mixin_Call*>(node)) {
+    Mixin_Call* block = dynamic_cast<Mixin_Call*>(node);
+    cerr << ind << "Mixin_Call " << block << " " << block->tabs() << endl;
+    if (block->block()) for(auto i : block->block()->elements()) { debug_ast(i, ind + " ", env); }
+  } else if (dynamic_cast<Ruleset*>(node)) {
+    Ruleset* ruleset = dynamic_cast<Ruleset*>(node);
+    cerr << ind << "Ruleset " << ruleset << " " << ruleset->tabs() << endl;
+    debug_ast(ruleset->selector(), ind + " ");
+    if (ruleset->block()) for(auto i : ruleset->block()->elements()) { debug_ast(i, ind + " ", env); }
+  } else if (dynamic_cast<Block*>(node)) {
+    Block* block = dynamic_cast<Block*>(node);
+    cerr << ind << "Block " << block << " " << block->tabs() << endl;
+    for(auto i : block->elements()) { debug_ast(i, ind + " ", env); }
+  } else if (dynamic_cast<Textual*>(node)) {
+    Textual* expression = dynamic_cast<Textual*>(node);
+    cerr << ind << "Textual ";
+    if (expression->type() == Textual::NUMBER) cerr << " [NUMBER]";
+    else if (expression->type() == Textual::PERCENTAGE) cerr << " [PERCENTAGE]";
+    else if (expression->type() == Textual::DIMENSION) cerr << " [DIMENSION]";
+    else if (expression->type() == Textual::HEX) cerr << " [HEX]";
+    cerr << expression << " [" << expression->value() << "]" << endl;
+  } else if (dynamic_cast<Variable*>(node)) {
+    Variable* expression = dynamic_cast<Variable*>(node);
+    cerr << ind << "Variable " << expression << " [" << expression->name() << "]" << endl;
+    string name(expression->name());
+    if (env && env->has(name)) debug_ast(static_cast<Expression*>((*env)[name]), ind + " -> ", env);
+  } else if (dynamic_cast<Function_Call_Schema*>(node)) {
+    Function_Call_Schema* expression = dynamic_cast<Function_Call_Schema*>(node);
+    cerr << ind << "Function_Call_Schema " << expression << "]" << endl;
+    debug_ast(expression->name(), ind + "name: ", env);
+    debug_ast(expression->arguments(), ind + " args: ", env);
+  } else if (dynamic_cast<Function_Call*>(node)) {
+    Function_Call* expression = dynamic_cast<Function_Call*>(node);
+    cerr << ind << "Function_Call " << expression << " [" << expression->name() << "]" << endl;
+    debug_ast(expression->arguments(), ind + " args: ", env);
+  } else if (dynamic_cast<Arguments*>(node)) {
+    Arguments* expression = dynamic_cast<Arguments*>(node);
+    cerr << ind << "Arguments " << expression << "]" << endl;
+    for(auto i : expression->elements()) { debug_ast(i, ind + " ", env); }
+  } else if (dynamic_cast<Argument*>(node)) {
+    Argument* expression = dynamic_cast<Argument*>(node);
+    cerr << ind << "Argument " << expression << " [" << expression->value() << "]" << endl;
+    debug_ast(expression->value(), ind + " value: ", env);
+  } else if (dynamic_cast<Unary_Expression*>(node)) {
+    Unary_Expression* expression = dynamic_cast<Unary_Expression*>(node);
+    cerr << ind << "Unary_Expression " << expression << " [" << expression->type() << "]" << endl;
+    debug_ast(expression->operand(), ind + " operand: ", env);
+  } else if (dynamic_cast<Binary_Expression*>(node)) {
+    Binary_Expression* expression = dynamic_cast<Binary_Expression*>(node);
+    cerr << ind << "Binary_Expression " << expression << " [" << expression->type() << "]" << endl;
+    debug_ast(expression->left(), ind + " left:  ", env);
+    debug_ast(expression->right(), ind + " right: ", env);
+  } else if (dynamic_cast<Map*>(node)) {
+    Map* expression = dynamic_cast<Map*>(node);
+    cerr << ind << "Map " << expression << " [Hashed]" << endl;
+  } else if (dynamic_cast<List*>(node)) {
+    List* expression = dynamic_cast<List*>(node);
+    cerr << ind << "List " << expression <<
+      (expression->separator() == Sass::List::Separator::COMMA ? "Comma " : "Space ") <<
+      " [delayed: " << expression->is_delayed() << "] " <<
+      " [interpolant: " << expression->is_interpolant() << "] " <<
+      endl;
+    for(auto i : expression->elements()) { debug_ast(i, ind + " ", env); }
+  } else if (dynamic_cast<Content*>(node)) {
+    Content* expression = dynamic_cast<Content*>(node);
+    cerr << ind << "Content " << expression << " [Statement]" << endl;
+  } else if (dynamic_cast<Boolean*>(node)) {
+    Boolean* expression = dynamic_cast<Boolean*>(node);
+    cerr << ind << "Boolean " << expression << " [" << expression->value() << "]" << endl;
+  } else if (dynamic_cast<Color*>(node)) {
+    Color* expression = dynamic_cast<Color*>(node);
+    cerr << ind << "Color " << expression << " [" << expression->r() << ":"  << expression->g() << ":" << expression->b() << "@" << expression->a() << "]" << endl;
+  } else if (dynamic_cast<Number*>(node)) {
+    Number* expression = dynamic_cast<Number*>(node);
+    cerr << ind << "Number " << expression << " [" << expression->value() << expression->unit() << "]" << endl;
+  } else if (dynamic_cast<String_Quoted*>(node)) {
+    String_Quoted* expression = dynamic_cast<String_Quoted*>(node);
+    cerr << ind << "String_Quoted : " << expression << " [" << prettyprint(expression->value()) << "]" <<
+      (expression->is_delayed() ? " {delayed}" : "") <<
+      (expression->sass_fix_1291() ? " {sass_fix_1291}" : "") <<
+      (expression->quote_mark() != 0 ? " {qm:" + string(1, expression->quote_mark()) + "}" : "") <<
+      " <" << prettyprint(expression->pstate().token.ws_before()) << "> X <" << prettyprint(expression->pstate().token.ws_after()) << ">" << endl;
+  } else if (dynamic_cast<String_Constant*>(node)) {
+    String_Constant* expression = dynamic_cast<String_Constant*>(node);
+    cerr << ind << "String_Constant : " << expression << " [" << prettyprint(expression->value()) << "]" <<
+      (expression->is_delayed() ? " {delayed}" : "") <<
+      (expression->sass_fix_1291() ? " {sass_fix_1291}" : "") <<
+      " <" << prettyprint(expression->pstate().token.ws_before()) << "> X <" << prettyprint(expression->pstate().token.ws_after()) << ">" << endl;
+  } else if (dynamic_cast<String_Schema*>(node)) {
+    String_Schema* expression = dynamic_cast<String_Schema*>(node);
+    cerr << ind << "String_Schema " << expression << " " << expression->concrete_type() <<
+      (expression->has_interpolants() ? " {has_interpolants}" : "") <<
+      endl;
+    for(auto i : expression->elements()) { debug_ast(i, ind + " ", env); }
+  } else if (dynamic_cast<String*>(node)) {
+    String* expression = dynamic_cast<String*>(node);
+    cerr << ind << "String " << expression << expression->concrete_type() <<
+      " " << (expression->sass_fix_1291() ? "{sass_fix_1291}" : "") <<
+      endl;
+  } else if (dynamic_cast<Expression*>(node)) {
+    Expression* expression = dynamic_cast<Expression*>(node);
+    cerr << ind << "Expression " << expression << " " << expression->concrete_type() << endl;
+  } else if (dynamic_cast<Has_Block*>(node)) {
+    Has_Block* has_block = dynamic_cast<Has_Block*>(node);
+    cerr << ind << "Has_Block " << has_block << " " << has_block->tabs() << endl;
+    if (has_block->block()) for(auto i : has_block->block()->elements()) { debug_ast(i, ind + " ", env); }
+  } else if (dynamic_cast<Statement*>(node)) {
+    Statement* statement = dynamic_cast<Statement*>(node);
+    cerr << ind << "Statement " << statement << " " << statement->tabs() << endl;
+  }
+
+  if (ind == "") cerr << "####################################################################\n";
+}
+
+#endif // SASS_DEBUGGER
diff --git a/emitter.cpp b/emitter.cpp
new file mode 100644
index 0000000000..e2b030b2b6
--- /dev/null
+++ b/emitter.cpp
@@ -0,0 +1,240 @@
+#include "util.hpp"
+#include "context.hpp"
+#include "output.hpp"
+#include "emitter.hpp"
+#include "utf8_string.hpp"
+
+namespace Sass {
+  using namespace std;
+
+  Emitter::Emitter(Context* ctx)
+  : wbuf(),
+    ctx(ctx),
+    indentation(0),
+    scheduled_space(0),
+    scheduled_linefeed(0),
+    scheduled_delimiter(false),
+    in_comment(false),
+    in_media_block(false),
+    in_declaration(false),
+    in_declaration_list(false)
+  { }
+
+  // return buffer as string
+  string Emitter::get_buffer(void)
+  {
+    return wbuf.buffer;
+  }
+
+  Output_Style Emitter::output_style(void)
+  {
+    return ctx ? ctx->output_style : COMPRESSED;
+  }
+
+  // PROXY METHODS FOR SOURCE MAPS
+
+  void Emitter::add_source_index(size_t idx)
+  { wbuf.smap.source_index.push_back(idx); }
+
+  string Emitter::generate_source_map(Context &ctx)
+  { return wbuf.smap.generate_source_map(ctx); }
+
+  void Emitter::set_filename(const string& str)
+  { wbuf.smap.file = str; }
+
+  void Emitter::add_open_mapping(AST_Node* node)
+  { wbuf.smap.add_open_mapping(node); }
+  void Emitter::add_close_mapping(AST_Node* node)
+  { wbuf.smap.add_close_mapping(node); }
+  ParserState Emitter::remap(const ParserState& pstate)
+  { return wbuf.smap.remap(pstate); }
+
+  // MAIN BUFFER MANIPULATION
+
+  // add outstanding delimiter
+  void Emitter::finalize(void)
+  {
+    scheduled_space = 0;
+    if (scheduled_linefeed)
+      scheduled_linefeed = 1;
+    flush_schedules();
+  }
+
+  // flush scheduled space/linefeed
+  void Emitter::flush_schedules(void)
+  {
+    // check the schedule
+    if (scheduled_linefeed) {
+      string linefeeds = "";
+
+      for (size_t i = 0; i < scheduled_linefeed; i++)
+        linefeeds += ctx ? ctx->linefeed : "\n";
+      scheduled_space = 0;
+      scheduled_linefeed = 0;
+      append_string(linefeeds);
+
+    } else if (scheduled_space) {
+      string spaces(scheduled_space, ' ');
+      scheduled_space = 0;
+      append_string(spaces);
+    }
+    if (scheduled_delimiter) {
+      scheduled_delimiter = false;
+      append_string(";");
+    }
+  }
+
+  // append some text or token to the buffer
+  void Emitter::append_string(const string& text)
+  {
+    // write space/lf
+    flush_schedules();
+
+    if (in_comment && output_style() == COMPACT) {
+      // unescape comment nodes
+      string out = comment_to_string(text);
+      // add to buffer
+      wbuf.buffer += out;
+      // account for data in source-maps
+      wbuf.smap.update_column(out);
+    } else {
+      // add to buffer
+      wbuf.buffer += text;
+      // account for data in source-maps
+      wbuf.smap.update_column(text);
+    }
+  }
+
+  // append some white-space only text
+  void Emitter::append_wspace(const string& text)
+  {
+    if (text.empty()) return;
+    if (peek_linefeed(text.c_str())) {
+      scheduled_space = 0;
+      append_mandatory_linefeed();
+    }
+  }
+
+  // append some text or token to the buffer
+  // this adds source-mappings for node start and end
+  void Emitter::append_token(const string& text, AST_Node* node)
+  {
+    flush_schedules();
+    add_open_mapping(node);
+    append_string(text);
+    add_close_mapping(node);
+  }
+
+  // HELPER METHODS
+
+  void Emitter::append_indentation()
+  {
+    if (output_style() == COMPRESSED) return;
+    if (output_style() == COMPACT) return;
+    if (scheduled_linefeed && indentation)
+      scheduled_linefeed = 1;
+    string indent = "";
+    for (size_t i = 0; i < indentation; i++)
+      indent += ctx ? ctx->indent : "  ";
+    append_string(indent);
+  }
+
+  void Emitter::append_delimiter()
+  {
+    scheduled_delimiter = true;
+    if (output_style() == COMPACT) {
+      if (indentation == 0) {
+        append_mandatory_linefeed();
+      } else {
+        append_mandatory_space();
+      }
+    } else if (output_style() != COMPRESSED) {
+      append_optional_linefeed();
+    }
+  }
+
+  void Emitter::append_comma_separator()
+  {
+    scheduled_space = 0;
+    append_string(",");
+    append_optional_space();
+  }
+
+  void Emitter::append_colon_separator()
+  {
+    scheduled_space = 0;
+    append_string(":");
+    append_optional_space();
+  }
+
+  void Emitter::append_mandatory_space()
+  {
+    scheduled_space = 1;
+  }
+
+  void Emitter::append_optional_space()
+  {
+    if (output_style() != COMPRESSED && buffer().size()) {
+      char lst = buffer().at(buffer().length() - 1);
+      if (!isspace(lst)) append_mandatory_space();
+    }
+  }
+
+  void Emitter::append_special_linefeed()
+  {
+    if (output_style() == COMPACT) {
+      append_mandatory_linefeed();
+      for (size_t p = 0; p < indentation; p++)
+        append_string(ctx ? ctx->indent : "  ");
+    }
+  }
+
+  void Emitter::append_optional_linefeed()
+  {
+    if (output_style() == COMPACT) {
+      append_mandatory_space();
+    } else {
+      append_mandatory_linefeed();
+    }
+  }
+
+  void Emitter::append_mandatory_linefeed()
+  {
+    if (output_style() != COMPRESSED) {
+      scheduled_linefeed = 1;
+      scheduled_space = 0;
+      // flush_schedules();
+    }
+  }
+
+  void Emitter::append_scope_opener(AST_Node* node)
+  {
+    append_optional_space();
+    flush_schedules();
+    if (node) add_open_mapping(node);
+    append_string("{");
+    append_optional_linefeed();
+    // append_optional_space();
+    ++ indentation;
+  }
+  void Emitter::append_scope_closer(AST_Node* node)
+  {
+    -- indentation;
+    scheduled_linefeed = 0;
+    if (output_style() == COMPRESSED)
+      scheduled_delimiter = false;
+    if (output_style() == EXPANDED) {
+      append_optional_linefeed();
+      append_indentation();
+    } else {
+      append_optional_space();
+    }
+    append_string("}");
+    if (node) add_close_mapping(node);
+    append_optional_linefeed();
+    if (indentation != 0) return;
+    if (output_style() != COMPRESSED)
+      scheduled_linefeed = 2;
+  }
+
+}
diff --git a/emitter.hpp b/emitter.hpp
new file mode 100644
index 0000000000..83855ce5ff
--- /dev/null
+++ b/emitter.hpp
@@ -0,0 +1,89 @@
+#ifndef SASS_EMITTER_H
+#define SASS_EMITTER_H
+
+#include <string>
+#include "source_map.hpp"
+#include "ast_fwd_decl.hpp"
+
+namespace Sass {
+  class Context;
+  using namespace std;
+
+  class OutputBuffer {
+    public:
+      OutputBuffer(void)
+      : buffer(""),
+        smap()
+      { }
+    public:
+      string buffer;
+      SourceMap smap;
+  };
+
+  class Emitter {
+
+    public:
+      Emitter(Context* ctx);
+      virtual ~Emitter() { };
+
+    protected:
+      OutputBuffer wbuf;
+    public:
+      const string buffer(void) { return wbuf.buffer; }
+      const SourceMap smap(void) { return wbuf.smap; }
+      // proxy methods for source maps
+      void add_source_index(size_t idx);
+      void set_filename(const string& str);
+      void add_open_mapping(AST_Node* node);
+      void add_close_mapping(AST_Node* node);
+      string generate_source_map(Context &ctx);
+      ParserState remap(const ParserState& pstate);
+
+    public:
+      Context* ctx;
+      size_t indentation;
+      size_t scheduled_space;
+      size_t scheduled_linefeed;
+      bool scheduled_delimiter;
+
+    public:
+      bool in_comment;
+      bool in_media_block;
+      bool in_declaration;
+      bool in_declaration_list;
+
+    public:
+      // return buffer as string
+      string get_buffer(void);
+      // flush scheduled space/linefeed
+      Output_Style output_style(void);
+      // add outstanding linefeed
+      void finalize(void);
+      // flush scheduled space/linefeed
+      void flush_schedules(void);
+      // append some text or token to the buffer
+      void append_string(const string& text);
+      // append some white-space only text
+      void append_wspace(const string& text);
+      // append some text or token to the buffer
+      // this adds source-mappings for node start and end
+      void append_token(const string& text, AST_Node* node);
+
+    public: // syntax sugar
+      void append_indentation();
+      void append_optional_space(void);
+      void append_mandatory_space(void);
+      void append_special_linefeed(void);
+      void append_optional_linefeed(void);
+      void append_mandatory_linefeed(void);
+      void append_scope_opener(AST_Node* node = 0);
+      void append_scope_closer(AST_Node* node = 0);
+      void append_comma_separator(void);
+      void append_colon_separator(void);
+      void append_delimiter(void);
+
+  };
+
+}
+
+#endif
diff --git a/eval.cpp b/eval.cpp
index cf4979c749..44e6c1e2f8 100644
--- a/eval.cpp
+++ b/eval.cpp
@@ -204,7 +204,7 @@ namespace Sass {
   Expression* Eval::operator()(Warning* w)
   {
     Expression* message = w->message()->perform(this);
-    To_String to_string;
+    To_String to_string(&ctx);
 
     // try to use generic function
     if (env->has("@warn[f]")) {
@@ -235,7 +235,7 @@ namespace Sass {
   Expression* Eval::operator()(Error* e)
   {
     Expression* message = e->message()->perform(this);
-    To_String to_string;
+    To_String to_string(&ctx);
 
     // try to use generic function
     if (env->has("@error[f]")) {
@@ -266,7 +266,7 @@ namespace Sass {
   Expression* Eval::operator()(Debug* d)
   {
     Expression* message = d->value()->perform(this);
-    To_String to_string;
+    To_String to_string(&ctx);
 
     // try to use generic function
     if (env->has("@debug[f]")) {
@@ -384,7 +384,18 @@ namespace Sass {
     if (l_type == Expression::COLOR && r_type == Expression::COLOR) {
       return op_colors(ctx, op_type, lhs, rhs);
     }
-    return op_strings(ctx, op_type, lhs, rhs);
+
+    Expression* ex = op_strings(ctx, op_type, lhs, rhs);
+    if (String_Constant* str = (String_Constant*) ex)
+    {
+      if (str->concrete_type() != Expression::STRING) return ex;
+      String_Constant* lstr = dynamic_cast<String_Constant*>(lhs);
+      String_Constant* rstr = dynamic_cast<String_Constant*>(rhs);
+      if (String_Constant* org = lstr ? lstr : rstr)
+      { str->quote_mark(org->quote_mark()); }
+    }
+    return ex;
+
   }
 
   Expression* Eval::operator()(Unary_Expression* u)
@@ -403,7 +414,7 @@ namespace Sass {
       return result;
     }
     else {
-      To_String to_string;
+      To_String to_string(&ctx);
       // Special cases: +/- variables which evaluate to null ouput just +/-,
       // but +/- null itself outputs the string
       if (operand->concrete_type() == Expression::NULL_VAL && typeid(*(u->operand())) == typeid(Variable)) {
@@ -438,7 +449,7 @@ namespace Sass {
       Function_Call* lit = new (ctx.mem) Function_Call(c->pstate(),
                                                        c->name(),
                                                        args);
-      To_String to_string;
+      To_String to_string(&ctx);
       return new (ctx.mem) String_Constant(c->pstate(),
                                            lit->perform(&to_string));
     }
@@ -589,7 +600,7 @@ namespace Sass {
 
   Expression* Eval::operator()(Variable* v)
   {
-    To_String to_string;
+    To_String to_string(&ctx);
     string name(v->name());
     Expression* value = 0;
     if (env->has(name)) value = static_cast<Expression*>((*env)[name]);
@@ -603,7 +614,11 @@ namespace Sass {
       static_cast<Number*>(value)->zero(true);
     }
     else if (value->concrete_type() == Expression::STRING) {
-      value = new (ctx.mem) String_Constant(*static_cast<String_Constant*>(value));
+      if (auto str = dynamic_cast<String_Quoted*>(value)) {
+        value = new (ctx.mem) String_Quoted(*str);
+      } else if (auto str = dynamic_cast<String_Constant*>(value)) {
+        value = new (ctx.mem) String_Constant(*str);
+      }
     }
     else if (value->concrete_type() == Expression::LIST) {
       value = new (ctx.mem) List(*static_cast<List*>(value));
@@ -711,28 +726,91 @@ namespace Sass {
     }
   }
 
+  string Eval::interpolation(Expression* s) {
+
+    if (String_Quoted* str_quoted = dynamic_cast<String_Quoted*>(s)) {
+
+      if (str_quoted->quote_mark()) {
+        return string_escape(str_quoted->value());
+      } else {
+        return evacuate_escapes(str_quoted->value());
+      }
+
+    } else if (String_Constant* str_constant = dynamic_cast<String_Constant*>(s)) {
+
+      return evacuate_escapes(str_constant->value());
+
+    } else if (String_Schema* str_schema = dynamic_cast<String_Schema*>(s)) {
+
+      string res = "";
+      for(auto i : str_schema->elements())
+        res += (interpolation(i));
+      //ToDo: do this in one step
+      auto esc = evacuate_escapes(res);
+      auto unq = unquote(esc);
+      if (unq == esc) {
+        return string_to_output(res);
+      } else {
+        return evacuate_quotes(unq);
+      }
+
+    } else if (List* list = dynamic_cast<List*>(s)) {
+
+      string acc = ""; // ToDo: different output styles
+      string sep = list->separator() == List::Separator::COMMA ? "," : " ";
+      if (ctx.output_style != COMPRESSED && sep == ",") sep += " ";
+      bool initial = false;
+      for(auto item : list->elements()) {
+        if (initial) acc += sep;
+        acc += interpolation(item);
+        initial = true;
+      }
+      return evacuate_quotes(acc);
+
+    } else if (Variable* var = dynamic_cast<Variable*>(s)) {
+
+      string name(var->name());
+      if (!env->has(name)) return name;
+      Expression* value = static_cast<Expression*>((*env)[name]);
+      return evacuate_quotes(interpolation(value));
+
+    } else if (Binary_Expression* var = dynamic_cast<Binary_Expression*>(s)) {
+
+      Expression* ex = operator()(var);
+      return evacuate_quotes(interpolation(ex));
+
+    } else if (Function_Call* var = dynamic_cast<Function_Call*>(s)) {
+
+      Expression* ex = operator()(var);
+      return evacuate_quotes(interpolation(ex));
+
+    } else {
+
+      To_String to_string(&ctx);
+      // to_string.in_decl_list = true;
+      return evacuate_quotes(s->perform(&to_string));
+
+    }
+  }
+
   Expression* Eval::operator()(String_Schema* s)
   {
     string acc;
-    // ctx._skip_source_map_update = true;
-    To_String to_string(&ctx);
-    // ctx._skip_source_map_update = false;
     for (size_t i = 0, L = s->length(); i < L; ++i) {
-      string chunk((*s)[i]->perform(this)->perform(&to_string));
-      if (((s->quote_mark() && is_quoted(chunk)) || !s->quote_mark()) && (*s)[i]->is_interpolant()) { // some redundancy in that test
-        acc += unquote(chunk);
-      }
-      else {
-        acc += chunk;
-      }
+      acc += interpolation((*s)[i]);
+    }
+    String_Quoted* str = new (ctx.mem) String_Quoted(s->pstate(), acc);
+    if (!str->quote_mark()) {
+      str->value(string_unescape(str->value()));
+    } else if (str->quote_mark()) {
+      str->quote_mark('*');
     }
-    return new (ctx.mem) String_Constant(s->pstate(),
-                                         acc);
+    return str;
   }
 
   Expression* Eval::operator()(String_Constant* s)
   {
-    if (!s->is_delayed() && ctx.names_to_colors.count(s->value())) {
+    if (!s->quote_mark() && !s->is_delayed() && ctx.names_to_colors.count(s->value())) {
       Color* c = new (ctx.mem) Color(*ctx.names_to_colors[s->value()]);
       c->pstate(s->pstate());
       c->disp(s->value());
@@ -783,7 +861,7 @@ namespace Sass {
 
   Expression* Eval::operator()(Media_Query* q)
   {
-    To_String to_string;
+    To_String to_string(&ctx);
     String* t = q->media_type();
     t = static_cast<String*>(t ? t->perform(this) : 0);
     Media_Query* qq = new (ctx.mem) Media_Query(q->pstate(),
@@ -1019,8 +1097,9 @@ namespace Sass {
       case Binary_Expression::SUB:
       case Binary_Expression::DIV: {
         string sep(op == Binary_Expression::SUB ? "-" : "/");
-        To_String to_string;
-        string color(r->sixtuplet() ? r->perform(&to_string) :
+        To_String to_string(&ctx);
+        string color(r->sixtuplet() && (ctx.output_style != COMPRESSED) ?
+                     r->perform(&to_string) :
                      Util::normalize_sixtuplet(r->perform(&to_string)));
         return new (ctx.mem) String_Constant(l->pstate(),
                                              l->perform(&to_string)
@@ -1069,20 +1148,18 @@ namespace Sass {
 
   Expression* op_strings(Context& ctx, Binary_Expression::Type op, Expression* lhs, Expression*rhs)
   {
-    To_String to_string;
+    To_String to_string(&ctx);
     Expression::Concrete_Type ltype = lhs->concrete_type();
     Expression::Concrete_Type rtype = rhs->concrete_type();
 
     string lstr(lhs->perform(&to_string));
     string rstr(rhs->perform(&to_string));
 
-    bool l_str_quoted = ((Sass::String*)lhs) && ((Sass::String*)lhs)->needs_unquoting();
-    bool r_str_quoted = ((Sass::String*)rhs) && ((Sass::String*)rhs)->needs_unquoting();
+    bool l_str_quoted = ((Sass::String*)lhs) && ((Sass::String*)lhs)->sass_fix_1291();
+    bool r_str_quoted = ((Sass::String*)rhs) && ((Sass::String*)rhs)->sass_fix_1291();
     bool l_str_color = ltype == Expression::STRING && ctx.names_to_colors.count(lstr) && !l_str_quoted;
     bool r_str_color = rtype == Expression::STRING && ctx.names_to_colors.count(rstr) && !r_str_quoted;
 
-    bool unquoted = false;
-    if (ltype == Expression::STRING && lstr[0] != '"' && lstr[0] != '\'') unquoted = true;
     if (l_str_color && r_str_color) {
       return op_colors(ctx, op, ctx.names_to_colors[lstr], ctx.names_to_colors[rstr]);
     }
@@ -1108,12 +1185,10 @@ namespace Sass {
     }
     if (ltype == Expression::NULL_VAL) error("invalid null operation: \"null plus "+quote(unquote(rstr), '"')+"\".", lhs->pstate());
     if (rtype == Expression::NULL_VAL) error("invalid null operation: \""+quote(unquote(lstr), '"')+" plus null\".", lhs->pstate());
-    char q = '\0';
-    if (lstr[0] == '"' || lstr[0] == '\'') q = lstr[0];
-    else if (rstr[0] == '"' || rstr[0] == '\'') q = rstr[0];
-    string result(unquote(lstr) + sep + unquote(rstr));
-    return new (ctx.mem) String_Constant(lhs->pstate(),
-                               unquoted ? result : quote(result, q));
+    string result((lstr) + sep + (rstr));
+    String_Quoted* str = new (ctx.mem) String_Quoted(lhs->pstate(), result);
+    str->quote_mark(0);
+    return str;
   }
 
   Expression* cval_to_astnode(Sass_Value* v, Context& ctx, Backtrace* backtrace, ParserState pstate)
diff --git a/eval.hpp b/eval.hpp
index e3a2fed59c..c902687de5 100644
--- a/eval.hpp
+++ b/eval.hpp
@@ -3,6 +3,7 @@
 
 #include <iostream>
 
+#include "context.hpp"
 #include "position.hpp"
 #include "operation.hpp"
 #include "environment.hpp"
@@ -11,7 +12,6 @@
 namespace Sass {
   using namespace std;
 
-  struct Context;
   typedef Environment<AST_Node*> Env;
   struct Backtrace;
 
@@ -65,6 +65,10 @@ namespace Sass {
 
     template <typename U>
     Expression* fallback(U x) { return fallback_impl(x); }
+
+  private:
+    string interpolation(Expression* s);
+
   };
 
   Expression* cval_to_astnode(Sass_Value* v, Context& ctx, Backtrace* backtrace, ParserState pstate = ParserState("[AST]"));
diff --git a/expand.cpp b/expand.cpp
index da485539e4..a8a30de67e 100644
--- a/expand.cpp
+++ b/expand.cpp
@@ -62,8 +62,10 @@ namespace Sass {
       contextual = contextualize->with(at_root_selector_stack.back(), env, backtrace);
 
     Selector* sel_ctx = r->selector()->perform(contextual);
+    if (sel_ctx == 0) throw "Cannot expand null selector";
 
-    Inspect isp(0);
+    Emitter emitter(&ctx);
+    Inspect isp(emitter);
     sel_ctx->perform(&isp);
     string str = isp.get_buffer();
     str += ";";
@@ -73,17 +75,17 @@ namespace Sass {
     p.position = str.c_str();
     p.end      = str.c_str() + strlen(str.c_str());
     Selector_List* sel_lst = p.parse_selector_group();
-    sel_lst->pstate(isp.source_map.remap(sel_lst->pstate()));
+    sel_lst->pstate(isp.remap(sel_lst->pstate()));
 
     for(size_t i = 0; i < sel_lst->length(); i++) {
 
       Complex_Selector* pIter = (*sel_lst)[i];
       while (pIter) {
         Compound_Selector* pHead = pIter->head();
-        pIter->pstate(isp.source_map.remap(pIter->pstate()));
+        pIter->pstate(isp.remap(pIter->pstate()));
         if (pHead) {
-          pHead->pstate(isp.source_map.remap(pHead->pstate()));
-          (*pHead)[0]->pstate(isp.source_map.remap((*pHead)[0]->pstate()));
+          pHead->pstate(isp.remap(pHead->pstate()));
+          (*pHead)[0]->pstate(isp.remap((*pHead)[0]->pstate()));
         }
         pIter = pIter->tail();
       }
@@ -91,9 +93,11 @@ namespace Sass {
     sel_ctx = sel_lst;
 
     selector_stack.push_back(sel_ctx);
+    Block* blk = r->block()->perform(this)->block();
     Ruleset* rr = new (ctx.mem) Ruleset(r->pstate(),
                                         sel_ctx,
-                                        r->block()->perform(this)->block());
+                                        blk);
+    rr->tabs(r->tabs());
     selector_stack.pop_back();
     in_at_root = old_in_at_root;
     old_in_at_root = false;
@@ -147,13 +151,14 @@ namespace Sass {
 
   Statement* Expand::operator()(Media_Block* m)
   {
-    To_String to_string;
+    To_String to_string(&ctx);
     Expression* mq = m->media_queries()->perform(eval->with(env, backtrace));
     mq = Parser::from_c_str(mq->perform(&to_string).c_str(), ctx, mq->pstate()).parse_media_queries();
     Media_Block* mm = new (ctx.mem) Media_Block(m->pstate(),
                                                 static_cast<List*>(mq),
                                                 m->block()->perform(this)->block(),
                                                 selector_stack.back());
+    mm->tabs(m->tabs());
     return mm;
   }
 
@@ -201,10 +206,12 @@ namespace Sass {
 
     if (value->is_invisible() && !d->is_important()) return 0;
 
-    return new (ctx.mem) Declaration(d->pstate(),
-                                     new_p,
-                                     value,
-                                     d->is_important());
+    Declaration* decl = new (ctx.mem) Declaration(d->pstate(),
+                                                  new_p,
+                                                  value,
+                                                  d->is_important());
+    decl->tabs(d->tabs());
+    return decl;
   }
 
   Statement* Expand::operator()(Assignment* a)
@@ -259,7 +266,7 @@ namespace Sass {
   Statement* Expand::operator()(Comment* c)
   {
     // TODO: eval the text, once we're parsing/storing it as a String_Schema
-    return new (ctx.mem) Comment(c->pstate(), static_cast<String*>(c->text()->perform(eval->with(env, backtrace))));
+    return new (ctx.mem) Comment(c->pstate(), static_cast<String*>(c->text()->perform(eval->with(env, backtrace))), c->is_important());
   }
 
   Statement* Expand::operator()(If* i)
@@ -393,7 +400,7 @@ namespace Sass {
 
   Statement* Expand::operator()(Extension* e)
   {
-    To_String to_string;
+    To_String to_string(&ctx);
     Selector_List* extender = static_cast<Selector_List*>(selector_stack.back());
     if (!extender) return 0;
     Selector_List* extendee = static_cast<Selector_List*>(e->selector()->perform(contextualize->with(0, env, backtrace)));
diff --git a/expand.hpp b/expand.hpp
index e6afa35331..e6962f7a84 100644
--- a/expand.hpp
+++ b/expand.hpp
@@ -6,15 +6,14 @@
 #include <iostream>
 
 #include "ast.hpp"
+#include "eval.hpp"
 #include "operation.hpp"
 #include "environment.hpp"
+#include "contextualize.hpp"
 
 namespace Sass {
   using namespace std;
 
-  struct Context;
-  class Eval;
-  class Contextualize;
   typedef Environment<AST_Node*> Env;
   struct Backtrace;
 
diff --git a/extend.cpp b/extend.cpp
index 566568ddb3..812d5e4c60 100644
--- a/extend.cpp
+++ b/extend.cpp
@@ -1594,6 +1594,7 @@ namespace Sass {
 #endif
 
 
+      if (pSelector && pSelector->has_line_feed()) pNewSelector->has_line_feed(true);
 
       // Set the sources on our new Complex_Selector to the sources of this simple sequence plus the thing we're extending.
       DEBUG_PRINTLN(EXTEND_COMPOUND, "SOURCES SETTING ON NEW SEQ: " << complexSelectorToNode(pNewSelector, ctx))
@@ -1701,6 +1702,8 @@ namespace Sass {
     ExtensionSubsetMap& subsetMap,
     set<Compound_Selector> seen) {
 
+    pComplexSelector->tail()->has_line_feed(pComplexSelector->has_line_feed());
+
     Node complexSelector = complexSelectorToNode(pComplexSelector, ctx);
 
     DEBUG_PRINTLN(EXTEND_COMPLEX, "EXTEND COMPLEX: " << complexSelector)
@@ -1806,7 +1809,7 @@ namespace Sass {
   */
   static Selector_List* extendSelectorList(Selector_List* pSelectorList, Context& ctx, ExtensionSubsetMap& subsetMap, bool& extendedSomething) {
 
-    To_String to_string;
+    To_String to_string(&ctx);
 
     Selector_List* pNewSelectors = new (ctx.mem) Selector_List(pSelectorList->pstate(), pSelectorList->length());
 
@@ -1881,7 +1884,7 @@ namespace Sass {
   // Extend a ruleset by extending the selectors and updating them on the ruleset. The block's rules don't need to change.
   template <typename ObjectType>
   static void extendObjectWithSelectorAndBlock(ObjectType* pObject, Context& ctx, ExtensionSubsetMap& subsetMap) {
-    To_String to_string;
+    To_String to_string(&ctx);
 
     DEBUG_PRINTLN(EXTEND_OBJECT, "FOUND SELECTOR: " << static_cast<Selector_List*>(pObject->selector())->perform(&to_string))
 
diff --git a/functions.cpp b/functions.cpp
index 63f75e8498..dc33586601 100644
--- a/functions.cpp
+++ b/functions.cpp
@@ -754,21 +754,21 @@ namespace Sass {
     Signature unquote_sig = "unquote($string)";
     BUILT_IN(sass_unquote)
     {
-      To_String to_string;
+      To_String to_string(&ctx);
       AST_Node* arg = env["$string"];
-      string org(arg->perform(&to_string));
-      string str(unquote(org));
-      String_Constant* result = new (ctx.mem) String_Constant(pstate, str);
-      // remember if the string was quoted (color tokens)
-      if (org[0] != str[0]) result->needs_unquoting(true);
-      result->is_delayed(true);
-      return result;
+      if (String_Quoted* string_quoted = dynamic_cast<String_Quoted*>(arg)) {
+        String_Constant* result = new (ctx.mem) String_Constant(pstate, string_quoted->value());
+        // remember if the string was quoted (color tokens)
+        result->sass_fix_1291(string_quoted->quote_mark());
+        return result;
+      }
+      return new (ctx.mem) String_Constant(pstate, string(arg->perform(&to_string)));
     }
 
     Signature quote_sig = "quote($string)";
     BUILT_IN(sass_quote)
     {
-      To_String to_string;
+      To_String to_string(&ctx);
       AST_Node* arg = env["$string"];
       string str(quote(arg->perform(&to_string), String_Constant::double_quote()));
       String_Constant* result = new (ctx.mem) String_Constant(pstate, str);
@@ -783,16 +783,7 @@ namespace Sass {
       size_t len = string::npos;
       try {
         String_Constant* s = ARG("$string", String_Constant);
-        string str = s->value();
-        size_t length_of_s = str.size();
-        size_t i = 0;
-
-        if (s->is_quoted()) {
-          ++i;
-          --length_of_s;
-        }
-
-        len = UTF_8::code_point_count(str, i, length_of_s);
+        len = UTF_8::code_point_count(s->value(), 0, s->value().size());
 
       }
       catch (utf8::invalid_code_point) {
@@ -819,7 +810,6 @@ namespace Sass {
       try {
         String_Constant* s = ARG("$string", String_Constant);
         str = s->value();
-        char quotemark = s->quote_mark();
         str = unquote(str);
         String_Constant* i = ARG("$insert", String_Constant);
         string ins = i->value();
@@ -849,8 +839,8 @@ namespace Sass {
           str = ins + str;
         }
 
-        if (quotemark) {
-          str = quote(str, String_Constant::double_quote());
+        if (String_Quoted* ss = dynamic_cast<String_Quoted*>(s)) {
+          if (ss->quote_mark()) str = quote(str);
         }
       }
       catch (utf8::invalid_code_point) {
@@ -913,9 +903,7 @@ namespace Sass {
         Number* n = ARG("$start-at", Number);
         Number* m = ARG("$end-at", Number);
 
-        string str = s->value();
-        char quotemark = s->quote_mark();
-        str = unquote(str);
+        string str = unquote(s->value());
 
         // normalize into 0-based indices
         size_t start = UTF_8::offset_at_position(str, UTF_8::normalize_index(n->value(), UTF_8::code_point_count(str)));
@@ -924,15 +912,19 @@ namespace Sass {
         // `str-slice` should always return an empty string when $end-at == 0
         // `normalize_index` normalizes 1 -> 0 so we need to check the original value
         if(m->value() == 0) {
-          if(!quotemark) return new (ctx.mem) Null(pstate);
+          if (String_Quoted* ss = dynamic_cast<String_Quoted*>(s)) {
+            if(!ss->quote_mark()) return new (ctx.mem) Null(pstate);
+          } else {
+            return new (ctx.mem) Null(pstate);
+          }
           newstr = "";
         } else if(start == end && m->value() != 0) {
           newstr = str.substr(start, 1);
         } else if(end > start) {
           newstr = str.substr(start, end - start + UTF_8::code_point_size_at_offset(str, end));
         }
-        if(quotemark) {
-          newstr = quote(newstr, String_Constant::double_quote());
+        if (String_Quoted* ss = dynamic_cast<String_Quoted*>(s)) {
+          if(ss->quote_mark()) newstr = quote(newstr);
         }
       }
       catch (utf8::invalid_code_point) {
@@ -963,6 +955,9 @@ namespace Sass {
         }
       }
 
+      if (String_Quoted* ss = dynamic_cast<String_Quoted*>(s)) {
+        str = ss->quote_mark() ? quote(str) : str;
+      }
       return new (ctx.mem) String_Constant(pstate, str);
     }
 
@@ -978,6 +973,9 @@ namespace Sass {
         }
       }
 
+      if (String_Quoted* ss = dynamic_cast<String_Quoted*>(s)) {
+        str = ss->quote_mark() ? quote(str, '"') : str;
+      }
       return new (ctx.mem) String_Constant(pstate, str);
     }
 
@@ -1362,7 +1360,7 @@ namespace Sass {
     {
       Expression* v = ARG("$value", Expression);
       if (v->concrete_type() == Expression::STRING) {
-        To_String to_string;
+        To_String to_string(&ctx);
         string str(v->perform(&to_string));
         if (ctx.names_to_colors.count(str)) {
           return new (ctx.mem) String_Constant(pstate, "color");
@@ -1373,7 +1371,7 @@ namespace Sass {
 
     Signature unit_sig = "unit($number)";
     BUILT_IN(unit)
-    { return new (ctx.mem) String_Constant(pstate, quote(ARG("$number", Number)->unit(), '"')); }
+    { return new (ctx.mem) String_Quoted(pstate, quote(ARG("$number", Number)->unit(), '"')); }
 
     Signature unitless_sig = "unitless($number)";
     BUILT_IN(unitless)
@@ -1520,8 +1518,20 @@ namespace Sass {
         return new (ctx.mem) String_Constant(pstate, "null");
       } else if (v->concrete_type() == Expression::BOOLEAN && *v == 0) {
         return new (ctx.mem) String_Constant(pstate, "false");
+      } else if (v->concrete_type() == Expression::STRING) {
+        return v;
+      } else {
+        Output_Style old_style;
+        old_style = ctx.output_style;
+        ctx.output_style = NESTED;
+        To_String to_string(&ctx);
+        string inspect = v->perform(&to_string);
+        ctx.output_style = old_style;
+        return new (ctx.mem) String_Constant(pstate, inspect);
+
+
       }
-      return v;
+      // return v;
     }
 
     Signature unique_id_sig = "unique-id()";
diff --git a/inspect.cpp b/inspect.cpp
index d58dd3ce74..2fd3d236b3 100644
--- a/inspect.cpp
+++ b/inspect.cpp
@@ -6,16 +6,14 @@
 #include <string>
 #include <iostream>
 #include <iomanip>
+#include <stdint.h>
+#include <stdint.h>
 
 namespace Sass {
   using namespace std;
 
-  Inspect::Inspect(Context* ctx)
-  : buffer(""),
-    indentation(0),
-    ctx(ctx),
-    in_declaration(false),
-    in_declaration_list(false)
+  Inspect::Inspect(Emitter emi)
+  : Emitter(emi)
   { }
   Inspect::~Inspect() { }
 
@@ -23,30 +21,19 @@ namespace Sass {
   void Inspect::operator()(Block* block)
   {
     if (!block->is_root()) {
-      append_to_buffer(" {" + ctx->linefeed);
-      ++ indentation;
+      add_open_mapping(block);
+      append_scope_opener();
     }
+    if (output_style() == NESTED) indentation += block->tabs();
     for (size_t i = 0, L = block->length(); i < L; ++i) {
-      append_indent_to_buffer();
       (*block)[i]->perform(this);
-      // extra newline at the end of top-level statements
-      if (block->is_root()) append_to_buffer(ctx->linefeed);
-      append_to_buffer(ctx->linefeed);
     }
+    if (output_style() == NESTED) indentation -= block->tabs();
     if (!block->is_root()) {
-      -- indentation;
-      append_indent_to_buffer();
-      append_to_buffer("}");
-    }
-    // remove extra newline that gets added after the last top-level block
-    if (block->is_root()) {
-      size_t l = buffer.length();
-      if (l > 2 && buffer[l-1] == '\n' && buffer[l-2] == '\n') {
-        buffer.erase(l-1);
-        if (ctx) ctx->source_map.remove_line();
-        source_map.remove_line();
-      }
+      append_scope_closer();
+      add_close_mapping(block);
     }
+
   }
 
   void Inspect::operator()(Ruleset* ruleset)
@@ -57,6 +44,7 @@ namespace Sass {
 
   void Inspect::operator()(Keyframe_Rule* rule)
   {
+    append_indentation();
     if (rule->rules()) rule->rules()->perform(this);
     rule->block()->perform(this);
   }
@@ -64,50 +52,65 @@ namespace Sass {
   void Inspect::operator()(Propset* propset)
   {
     propset->property_fragment()->perform(this);
-    append_to_buffer(": ");
+    append_colon_separator();
     propset->block()->perform(this);
   }
 
   void Inspect::operator()(Bubble* bubble)
   {
-    append_to_buffer("Bubble ( ");
+    append_indentation();
+    append_token("Bubble", bubble);
+    append_optional_space();
+    append_string("(");
+    append_optional_space();
     bubble->node()->perform(this);
-    append_to_buffer(" )");
+    append_optional_space();
+    append_string(")");
+    append_optional_space();
   }
 
   void Inspect::operator()(Media_Block* media_block)
   {
-    append_to_buffer("@media", media_block, " ");
+    append_indentation();
+    append_token("@media", media_block);
+    append_mandatory_space();
+    in_media_block = true;
     media_block->media_queries()->perform(this);
+    in_media_block = false;
     media_block->block()->perform(this);
   }
 
   void Inspect::operator()(Feature_Block* feature_block)
   {
-    append_to_buffer("@supports", feature_block, " ");
+    append_indentation();
+    append_token("@supports", feature_block);
+    append_mandatory_space();
     feature_block->feature_queries()->perform(this);
     feature_block->block()->perform(this);
   }
 
   void Inspect::operator()(At_Root_Block* at_root_block)
   {
-    append_to_buffer("@at-root ", at_root_block, " ");
+    append_indentation();
+    append_token("@at-root ", at_root_block);
+    append_mandatory_space();
     if(at_root_block->expression()) at_root_block->expression()->perform(this);
     at_root_block->block()->perform(this);
   }
 
   void Inspect::operator()(At_Rule* at_rule)
   {
-    append_to_buffer(at_rule->keyword());
+    append_indentation();
+    append_token(at_rule->keyword(), at_rule);
     if (at_rule->selector()) {
-      append_to_buffer(" ");
+      append_mandatory_space();
       at_rule->selector()->perform(this);
     }
     if (at_rule->block()) {
       at_rule->block()->perform(this);
     }
     else {
-      append_to_buffer(";");
+      append_delimiter();
     }
   }
 
@@ -115,166 +118,210 @@ namespace Sass {
   {
     if (dec->value()->concrete_type() == Expression::NULL_VAL) return;
     in_declaration = true;
-    if (ctx) ctx->source_map.add_open_mapping(dec->property());
-    source_map.add_open_mapping(dec->property());
+    if (output_style() == NESTED)
+      indentation += dec->tabs();
+    append_indentation();
     dec->property()->perform(this);
-    if (ctx) ctx->source_map.add_close_mapping(dec->property());
-    source_map.add_close_mapping(dec->property());
-    append_to_buffer(": ");
-    if (ctx) ctx->source_map.add_open_mapping(dec->value());
-    source_map.add_open_mapping(dec->value());
+    append_colon_separator();
     dec->value()->perform(this);
-    if (dec->is_important()) append_to_buffer(" !important");
-    if (ctx) ctx->source_map.add_close_mapping(dec->value());
-    source_map.add_close_mapping(dec->value());
-    append_to_buffer(";");
+    if (dec->is_important()) {
+      append_optional_space();
+      append_string("!important");
+    }
+    append_delimiter();
+    if (output_style() == NESTED)
+      indentation -= dec->tabs();
     in_declaration = false;
   }
 
   void Inspect::operator()(Assignment* assn)
   {
-    append_to_buffer(assn->variable());
-    append_to_buffer(": ");
+    append_token(assn->variable(), assn);
+    append_colon_separator();
     assn->value()->perform(this);
-    if (assn->is_guarded()) append_to_buffer(" !default");
-    append_to_buffer(";");
+    if (assn->is_guarded()) {
+      append_optional_space();
+      append_string("!default");
+    }
+    append_delimiter();
   }
 
   void Inspect::operator()(Import* import)
   {
     if (!import->urls().empty()) {
-      append_to_buffer("@import", import, " ");
+      append_token("@import", import);
+      append_mandatory_space();
+
+      if (String_Quoted* strq = dynamic_cast<String_Quoted*>(import->urls().front())) {
+        strq->is_delayed(false);
+      }
+
       import->urls().front()->perform(this);
-      append_to_buffer(";");
+      append_delimiter();
       for (size_t i = 1, S = import->urls().size(); i < S; ++i) {
-        append_to_buffer(ctx->linefeed);
-        append_to_buffer("@import", import, " ");
+        append_mandatory_linefeed();
+        append_token("@import", import);
+        append_mandatory_space();
+
+        if (String_Quoted* strq = dynamic_cast<String_Quoted*>(import->urls()[i])) {
+          strq->is_delayed(false);
+        }
+
         import->urls()[i]->perform(this);
-        append_to_buffer(";");
+        append_delimiter();
       }
     }
   }
 
   void Inspect::operator()(Import_Stub* import)
   {
-    append_to_buffer("@import", import, " ");
-    append_to_buffer(import->file_name());
-    append_to_buffer(";");
+    append_indentation();
+    append_token("@import", import);
+    append_mandatory_space();
+    append_string(import->file_name());
+    append_delimiter();
   }
 
   void Inspect::operator()(Warning* warning)
   {
-    append_to_buffer("@warn", warning, " ");
+    append_indentation();
+    append_token("@warn", warning);
+    append_mandatory_space();
     warning->message()->perform(this);
-    append_to_buffer(";");
+    append_delimiter();
   }
 
   void Inspect::operator()(Error* error)
   {
-    append_to_buffer("@error", error, " ");
+    append_indentation();
+    append_token("@error", error);
+    append_mandatory_space();
     error->message()->perform(this);
-    append_to_buffer(";");
+    append_delimiter();
   }
 
   void Inspect::operator()(Debug* debug)
   {
-    append_to_buffer("@debug", debug, " ");
+    append_indentation();
+    append_token("@debug", debug);
+    append_mandatory_space();
     debug->value()->perform(this);
-    append_to_buffer(";");
+    append_delimiter();
   }
 
   void Inspect::operator()(Comment* comment)
   {
+    in_comment = true;
     comment->text()->perform(this);
+    in_comment = false;
   }
 
   void Inspect::operator()(If* cond)
   {
-    append_to_buffer("@if", cond, " ");
+    append_indentation();
+    append_token("@if", cond);
+    append_mandatory_space();
     cond->predicate()->perform(this);
     cond->consequent()->perform(this);
     if (cond->alternative()) {
-      append_to_buffer(ctx->linefeed);
-      append_indent_to_buffer();
-      append_to_buffer("else");
+      append_optional_linefeed();
+      append_indentation();
+      append_string("else");
       cond->alternative()->perform(this);
     }
   }
 
   void Inspect::operator()(For* loop)
   {
-    append_to_buffer("@for", loop, " ");
-    append_to_buffer(loop->variable());
-    append_to_buffer(" from ");
+    append_indentation();
+    append_token("@for", loop);
+    append_mandatory_space();
+    append_string(loop->variable());
+    append_string(" from ");
     loop->lower_bound()->perform(this);
-    append_to_buffer((loop->is_inclusive() ? " through " : " to "));
+    append_string(loop->is_inclusive() ? " through " : " to ");
     loop->upper_bound()->perform(this);
     loop->block()->perform(this);
   }
 
   void Inspect::operator()(Each* loop)
   {
-    append_to_buffer("@each", loop, " ");
-    append_to_buffer(loop->variables()[0]);
+    append_indentation();
+    append_token("@each", loop);
+    append_mandatory_space();
+    append_string(loop->variables()[0]);
     for (size_t i = 1, L = loop->variables().size(); i < L; ++i) {
-      append_to_buffer(", ");
-      append_to_buffer(loop->variables()[i]);
+      append_comma_separator();
+      append_string(loop->variables()[i]);
     }
-    append_to_buffer(" in ");
+    append_string(" in ");
     loop->list()->perform(this);
     loop->block()->perform(this);
   }
 
   void Inspect::operator()(While* loop)
   {
-    append_to_buffer("@while", loop, " ");
+    append_indentation();
+    append_token("@while", loop);
+    append_mandatory_space();
     loop->predicate()->perform(this);
     loop->block()->perform(this);
   }
 
   void Inspect::operator()(Return* ret)
   {
-    append_to_buffer("@return", ret, " ");
+    append_indentation();
+    append_token("@return", ret);
+    append_mandatory_space();
     ret->value()->perform(this);
-    append_to_buffer(";");
+    append_delimiter();
   }
 
   void Inspect::operator()(Extension* extend)
   {
-    append_to_buffer("@extend", extend, " ");
+    append_indentation();
+    append_token("@extend", extend);
+    append_mandatory_space();
     extend->selector()->perform(this);
-    append_to_buffer(";");
+    append_delimiter();
   }
 
   void Inspect::operator()(Definition* def)
   {
+    append_indentation();
     if (def->type() == Definition::MIXIN) {
-      append_to_buffer("@mixin", def, " ");
+      append_token("@mixin", def);
+      append_mandatory_space();
     } else {
-      append_to_buffer("@function", def, " ");
+      append_token("@function", def);
+      append_mandatory_space();
     }
-    append_to_buffer(def->name());
+    append_string(def->name());
     def->parameters()->perform(this);
     def->block()->perform(this);
   }
 
   void Inspect::operator()(Mixin_Call* call)
   {
-    append_to_buffer("@include", call, " ");
-    append_to_buffer(call->name());
+    append_indentation();
+    append_token("@include", call);
+    append_mandatory_space();
+    append_string(call->name());
     if (call->arguments()) {
       call->arguments()->perform(this);
     }
     if (call->block()) {
-      append_to_buffer(" ");
+      append_optional_space();
       call->block()->perform(this);
     }
-    if (!call->block()) append_to_buffer(";");
+    if (!call->block()) append_delimiter();
   }
 
   void Inspect::operator()(Content* content)
   {
-    append_to_buffer("@content", content, ";");
+    append_indentation();
+    append_token("@content", content);
+    append_delimiter();
   }
 
   void Inspect::operator()(Map* map)
@@ -282,22 +329,24 @@ namespace Sass {
     if (map->empty()) return;
     if (map->is_invisible()) return;
     bool items_output = false;
-    append_to_buffer("(");
+    append_string("(");
     for (auto key : map->keys()) {
       if (key->is_invisible()) continue;
       if (map->at(key)->is_invisible()) continue;
-      if (items_output) append_to_buffer(", ");
+      if (items_output) append_comma_separator();
       key->perform(this);
-      append_to_buffer(": ");
+      append_colon_separator();
       map->at(key)->perform(this);
       items_output = true;
     }
-    append_to_buffer(")");
+    append_string(")");
   }
 
   void Inspect::operator()(List* list)
   {
-    string sep(list->separator() == List::SPACE ? " " : ", ");
+    string sep(list->separator() == List::SPACE ? " " : ",");
+    if (output_style() != COMPRESSED && sep == ",") sep += " ";
+    else if (in_media_block && sep != " ") sep += " "; // verified
     if (list->empty()) return;
     bool items_output = false;
     in_declaration_list = in_declaration;
@@ -306,7 +355,11 @@ namespace Sass {
       if (list_item->is_invisible()) {
         continue;
       }
-      if (items_output) append_to_buffer(sep);
+      if (items_output) {
+        append_string(sep);
+      }
+      if (items_output && sep != " ")
+        append_optional_space();
       list_item->perform(this);
       items_output = true;
     }
@@ -317,19 +370,19 @@ namespace Sass {
   {
     expr->left()->perform(this);
     switch (expr->type()) {
-      case Binary_Expression::AND: append_to_buffer(" and "); break;
-      case Binary_Expression::OR:  append_to_buffer(" or ");  break;
-      case Binary_Expression::EQ:  append_to_buffer(" == ");  break;
-      case Binary_Expression::NEQ: append_to_buffer(" != ");  break;
-      case Binary_Expression::GT:  append_to_buffer(" > ");   break;
-      case Binary_Expression::GTE: append_to_buffer(" >= ");  break;
-      case Binary_Expression::LT:  append_to_buffer(" < ");   break;
-      case Binary_Expression::LTE: append_to_buffer(" <= ");  break;
-      case Binary_Expression::ADD: append_to_buffer(" + ");   break;
-      case Binary_Expression::SUB: append_to_buffer(" - ");   break;
-      case Binary_Expression::MUL: append_to_buffer(" * ");   break;
-      case Binary_Expression::DIV: append_to_buffer("/");     break;
-      case Binary_Expression::MOD: append_to_buffer(" % ");   break;
+      case Binary_Expression::AND: append_string(" and "); break;
+      case Binary_Expression::OR:  append_string(" or ");  break;
+      case Binary_Expression::EQ:  append_string(" == ");  break;
+      case Binary_Expression::NEQ: append_string(" != ");  break;
+      case Binary_Expression::GT:  append_string(" > ");   break;
+      case Binary_Expression::GTE: append_string(" >= ");  break;
+      case Binary_Expression::LT:  append_string(" < ");   break;
+      case Binary_Expression::LTE: append_string(" <= ");  break;
+      case Binary_Expression::ADD: append_string(" + ");   break;
+      case Binary_Expression::SUB: append_string(" - ");   break;
+      case Binary_Expression::MUL: append_string(" * ");   break;
+      case Binary_Expression::DIV: append_string("/");     break;
+      case Binary_Expression::MOD: append_string(" % ");   break;
       default: break; // shouldn't get here
     }
     expr->right()->perform(this);
@@ -337,14 +390,14 @@ namespace Sass {
 
   void Inspect::operator()(Unary_Expression* expr)
   {
-    if (expr->type() == Unary_Expression::PLUS) append_to_buffer("+");
-    else                                        append_to_buffer("-");
+    if (expr->type() == Unary_Expression::PLUS) append_string("+");
+    else                                        append_string("-");
     expr->operand()->perform(this);
   }
 
   void Inspect::operator()(Function_Call* call)
   {
-    append_to_buffer(call->name());
+    append_token(call->name(), call);
     call->arguments()->perform(this);
   }
 
@@ -356,34 +409,13 @@ namespace Sass {
 
   void Inspect::operator()(Variable* var)
   {
-    append_to_buffer(var->name());
+    append_token(var->name(), var);
   }
 
   void Inspect::operator()(Textual* txt)
   {
-    append_to_buffer(txt->value());
-  }
-
-  // helper functions for serializing numbers
-  // string frac_to_string(double f, size_t p) {
-  //   stringstream ss;
-  //   ss.setf(ios::fixed, ios::floatfield);
-  //   ss.precision(p);
-  //   ss << f;
-  //   string result(ss.str().substr(f < 0 ? 2 : 1));
-  //   size_t i = result.size() - 1;
-  //   while (result[i] == '0') --i;
-  //   result = result.substr(0, i+1);
-  //   return result;
-  // }
-  // string double_to_string(double d, size_t p) {
-  //   stringstream ss;
-  //   double ipart;
-  //   double fpart = std::modf(d, &ipart);
-  //   ss << ipart;
-  //   if (fpart != 0) ss << frac_to_string(fpart, 5);
-  //   return ss.str();
-  // }
+    append_token(txt->value(), txt);
+  }
 
   void Inspect::operator()(Number* n)
   {
@@ -416,8 +448,7 @@ namespace Sass {
     // a value before it got truncated
     if (d == "0" && nonzero) d = "0.0";
     // append number and unit
-    append_to_buffer(d);
-    append_to_buffer(n->unit());
+    append_token(d + n->unit(), n);
   }
 
   // helper function for serializing colors
@@ -431,47 +462,85 @@ namespace Sass {
   void Inspect::operator()(Color* c)
   {
     stringstream ss;
+
+    // check if we prefer short hex colors
+    bool want_short = output_style() == COMPRESSED;
+
+    // original color name
+    // maybe an unknown token
+    string name = c->disp();
+
+    // resolved color
+    string res_name = name;
+
     double r = round(cap_channel<0xff>(c->r()));
     double g = round(cap_channel<0xff>(c->g()));
     double b = round(cap_channel<0xff>(c->b()));
     double a = cap_channel<1>   (c->a());
 
+    // get color from given name (if one was given at all)
+    if (name != "" && ctx && ctx->names_to_colors.count(name)) {
+      Color* n = ctx->names_to_colors[name];
+      r = round(cap_channel<0xff>(n->r()));
+      g = round(cap_channel<0xff>(n->g()));
+      b = round(cap_channel<0xff>(n->b()));
+      a = cap_channel<1>   (n->a());
+    }
+    // otherwise get the possible resolved color name
+    else {
+      int numval = r * 0x10000 + g * 0x100 + b;
+      if (ctx && ctx->colors_to_names.count(numval))
+        res_name = ctx->colors_to_names[numval];
+    }
+
+    stringstream hexlet;
+    hexlet << '#' << setw(1) << setfill('0');
+    // create a short color hexlet if there is any need for it
+    if (want_short && is_color_doublet(r, g, b) && a == 1) {
+      hexlet << hex << setw(1) << (static_cast<unsigned long>(r) >> 4);
+      hexlet << hex << setw(1) << (static_cast<unsigned long>(g) >> 4);
+      hexlet << hex << setw(1) << (static_cast<unsigned long>(b) >> 4);
+    } else {
+      hexlet << hex << setw(2) << static_cast<unsigned long>(r);
+      hexlet << hex << setw(2) << static_cast<unsigned long>(g);
+      hexlet << hex << setw(2) << static_cast<unsigned long>(b);
+    }
+
     // retain the originally specified color definition if unchanged
-    if (!c->disp().empty()) {
-      ss << c->disp();
+    if (name != "") {
+      ss << name;
     }
     else if (r == 0 && g == 0 && b == 0 && a == 0) {
         ss << "transparent";
     }
     else if (a >= 1) {
-      // see if it's a named color
-      int numval = r * 0x10000;
-      numval += g * 0x100;
-      numval += b;
-      if (ctx && ctx->colors_to_names.count(numval)) {
-        ss << ctx->colors_to_names[numval];
+      if (res_name != "") {
+        if (want_short && hexlet.str().size() < res_name.size()) {
+          ss << hexlet.str();
+        } else {
+          ss << res_name;
+        }
       }
       else {
-        // otherwise output the hex triplet
-        ss << '#' << setw(2) << setfill('0');
-        ss << hex << setw(2) << static_cast<unsigned long>(r);
-        ss << hex << setw(2) << static_cast<unsigned long>(g);
-        ss << hex << setw(2) << static_cast<unsigned long>(b);
+        ss << hexlet.str();
       }
     }
     else {
       ss << "rgba(";
-      ss << static_cast<unsigned long>(r) << ", ";
-      ss << static_cast<unsigned long>(g) << ", ";
-      ss << static_cast<unsigned long>(b) << ", ";
+      ss << static_cast<unsigned long>(r) << ",";
+      if (output_style() != COMPRESSED) ss << " ";
+      ss << static_cast<unsigned long>(g) << ",";
+      if (output_style() != COMPRESSED) ss << " ";
+      ss << static_cast<unsigned long>(b) << ",";
+      if (output_style() != COMPRESSED) ss << " ";
       ss << a << ')';
     }
-    append_to_buffer(ss.str());
+    append_token(ss.str(), c);
   }
 
   void Inspect::operator()(Boolean* b)
   {
-    append_to_buffer(b->value() ? "true" : "false");
+    append_token(b->value() ? "true" : "false", b);
   }
 
   void Inspect::operator()(String_Schema* ss)
@@ -479,15 +548,27 @@ namespace Sass {
     // Evaluation should turn these into String_Constants, so this method is
     // only for inspection purposes.
     for (size_t i = 0, L = ss->length(); i < L; ++i) {
-      if ((*ss)[i]->is_interpolant()) append_to_buffer("#{");
+      if ((*ss)[i]->is_interpolant()) append_string("#{");
       (*ss)[i]->perform(this);
-      if ((*ss)[i]->is_interpolant()) append_to_buffer("}");
+      if ((*ss)[i]->is_interpolant()) append_string("}");
     }
   }
 
   void Inspect::operator()(String_Constant* s)
   {
-    append_to_buffer(s->needs_unquoting() ? unquote(s->value()) : s->value(), s);
+    if (String_Quoted* quoted = dynamic_cast<String_Quoted*>(s)) {
+      return Inspect::operator()(quoted);
+    }
+    append_token(s->value(), s);
+  }
+
+  void Inspect::operator()(String_Quoted* s)
+  {
+    if (s->quote_mark()) {
+      append_token(quote(s->value(), s->quote_mark()), s);
+    } else {
+      append_token(s->value(), s);
+    }
   }
 
   void Inspect::operator()(Feature_Query* fq)
@@ -501,40 +582,46 @@ namespace Sass {
 
   void Inspect::operator()(Feature_Query_Condition* fqc)
   {
-    if (fqc->operand() == Feature_Query_Condition::AND)
-      append_to_buffer(" and ");
-    else if (fqc->operand() == Feature_Query_Condition::OR)
-      append_to_buffer(" or ");
-    else if (fqc->operand() == Feature_Query_Condition::NOT)
-      append_to_buffer(" not ");
+    if (fqc->operand() == Feature_Query_Condition::AND) {
+      append_mandatory_space();
+      append_token("and", fqc);
+      append_mandatory_space();
+    } else if (fqc->operand() == Feature_Query_Condition::OR) {
+      append_mandatory_space();
+      append_token("or", fqc);
+      append_mandatory_space();
+    } else if (fqc->operand() == Feature_Query_Condition::NOT) {
+      append_mandatory_space();
+      append_token("not", fqc);
+      append_mandatory_space();
+    }
 
-    if (!fqc->is_root()) append_to_buffer("(");
+    if (!fqc->is_root()) append_string("(");
 
     if (!fqc->length()) {
       fqc->feature()->perform(this);
-      append_to_buffer(": ");
+      append_string(": "); // verified
       fqc->value()->perform(this);
     }
-    // else
     for (size_t i = 0, L = fqc->length(); i < L; ++i)
       (*fqc)[i]->perform(this);
 
-    if (!fqc->is_root()) append_to_buffer(")");
+    if (!fqc->is_root()) append_string(")");
   }
 
   void Inspect::operator()(Media_Query* mq)
   {
     size_t i = 0;
     if (mq->media_type()) {
-      if      (mq->is_negated())    append_to_buffer("not ");
-      else if (mq->is_restricted()) append_to_buffer("only ");
+      if      (mq->is_negated())    append_string("not ");
+      else if (mq->is_restricted()) append_string("only ");
       mq->media_type()->perform(this);
     }
     else {
       (*mq)[i++]->perform(this);
     }
     for (size_t L = mq->length(); i < L; ++i) {
-      append_to_buffer(" and ");
+      append_string(" and ");
       (*mq)[i]->perform(this);
     }
   }
@@ -542,28 +629,16 @@ namespace Sass {
   void Inspect::operator()(Media_Query_Expression* mqe)
   {
     if (mqe->is_interpolated()) {
-      if (ctx) ctx->source_map.add_open_mapping(mqe->feature());
-      source_map.add_open_mapping(mqe->feature());
       mqe->feature()->perform(this);
-      if (ctx) ctx->source_map.add_close_mapping(mqe->feature());
-      source_map.add_close_mapping(mqe->feature());
     }
     else {
-      append_to_buffer("(");
-      if (ctx) ctx->source_map.add_open_mapping(mqe->feature());
-      source_map.add_open_mapping(mqe->feature());
+      append_string("(");
       mqe->feature()->perform(this);
-      if (ctx) ctx->source_map.add_close_mapping(mqe->feature());
-      source_map.add_close_mapping(mqe->feature());
       if (mqe->value()) {
-        append_to_buffer(": ");
-        if (ctx) ctx->source_map.add_open_mapping(mqe->value());
-        source_map.add_open_mapping(mqe->value());
+        append_string(": "); // verified
         mqe->value()->perform(this);
-        if (ctx) ctx->source_map.add_close_mapping(mqe->value());
-        source_map.add_close_mapping(mqe->value());
       }
-      append_to_buffer(")");
+      append_string(")");
     }
   }
 
@@ -573,52 +648,52 @@ namespace Sass {
       ae->feature()->perform(this);
     }
     else {
-      append_to_buffer("(");
+      append_string("(");
       ae->feature()->perform(this);
       if (ae->value()) {
-        append_to_buffer(": ");
+        append_colon_separator();
         ae->value()->perform(this);
       }
-      append_to_buffer(")");
+      append_string(")");
     }
   }
 
   void Inspect::operator()(Null* n)
   {
-    append_to_buffer("null");
+    append_token("null", n);
   }
 
   // parameters and arguments
   void Inspect::operator()(Parameter* p)
   {
-    append_to_buffer(p->name());
+    append_token(p->name(), p);
     if (p->default_value()) {
-      append_to_buffer(": ");
+      append_colon_separator();
       p->default_value()->perform(this);
     }
     else if (p->is_rest_parameter()) {
-      append_to_buffer("...");
+      append_string("...");
     }
   }
 
   void Inspect::operator()(Parameters* p)
   {
-    append_to_buffer("(");
+    append_string("(");
     if (!p->empty()) {
       (*p)[0]->perform(this);
       for (size_t i = 1, L = p->length(); i < L; ++i) {
-        append_to_buffer(", ");
+        append_comma_separator();
         (*p)[i]->perform(this);
       }
     }
-    append_to_buffer(")");
+    append_string(")");
   }
 
   void Inspect::operator()(Argument* a)
   {
     if (!a->name().empty()) {
-      append_to_buffer(a->name());
-      append_to_buffer(": ");
+      append_token(a->name(), a);
+      append_colon_separator();
     }
     // Special case: argument nulls can be ignored
     if (a->value()->concrete_type() == Expression::NULL_VAL) {
@@ -626,28 +701,27 @@ namespace Sass {
     }
     if (a->value()->concrete_type() == Expression::STRING) {
       String_Constant* s = static_cast<String_Constant*>(a->value());
-      if (s->is_quoted()) s->value(quote(unquote(s->value()), String_Constant::double_quote()));
       s->perform(this);
     } else a->value()->perform(this);
     if (a->is_rest_argument()) {
-      append_to_buffer("...");
+      append_string("...");
     }
   }
 
   void Inspect::operator()(Arguments* a)
   {
-    append_to_buffer("(");
+    append_string("(");
     if (!a->empty()) {
       (*a)[0]->perform(this);
       for (size_t i = 1, L = a->length(); i < L; ++i) {
-        append_to_buffer(", ");
+        append_string(", "); // verified
+        // Sass Bug? append_comma_separator();
         (*a)[i]->perform(this);
       }
     }
-    append_to_buffer(")");
+    append_string(")");
   }
 
-  // selectors
   void Inspect::operator()(Selector_Schema* s)
   {
     s->contents()->perform(this);
@@ -656,56 +730,58 @@ namespace Sass {
   void Inspect::operator()(Selector_Reference* ref)
   {
     if (ref->selector()) ref->selector()->perform(this);
-    else                 append_to_buffer("&");
+    else                 append_string("&");
   }
 
   void Inspect::operator()(Selector_Placeholder* s)
   {
-    append_to_buffer(s->name(), s);
+    append_token(s->name(), s);
+    if (s->has_line_break()) append_optional_linefeed();
+    if (s->has_line_break()) append_indentation();
+
   }
 
   void Inspect::operator()(Type_Selector* s)
   {
-    append_to_buffer(s->name(), s);
+    append_token(s->name(), s);
   }
 
   void Inspect::operator()(Selector_Qualifier* s)
   {
-    append_to_buffer(s->name(), s);
+    append_token(s->name(), s);
+    if (s->has_line_break()) append_optional_linefeed();
+    if (s->has_line_break()) append_indentation();
   }
 
   void Inspect::operator()(Attribute_Selector* s)
   {
-    append_to_buffer("[");
-    if (ctx) ctx->source_map.add_open_mapping(s);
-    source_map.add_open_mapping(s);
-    append_to_buffer(s->name());
+    append_string("[");
+    add_open_mapping(s);
+    append_token(s->name(), s);
     if (!s->matcher().empty()) {
-      append_to_buffer(s->matcher());
+      append_string(s->matcher());
       if (s->value()) {
         s->value()->perform(this);
       }
-      // append_to_buffer(s->value());
     }
-    if (ctx) ctx->source_map.add_close_mapping(s);
-    source_map.add_close_mapping(s);
-    append_to_buffer("]");
+    add_close_mapping(s);
+    append_string("]");
   }
 
   void Inspect::operator()(Pseudo_Selector* s)
   {
-    append_to_buffer(s->name(), s);
+    append_token(s->name(), s);
     if (s->expression()) {
       s->expression()->perform(this);
-      append_to_buffer(")");
+      append_string(")");
     }
   }
 
   void Inspect::operator()(Wrapped_Selector* s)
   {
-    append_to_buffer(s->name(), s);
+    append_token(s->name(), s);
     s->selector()->perform(this);
-    append_to_buffer(")");
+    append_string(")");
   }
 
   void Inspect::operator()(Compound_Selector* s)
@@ -713,6 +789,9 @@ namespace Sass {
     for (size_t i = 0, L = s->length(); i < L; ++i) {
       (*s)[i]->perform(this);
     }
+    if (s->has_line_break()) {
+      append_optional_linefeed();
+    }
   }
 
   void Inspect::operator()(Complex_Selector* c)
@@ -721,15 +800,34 @@ namespace Sass {
     Complex_Selector*            tail = c->tail();
     Complex_Selector::Combinator comb = c->combinator();
     if (head && !head->is_empty_reference()) head->perform(this);
-    if (head && !head->is_empty_reference() && tail) append_to_buffer(" ");
+    bool is_empty = head && head->is_empty_reference();
+    bool is_tail = head && !head->is_empty_reference() && tail;
+    if (output_style() == COMPRESSED && comb != Complex_Selector::ANCESTOR_OF) scheduled_space = 0;
+
     switch (comb) {
-      case Complex_Selector::ANCESTOR_OF:                                        break;
-      case Complex_Selector::PARENT_OF:   append_to_buffer(">"); break;
-      case Complex_Selector::PRECEDES:    append_to_buffer("~"); break;
-      case Complex_Selector::ADJACENT_TO: append_to_buffer("+"); break;
+      case Complex_Selector::ANCESTOR_OF:
+        if (is_tail) append_mandatory_space();
+      break;
+      case Complex_Selector::PARENT_OF:
+        append_optional_space();
+        append_string(">");
+        append_optional_space();
+      break;
+      case Complex_Selector::ADJACENT_TO:
+        append_optional_space();
+        append_string("+");
+        append_optional_space();
+      break;
+      case Complex_Selector::PRECEDES:
+        if (is_empty) append_optional_space();
+        else append_mandatory_space();
+        append_string("~");
+        if (tail) append_mandatory_space();
+        else append_optional_space();
+      break;
     }
     if (tail && comb != Complex_Selector::ANCESTOR_OF) {
-      append_to_buffer(" ");
+      if (c->has_line_break()) append_optional_linefeed();
     }
     if (tail) tail->perform(this);
   }
@@ -737,130 +835,21 @@ namespace Sass {
   void Inspect::operator()(Selector_List* g)
   {
     if (g->empty()) return;
-    if (ctx) ctx->source_map.add_open_mapping((*g)[0]);
-    source_map.add_open_mapping((*g)[0]);
-    (*g)[0]->perform(this);
-    if (ctx) ctx->source_map.add_close_mapping((*g)[0]);
-    source_map.add_close_mapping((*g)[0]);
-    for (size_t i = 1, L = g->length(); i < L; ++i) {
-      append_to_buffer(", ");
-      if (ctx) ctx->source_map.add_open_mapping((*g)[i]);
-      source_map.add_open_mapping((*g)[i]);
+    for (size_t i = 0, L = g->length(); i < L; ++i) {
+      if (i == 0) append_indentation();
       (*g)[i]->perform(this);
-      if (ctx) ctx->source_map.add_close_mapping((*g)[i]);
-      source_map.add_close_mapping((*g)[i]);
-    }
-  }
-
-  inline void Inspect::fallback_impl(AST_Node* n)
-  { }
-
-  void Inspect::append_indent_to_buffer()
-  {
-    string indent = "";
-    for (size_t i = 0; i < indentation; i++)
-      indent += ctx->indent;
-    append_to_buffer(indent);
-  }
-
-  string unquote(const string& s)
-  {
-    if (s.empty()) return "";
-    if (s.length() == 1) {
-      if (s[0] == '"' || s[0] == '\'') return "";
-    }
-    // char q;
-    if      (*s.begin() == '"'  && *s.rbegin() == '"')  {} // q = '"';
-    else if (*s.begin() == '\'' && *s.rbegin() == '\'') {} // q = '\'';
-    else                                                return s;
-    string t;
-    t.reserve(s.length()-2);
-
-    for (size_t i = 1, L = s.length()-1; i < L; ++i) {
-
-      // implement the same strange ruby sass behavior
-      // an escape sequence can also mean a unicode char
-      if (s[i] == '\\') {
-
-        // skip it
-        ++ i;
-
-        // escape length
-        size_t len = 0;
-
-        // parse as many sequence chars as possible
-        // ToDo: Check if ruby aborts after possible max
-        while (s[i + len] && isxdigit(s[i + len])) ++ len;
-
-        // hex string?
-        if (len == 0) {
-
-          // add next char
-          t.push_back(s[i]);
-
-        } else {
-
-          // convert the extracted hex string to code point value
-          // ToDo: Maybe we could do this without creating a substring
-          uint32_t cp = strtol(s.substr (i, len).c_str(), nullptr, 16);
-
-          // use a very simple approach to convert via utf8 lib
-          // maybe there is a more elegant way; maybe we shoud
-          // convert the whole output from string to a stream!?
-          // allocate memory for utf8 char and convert to utf8
-          unsigned char u[5] = {0,0,0,0,0}; utf8::append(cp, u);
-          for(size_t m = 0; u[m] && m < 5; m++) t.push_back(u[m]);
-
-          // skip some more chars?
-          if (len > 1) i += len - 1;
-
+      if (i < L - 1) {
+        append_comma_separator();
+        if ((*g)[i]->has_line_feed()) {
+          append_optional_linefeed();
+          append_indentation();
         }
-        // EO if hex
-
-      } else {
-        // add single char
-        t.push_back(s[i]);
       }
     }
-
-    return t;
-  }
-
-  string quote(const string& s, char q)
-  {
-    if (s.empty()) return string(2, q);
-    if (!q || s[0] == '"' || s[0] == '\'') return s;
-    string t;
-    t.reserve(s.length()+2);
-    t.push_back(q);
-    for (size_t i = 0, L = s.length(); i < L; ++i) {
-      if (s[i] == q) t.push_back('\\');
-      t.push_back(s[i]);
-    }
-    t.push_back(q);
-    return t;
-  }
-
-  void Inspect::append_to_buffer(const string& text)
-  {
-    buffer += text;
-    if (ctx) ctx->source_map.update_column(text);
-    source_map.update_column(text);
-  }
-
-  void Inspect::append_to_buffer(const string& text, AST_Node* node)
-  {
-    if (ctx) ctx->source_map.add_open_mapping(node);
-    source_map.add_open_mapping(node);
-    append_to_buffer(text);
-    if (ctx) ctx->source_map.add_close_mapping(node);
-    source_map.add_close_mapping(node);
   }
 
-  void Inspect::append_to_buffer(const string& text, AST_Node* node, const string& tail)
+  void Inspect::fallback_impl(AST_Node* n)
   {
-    append_to_buffer(text, node);
-    append_to_buffer(tail);
   }
 
 }
diff --git a/inspect.hpp b/inspect.hpp
index e408322c91..702d562fd3 100644
--- a/inspect.hpp
+++ b/inspect.hpp
@@ -5,39 +5,24 @@
 
 #include "position.hpp"
 #include "operation.hpp"
-#include "source_map.hpp"
+#include "emitter.hpp"
 
 namespace Sass {
+  class Context;
   using namespace std;
-  struct Context;
 
-  class Inspect : public Operation_CRTP<void, Inspect> {
+  class Inspect : public Operation_CRTP<void, Inspect>, public Emitter {
+  protected:
     // import all the class-specific methods and override as desired
     using Operation_CRTP<void, Inspect>::operator();
 
-    // To_String* to_string;
-    string buffer;
-    size_t indentation;
-    Context* ctx;
-    bool in_declaration;
-    bool in_declaration_list;
-
     void fallback_impl(AST_Node* n);
 
-  public:
-    void append_indent_to_buffer();
-    void append_to_buffer(const string& text);
-    void append_to_buffer(const string& text, AST_Node* node);
-    void append_to_buffer(const string& text, AST_Node* node, const string& tail);
-
   public:
 
-    SourceMap source_map;
-    Inspect(Context* ctx = 0);
+    Inspect(Emitter emi);
     virtual ~Inspect();
 
-    string get_buffer() { return buffer; }
-
     // statements
     virtual void operator()(Block*);
     virtual void operator()(Ruleset*);
@@ -79,6 +64,7 @@ namespace Sass {
     virtual void operator()(Boolean*);
     virtual void operator()(String_Schema*);
     virtual void operator()(String_Constant*);
+    virtual void operator()(String_Quoted*);
     virtual void operator()(Feature_Query*);
     virtual void operator()(Feature_Query_Condition*);
     virtual void operator()(Media_Query*);
@@ -103,12 +89,9 @@ namespace Sass {
     virtual void operator()(Complex_Selector*);
     virtual void operator()(Selector_List*);
 
-    template <typename U>
-    void fallback(U x) { fallback_impl(reinterpret_cast<AST_Node*>(x)); }
+    // template <typename U>
+    // void fallback(U x) { fallback_impl(reinterpret_cast<AST_Node*>(x)); }
   };
 
-  string unquote(const string&);
-  string quote(const string&, char);
-
 }
 #endif
diff --git a/node.cpp b/node.cpp
index 18bf4d9b7c..5fea9cec9b 100644
--- a/node.cpp
+++ b/node.cpp
@@ -41,11 +41,9 @@ namespace Sass {
   }
 
 
-  Node::Node(const TYPE& type, Complex_Selector::Combinator combinator, Complex_Selector* pSelector, NodeDequePtr& pCollection) :
-  	mType(type),
-    mCombinator(combinator),
-    mpSelector(pSelector),
-    mpCollection(pCollection) {}
+  Node::Node(const TYPE& type, Complex_Selector::Combinator combinator, Complex_Selector* pSelector, NodeDequePtr& pCollection)
+  : got_line_feed(false), mType(type), mCombinator(combinator), mpSelector(pSelector), mpCollection(pCollection)
+  { /* if (pSelector) got_line_feed = pSelector->has_line_feed(); */ }
 
 
   Node Node::clone(Context& ctx) const {
@@ -131,6 +129,7 @@ namespace Sass {
   }
 
 
+  /* not used anymore - remove?
   ostream& operator<<(ostream& os, const Node& node) {
 
     if (node.isCombinator()) {
@@ -169,7 +168,7 @@ namespace Sass {
 
     return os;
 
-  }
+  }*/
 
 
   Node complexSelectorToNode(Complex_Selector* pToConvert, Context& ctx) {
@@ -177,7 +176,7 @@ namespace Sass {
       return Node::createNil();
     }
 
-		Node node = Node::createCollection();
+    Node node = Node::createCollection();
 
     while (pToConvert) {
 
@@ -243,6 +242,7 @@ namespace Sass {
     Selector_Reference* selectorRef = new (ctx.mem) Selector_Reference(ParserState("[NODE]"), NULL);
     fakeHead->elements().push_back(selectorRef);
     pFirst->head(fakeHead);
+    pFirst->has_line_feed(pFirst->has_line_feed() || pFirst->tail()->has_line_feed() || toConvert.got_line_feed);
 
     return pFirst;
   }
diff --git a/node.hpp b/node.hpp
index 097e2f8d16..d42d645801 100644
--- a/node.hpp
+++ b/node.hpp
@@ -50,6 +50,7 @@ namespace Sass {
     bool isSelector() const { return mType == SELECTOR; }
     bool isCollection() const { return mType == COLLECTION; }
     bool isNil() const { return mType == NIL; }
+    bool got_line_feed;
 
     Complex_Selector::Combinator combinator() const { return mCombinator; }
 
@@ -107,14 +108,10 @@ namespace Sass {
     NodeDequePtr mpCollection;
   };
 
-
-  ostream& operator<<(ostream& os, const Node& node);
-
-
+  // ostream& operator<<(ostream& os, const Node& node);
   Node complexSelectorToNode(Complex_Selector* pToConvert, Context& ctx);
   Complex_Selector* nodeToComplexSelector(const Node& toConvert, Context& ctx);
 
-
   bool nodesEqual(const Node& one, const Node& two, bool simpleSelectorOrderDependent);
 
 }
diff --git a/output.cpp b/output.cpp
new file mode 100644
index 0000000000..d0970b1e60
--- /dev/null
+++ b/output.cpp
@@ -0,0 +1,398 @@
+#include "ast.hpp"
+#include "output.hpp"
+#include "to_string.hpp"
+
+namespace Sass {
+  using namespace std;
+
+  Output::Output(Context* ctx)
+  : Inspect(Emitter(ctx)),
+    charset(""),
+    top_imports(0),
+    top_comments(0)
+  {}
+
+  Output::~Output() { }
+
+  void Output::fallback_impl(AST_Node* n)
+  {
+    return n->perform(this);
+  }
+
+  void Output::operator()(Import* imp)
+  {
+    top_imports.push_back(imp);
+  }
+
+  string Output::get_buffer(void)
+  {
+
+    Emitter emitter(ctx);
+    Inspect inspect(emitter);
+
+    size_t size_com = top_comments.size();
+    for (size_t i = 0; i < size_com; i++) {
+      top_comments[i]->perform(&inspect);
+      inspect.append_mandatory_linefeed();
+    }
+
+    size_t size_imp = top_imports.size();
+    for (size_t i = 0; i < size_imp; i++) {
+      top_imports[i]->perform(&inspect);
+      inspect.append_mandatory_linefeed();
+    }
+
+    // flush scheduled outputs
+    inspect.finalize();
+    // create combined buffer string
+    string buffer = inspect.buffer()
+                  + this->buffer();
+    // make sure we end with a linefeed
+    if (!ends_with(buffer, ctx->linefeed)) {
+      // if the output is not completely empty
+      if (!buffer.empty()) buffer += ctx->linefeed;
+    }
+
+    // search for unicode char
+    for(const char& chr : buffer) {
+      // skip all ascii chars
+      if (chr >= 0) continue;
+      // declare the charset
+      if (output_style() != COMPRESSED)
+        charset = "@charset \"UTF-8\";"
+                  + ctx->linefeed;
+      else charset = "\xEF\xBB\xBF";
+      // abort search
+      break;
+    }
+
+    // add charset as first line, before comments and imports
+    return (charset.empty() ? "" : charset) + buffer;
+
+  }
+
+  void Output::operator()(Comment* c)
+  {
+    To_String to_string(ctx);
+    string txt = c->text()->perform(&to_string);
+    // if (indentation && txt == "/**/") return;
+    bool important = c->is_important();
+    if (output_style() != COMPRESSED || important) {
+      if (buffer().size() + top_imports.size() == 0) {
+        top_comments.push_back(c);
+      } else {
+        in_comment = true;
+        append_indentation();
+        c->text()->perform(this);
+        in_comment = false;
+        if (indentation == 0) {
+          append_mandatory_linefeed();
+        } else {
+          append_optional_linefeed();
+        }
+      }
+    }
+  }
+
+  void Output::operator()(Ruleset* r)
+  {
+    Selector* s     = r->selector();
+    Block*    b     = r->block();
+    bool      decls = false;
+
+    // Filter out rulesets that aren't printable (process its children though)
+    if (!Util::isPrintable(r, output_style())) {
+      for (size_t i = 0, L = b->length(); i < L; ++i) {
+        Statement* stm = (*b)[i];
+        if (dynamic_cast<Has_Block*>(stm)) {
+          stm->perform(this);
+        }
+      }
+      return;
+    }
+
+    if (b->has_non_hoistable()) {
+      decls = true;
+      if (output_style() == NESTED) indentation += r->tabs();
+      if (ctx && ctx->source_comments) {
+        stringstream ss;
+        append_indentation();
+        ss << "/* line " << r->pstate().line+1 << ", " << r->pstate().path << " */";
+        append_string(ss.str());
+        append_optional_linefeed();
+      }
+      s->perform(this);
+      append_scope_opener(b);
+      for (size_t i = 0, L = b->length(); i < L; ++i) {
+        Statement* stm = (*b)[i];
+        bool bPrintExpression = true;
+        // Check print conditions
+        if (typeid(*stm) == typeid(Declaration)) {
+          Declaration* dec = static_cast<Declaration*>(stm);
+          if (dec->value()->concrete_type() == Expression::STRING) {
+            String_Constant* valConst = static_cast<String_Constant*>(dec->value());
+            string val(valConst->value());
+            if (dynamic_cast<String_Quoted*>(valConst)) {
+              if (val.empty()) {
+                bPrintExpression = false;
+              }
+            }
+          }
+          else if (dec->value()->concrete_type() == Expression::LIST) {
+            List* list = static_cast<List*>(dec->value());
+            bool all_invisible = true;
+            for (size_t list_i = 0, list_L = list->length(); list_i < list_L; ++list_i) {
+              Expression* item = (*list)[list_i];
+              if (!item->is_invisible()) all_invisible = false;
+            }
+            if (all_invisible) bPrintExpression = false;
+          }
+        }
+        // Print if OK
+        if (!stm->is_hoistable() && bPrintExpression) {
+          stm->perform(this);
+        }
+      }
+      if (output_style() == NESTED) indentation -= r->tabs();
+      append_scope_closer(b);
+    }
+
+    if (b->has_hoistable()) {
+      if (decls) ++indentation;
+      for (size_t i = 0, L = b->length(); i < L; ++i) {
+        Statement* stm = (*b)[i];
+        if (stm->is_hoistable()) {
+          stm->perform(this);
+        }
+      }
+      if (decls) --indentation;
+    }
+  }
+
+  void Output::operator()(Keyframe_Rule* r)
+  {
+    String* v = r->rules();
+    Block* b = r->block();
+
+    if (v) {
+      append_indentation();
+      v->perform(this);
+    }
+
+    if (!b) {
+      append_colon_separator();
+      return;
+    }
+
+    append_scope_opener();
+    for (size_t i = 0, L = b->length(); i < L; ++i) {
+      Statement* stm = (*b)[i];
+      if (!stm->is_hoistable()) {
+        stm->perform(this);
+        if (i < L - 1) append_special_linefeed();
+      }
+    }
+
+    for (size_t i = 0, L = b->length(); i < L; ++i) {
+      Statement* stm = (*b)[i];
+      if (stm->is_hoistable()) {
+        stm->perform(this);
+      }
+    }
+
+    append_scope_closer();
+  }
+
+  void Output::operator()(Feature_Block* f)
+  {
+    if (f->is_invisible()) return;
+
+    Feature_Query* q    = f->feature_queries();
+    Block* b            = f->block();
+
+    // Filter out feature blocks that aren't printable (process its children though)
+    if (!Util::isPrintable(f, output_style())) {
+      for (size_t i = 0, L = b->length(); i < L; ++i) {
+        Statement* stm = (*b)[i];
+        if (dynamic_cast<Has_Block*>(stm)) {
+          stm->perform(this);
+        }
+      }
+      return;
+    }
+
+    if (output_style() == NESTED) indentation += f->tabs();
+    append_indentation();
+    append_token("@supports", f);
+    append_mandatory_space();
+    q->perform(this);
+    append_scope_opener();
+
+    Selector* e = f->selector();
+    if (e && b->has_non_hoistable()) {
+      // JMA - hoisted, output the non-hoistable in a nested block, followed by the hoistable
+      e->perform(this);
+      append_scope_opener();
+
+      for (size_t i = 0, L = b->length(); i < L; ++i) {
+        Statement* stm = (*b)[i];
+        if (!stm->is_hoistable()) {
+          stm->perform(this);
+        }
+      }
+
+      append_scope_closer();
+
+      for (size_t i = 0, L = b->length(); i < L; ++i) {
+        Statement* stm = (*b)[i];
+        if (stm->is_hoistable()) {
+          stm->perform(this);
+        }
+      }
+    }
+    else {
+      // JMA - not hoisted, just output in order
+      for (size_t i = 0, L = b->length(); i < L; ++i) {
+        Statement* stm = (*b)[i];
+        stm->perform(this);
+        if (i < L - 1) append_special_linefeed();
+      }
+    }
+
+    if (output_style() == NESTED) indentation -= f->tabs();
+
+    append_scope_closer();
+
+  }
+
+  void Output::operator()(Media_Block* m)
+  {
+    if (m->is_invisible()) return;
+
+    List*  q     = m->media_queries();
+    Block* b     = m->block();
+
+    // Filter out media blocks that aren't printable (process its children though)
+    if (!Util::isPrintable(m, output_style())) {
+      for (size_t i = 0, L = b->length(); i < L; ++i) {
+        Statement* stm = (*b)[i];
+        if (dynamic_cast<Has_Block*>(stm)) {
+          stm->perform(this);
+        }
+      }
+      return;
+    }
+    if (output_style() == NESTED) indentation += m->tabs();
+    append_indentation();
+    append_token("@media", m);
+    append_mandatory_space();
+    in_media_block = true;
+    q->perform(this);
+    in_media_block = false;
+    append_scope_opener();
+
+    Selector* e = m->selector();
+    if (e && b->has_non_hoistable()) {
+      // JMA - hoisted, output the non-hoistable in a nested block, followed by the hoistable
+      e->perform(this);
+      append_scope_opener();
+
+      for (size_t i = 0, L = b->length(); i < L; ++i) {
+        Statement* stm = (*b)[i];
+        if (!stm->is_hoistable()) {
+          stm->perform(this);
+        }
+      }
+
+      append_scope_closer();
+
+      for (size_t i = 0, L = b->length(); i < L; ++i) {
+        Statement* stm = (*b)[i];
+        if (stm->is_hoistable()) {
+          stm->perform(this);
+        }
+      }
+    }
+    else {
+      // JMA - not hoisted, just output in order
+      for (size_t i = 0, L = b->length(); i < L; ++i) {
+        Statement* stm = (*b)[i];
+        stm->perform(this);
+        if (i < L - 1) append_special_linefeed();
+      }
+    }
+
+    if (output_style() == NESTED) indentation -= m->tabs();
+    append_scope_closer();
+  }
+
+  void Output::operator()(At_Rule* a)
+  {
+    string      kwd   = a->keyword();
+    Selector*   s     = a->selector();
+    Expression* v     = a->value();
+    Block*      b     = a->block();
+
+    append_indentation();
+    append_token(kwd, a);
+    if (s) {
+      append_mandatory_space();
+      s->perform(this);
+    }
+    else if (v) {
+      append_mandatory_space();
+      v->perform(this);
+    }
+    if (!b) {
+      append_delimiter();
+      return;
+    }
+
+    if (b->is_invisible() || b->length() == 0) {
+      return append_string(" {}");
+    }
+
+    append_scope_opener();
+
+    for (size_t i = 0, L = b->length(); i < L; ++i) {
+      Statement* stm = (*b)[i];
+      if (!stm->is_hoistable()) {
+        stm->perform(this);
+        if (i < L - 1) append_special_linefeed();
+      }
+    }
+
+    for (size_t i = 0, L = b->length(); i < L; ++i) {
+      Statement* stm = (*b)[i];
+      if (stm->is_hoistable()) {
+        stm->perform(this);
+        if (i < L - 1) append_special_linefeed();
+      }
+    }
+
+    append_scope_closer();
+  }
+
+  void Output::operator()(String_Quoted* s)
+  {
+    if (s->quote_mark()) {
+      append_token(quote((s->value()), s->quote_mark()), s);
+    } else if (!in_comment) {
+      append_token(string_to_output(s->value()), s);
+    } else {
+      append_token(s->value(), s);
+    }
+  }
+
+  void Output::operator()(String_Constant* s)
+  {
+    if (String_Quoted* quoted = dynamic_cast<String_Quoted*>(s)) {
+      return Output::operator()(quoted);
+    } else if (!in_comment) {
+      append_token(string_to_output(s->value()), s);
+    } else {
+      append_token(s->value(), s);
+    }
+  }
+
+}
diff --git a/output.hpp b/output.hpp
index 246c10ab54..f2cdd2c633 100644
--- a/output.hpp
+++ b/output.hpp
@@ -5,88 +5,49 @@
 #include <vector>
 
 #include "util.hpp"
-#include "context.hpp"
+#include "inspect.hpp"
 #include "operation.hpp"
 
 namespace Sass {
+  class Context;
   using namespace std;
-  struct Context;
 
-  template<typename T>
-  class Output : public Operation_CRTP<void, T> {
-    // import class-specific methods and override as desired
-    using Operation_CRTP<void, T>::operator();
+  // Refactor to make it generic to find linefeed (look behind)
+  inline bool ends_with(std::string const & value, std::string const & ending)
+  {
+    if (ending.size() > value.size()) return false;
+    return std::equal(ending.rbegin(), ending.rend(), value.rbegin());
+  }
 
+  class Output : public Inspect {
   protected:
-    Context* ctx;
-    string buffer;
-    vector<Import*> top_imports;
-    vector<Comment*> top_comments;
-    virtual void fallback_impl(AST_Node* n) = 0;
+    using Inspect::operator();
 
   public:
-    Output(Context* ctx = 0)
-    : ctx(ctx),
-      buffer(""),
-      top_imports(0),
-      top_comments(0)
-    { }
-    virtual ~Output() { };
-
-    string get_buffer(void)
-    {
-      string charset("");
-
-      Inspect comments(ctx);
-      size_t size_com = top_comments.size();
-      for (size_t i = 0; i < size_com; i++) {
-        top_comments[i]->perform(&comments);
-        comments.append_to_buffer(ctx->linefeed);
-      }
-
-      Inspect imports(ctx);
-      size_t size_imp = top_imports.size();
-      for (size_t i = 0; i < size_imp; i++) {
-        top_imports[i]->perform(&imports);
-        imports.append_to_buffer(ctx->linefeed);
-      }
-
-      // create combined buffer string
-      string buffer = comments.get_buffer()
-                    + imports.get_buffer()
-                    + this->buffer;
+    // change to Emitter
+    Output(Context* ctx);
+    virtual ~Output();
 
-      // search for unicode char
-      for(const char& chr : buffer) {
-        // skip all ascii chars
-        if (chr >= 0) continue;
-        // declare the charset
-        charset = "@charset \"UTF-8\";";
-        // abort search
-        break;
-      }
-
-      // add charset as the very first line, before top comments and imports
-      return (charset.empty() ? "" : charset + ctx->linefeed) + buffer;
-    }
-
-    // append some text or token to the buffer
-    void append_to_buffer(const string& data)
-    {
-      // add to buffer
-      buffer += data;
-      // account for data in source-maps
-      ctx->source_map.update_column(data);
-    }
+  protected:
+    string charset;
+    vector<Import*> top_imports;
+    vector<Comment*> top_comments;
 
-    // append some text or token to the buffer
-    // this adds source-mappings for node start and end
-    void append_to_buffer(const string& data, AST_Node* node)
-    {
-      ctx->source_map.add_open_mapping(node);
-      append_to_buffer(data);
-      ctx->source_map.add_close_mapping(node);
-    }
+  public:
+    string get_buffer(void);
+
+    virtual void operator()(Ruleset*);
+    // virtual void operator()(Propset*);
+    virtual void operator()(Feature_Block*);
+    virtual void operator()(Media_Block*);
+    virtual void operator()(At_Rule*);
+    virtual void operator()(Keyframe_Rule*);
+    virtual void operator()(Import*);
+    virtual void operator()(Comment*);
+    virtual void operator()(String_Quoted*);
+    virtual void operator()(String_Constant*);
+
+    void fallback_impl(AST_Node* n);
 
   };
 
diff --git a/output_compressed.cpp b/output_compressed.cpp
deleted file mode 100644
index 3c97c5b10d..0000000000
--- a/output_compressed.cpp
+++ /dev/null
@@ -1,410 +0,0 @@
-#include <cmath>
-#include <iomanip>
-
-#include "ast.hpp"
-#include "util.hpp"
-#include "context.hpp"
-#include "inspect.hpp"
-#include "to_string.hpp"
-#include "output_compressed.hpp"
-
-namespace Sass {
-  using namespace std;
-
-  Output_Compressed::Output_Compressed(Context* ctx) : Output(ctx), seen_utf8(false) { }
-  Output_Compressed::~Output_Compressed() { }
-
-  inline void Output_Compressed::fallback_impl(AST_Node* n)
-  {
-    Inspect i(ctx);
-    n->perform(&i);
-    append_to_buffer(i.get_buffer());
-  }
-
-  void Output_Compressed::operator()(Import* imp)
-  {
-    // Inspect insp(ctx);
-    // imp->perform(&insp);
-    // rendered_imports += insp.get_buffer();
-    top_imports.push_back(imp);
-  }
-
-  void Output_Compressed::operator()(Block* b)
-  {
-    if (!b->is_root()) return;
-    for (size_t i = 0, L = b->length(); i < L; ++i) {
-      (*b)[i]->perform(this);
-    }
-  }
-
-  void Output_Compressed::operator()(Ruleset* r)
-  {
-    Selector* s     = r->selector();
-    Block*    b     = r->block();
-
-    // Filter out rulesets that aren't printable (process its children though)
-    if (!Util::isPrintable(r)) {
-      for (size_t i = 0, L = b->length(); i < L; ++i) {
-        Statement* stm = (*b)[i];
-        if (dynamic_cast<Has_Block*>(stm)) {
-          stm->perform(this);
-        }
-      }
-      return;
-    }
-
-    if (b->has_non_hoistable()) {
-      s->perform(this);
-      append_singleline_part_to_buffer("{");
-      for (size_t i = 0, L = b->length(); i < L; ++i) {
-        Statement* stm = (*b)[i];
-        if (!stm->is_hoistable()) {
-          stm->perform(this);
-        }
-      }
-      size_t l = buffer.length();
-      if (l > 0 && buffer.at(l - 1) == ';') buffer.erase(l - 1);
-      append_singleline_part_to_buffer("}");
-    }
-
-    if (b->has_hoistable()) {
-      for (size_t i = 0, L = b->length(); i < L; ++i) {
-        Statement* stm = (*b)[i];
-        if (stm->is_hoistable()) {
-          stm->perform(this);
-        }
-      }
-    }
-  }
-
-  void Output_Compressed::operator()(Media_Block* m)
-  {
-    if (m->is_invisible()) return;
-
-    List*  q     = m->media_queries();
-    Block* b     = m->block();
-
-    // Filter out media blocks that aren't printable (process its children though)
-    if (!Util::isPrintable(m)) {
-      for (size_t i = 0, L = b->length(); i < L; ++i) {
-        Statement* stm = (*b)[i];
-        if (dynamic_cast<Has_Block*>(stm)) {
-          stm->perform(this);
-        }
-      }
-      return;
-    }
-
-    ctx->source_map.add_open_mapping(m);
-    append_singleline_part_to_buffer("@media ");
-    ctx->source_map.add_close_mapping(m);
-    q->perform(this);
-    append_singleline_part_to_buffer("{");
-
-    Selector* e = m->selector();
-    if (e && b->has_non_hoistable()) {
-      // JMA - hoisted, output the non-hoistable in a nested block, followed by the hoistable
-      e->perform(this);
-      append_singleline_part_to_buffer("{");
-
-      for (size_t i = 0, L = b->length(); i < L; ++i) {
-        Statement* stm = (*b)[i];
-        if (!stm->is_hoistable()) {
-          stm->perform(this);
-        }
-      }
-
-      append_singleline_part_to_buffer("}");
-
-      for (size_t i = 0, L = b->length(); i < L; ++i) {
-        Statement* stm = (*b)[i];
-        if (stm->is_hoistable()) {
-          stm->perform(this);
-        }
-      }
-    }
-    else {
-      // JMA - not hoisted, just output in order
-      for (size_t i = 0, L = b->length(); i < L; ++i) {
-        Statement* stm = (*b)[i];
-        stm->perform(this);
-      }
-    }
-
-    append_singleline_part_to_buffer("}");
-  }
-
-  void Output_Compressed::operator()(Keyframe_Rule* r)
-  {
-    String* v       = r->rules();
-    Block*  b       = r->block();
-
-    if (v) {
-      append_singleline_part_to_buffer(" ");
-      v->perform(this);
-    }
-
-    if (!b) {
-      append_singleline_part_to_buffer(";");
-      return;
-    }
-
-    append_singleline_part_to_buffer("{");
-    for (size_t i = 0, L = b->length(); i < L; ++i) {
-      Statement* stm = (*b)[i];
-      if (!stm->is_hoistable()) {
-        stm->perform(this);
-      }
-    }
-
-    for (size_t i = 0, L = b->length(); i < L; ++i) {
-      Statement* stm = (*b)[i];
-      if (stm->is_hoistable()) {
-        stm->perform(this);
-      }
-    }
-
-    append_singleline_part_to_buffer("}");
-  }
-
-  void Output_Compressed::operator()(At_Rule* a)
-  {
-    string      kwd   = a->keyword();
-    Selector*   s     = a->selector();
-    Expression* v     = a->value();
-    Block*      b     = a->block();
-
-    append_singleline_part_to_buffer(kwd);
-    if (s) {
-      append_singleline_part_to_buffer(" ");
-      s->perform(this);
-    }
-    else if (v) {
-      append_singleline_part_to_buffer(" ");
-      v->perform(this);
-    }
-
-    if (!b) {
-      append_singleline_part_to_buffer(";");
-      return;
-    }
-
-    append_singleline_part_to_buffer("{");
-    for (size_t i = 0, L = b->length(); i < L; ++i) {
-      Statement* stm = (*b)[i];
-      if (!stm->is_hoistable()) {
-        stm->perform(this);
-      }
-    }
-
-    for (size_t i = 0, L = b->length(); i < L; ++i) {
-      Statement* stm = (*b)[i];
-      if (stm->is_hoistable()) {
-        stm->perform(this);
-      }
-    }
-
-    append_singleline_part_to_buffer("}");
-  }
-
-  void Output_Compressed::operator()(Declaration* d)
-  {
-    bool bPrintExpression = true;
-    // Check print conditions
-    if (d->value()->concrete_type() == Expression::NULL_VAL) {
-      bPrintExpression = false;
-    }
-    if (d->value()->concrete_type() == Expression::STRING) {
-      String_Constant* valConst = static_cast<String_Constant*>(d->value());
-      string val(valConst->value());
-      if (val.empty()) {
-        bPrintExpression = false;
-      }
-    }
-    // Print if OK
-    if(bPrintExpression) {
-      if (ctx) ctx->source_map.add_open_mapping(d->property());
-      d->property()->perform(this);
-      append_singleline_part_to_buffer(":");
-      if (ctx) ctx->source_map.add_open_mapping(d->value());
-      d->value()->perform(this);
-      if (d->is_important()) append_singleline_part_to_buffer("!important");
-      append_singleline_part_to_buffer(";");
-    }
-  }
-
-  void Output_Compressed::operator()(Comment* c)
-  {
-    To_String to_string;
-    string txt = c->text()->perform(&to_string);
-    if(txt[2] != '!') {
-      return;
-    }
-    else {
-      Inspect i(ctx);
-      c->perform(&i);
-      append_to_buffer(i.get_buffer());
-    }
-  }
-
-  void Output_Compressed::operator()(List* list)
-  {
-    string sep(list->separator() == List::SPACE ? " " : ",");
-    if (list->empty()) return;
-    Expression* first = (*list)[0];
-    bool first_invisible = first->is_invisible();
-    if (!first_invisible) first->perform(this);
-    for (size_t i = 1, L = list->length(); i < L; ++i) {
-      Expression* next = (*list)[i];
-      bool next_invisible = next->is_invisible();
-      if (i == 1 && !first_invisible && !next_invisible) append_singleline_part_to_buffer(sep);
-      else if (!next_invisible)                          append_singleline_part_to_buffer(sep);
-      next->perform(this);
-    }
-  }
-
-  // helper function for serializing colors
-  template <size_t range>
-  static double cap_channel(double c) {
-    if      (c > range) return range;
-    else if (c < 0)     return 0;
-    else                return c;
-  }
-
-  void Output_Compressed::operator()(Color* c)
-  {
-    stringstream ss;
-    double r = round(cap_channel<0xff>(c->r()));
-    double g = round(cap_channel<0xff>(c->g()));
-    double b = round(cap_channel<0xff>(c->b()));
-    double a = cap_channel<1>   (c->a());
-
-    // retain the originally specified color definition if unchanged
-    if (!c->disp().empty()) {
-      ss << c->disp();
-    }
-    else if (r == 0 && g == 0 && b == 0 && a == 0) {
-        ss << "transparent";
-    }
-    else if (a >= 1) {
-      // see if it's a named color
-      int numval = r * 0x10000;
-      numval += g * 0x100;
-      numval += b;
-      if (ctx && ctx->colors_to_names.count(numval)) {
-        ss << ctx->colors_to_names[numval];
-      }
-      else {
-        // otherwise output the hex triplet
-        ss << '#' << setw(2) << setfill('0');
-        ss << hex << setw(2) << static_cast<unsigned long>(r);
-        ss << hex << setw(2) << static_cast<unsigned long>(g);
-        ss << hex << setw(2) << static_cast<unsigned long>(b);
-      }
-    }
-    else {
-      ss << "rgba(";
-      ss << static_cast<unsigned long>(r) << ",";
-      ss << static_cast<unsigned long>(g) << ",";
-      ss << static_cast<unsigned long>(b) << ",";
-      ss << a << ')';
-    }
-    append_singleline_part_to_buffer(ss.str());
-  }
-
-  void Output_Compressed::operator()(Media_Query_Expression* mqe)
-  {
-    if (mqe->is_interpolated()) {
-      mqe->feature()->perform(this);
-    }
-    else {
-      append_singleline_part_to_buffer("(");
-      mqe->feature()->perform(this);
-      if (mqe->value()) {
-        append_singleline_part_to_buffer(":");
-        mqe->value()->perform(this);
-      }
-      append_singleline_part_to_buffer(")");
-    }
-  }
-
-  void Output_Compressed::operator()(Null* n)
-  {
-    // noop
-  }
-
-  void Output_Compressed::operator()(Argument* a)
-  {
-    if (!a->name().empty()) {
-      append_singleline_part_to_buffer(a->name());
-      append_singleline_part_to_buffer(":");
-    }
-    a->value()->perform(this);
-    if (a->is_rest_argument()) {
-      append_singleline_part_to_buffer("...");
-    }
-  }
-
-  void Output_Compressed::operator()(Arguments* a)
-  {
-    append_singleline_part_to_buffer("(");
-    if (!a->empty()) {
-      (*a)[0]->perform(this);
-      for (size_t i = 1, L = a->length(); i < L; ++i) {
-        append_singleline_part_to_buffer(",");
-        (*a)[i]->perform(this);
-      }
-    }
-    append_singleline_part_to_buffer(")");
-  }
-
-  void Output_Compressed::operator()(Complex_Selector* c)
-  {
-    Compound_Selector*           head = c->head();
-    Complex_Selector*            tail = c->tail();
-    Complex_Selector::Combinator comb = c->combinator();
-    if (head && head->is_empty_reference() && tail)
-    {
-      tail->perform(this);
-      return;
-    }
-    if (head && !head->is_empty_reference()) head->perform(this);
-    switch (comb) {
-      case Complex_Selector::ANCESTOR_OF:
-        if (tail) append_singleline_part_to_buffer(" ");
-        break;
-      case Complex_Selector::PARENT_OF:
-        append_singleline_part_to_buffer(">");
-        break;
-      case Complex_Selector::PRECEDES:
-        // Apparently need to preserve spaces around this combinator?
-        if (head && !head->is_empty_reference()) append_singleline_part_to_buffer(" ");
-        append_singleline_part_to_buffer("~");
-        if (tail) append_singleline_part_to_buffer(" ");
-        break;
-      case Complex_Selector::ADJACENT_TO:
-        append_singleline_part_to_buffer("+");
-        break;
-    }
-    if (tail) tail->perform(this);
-  }
-
-  void Output_Compressed::operator()(Selector_List* g)
-  {
-    if (g->empty()) return;
-    (*g)[0]->perform(this);
-    for (size_t i = 1, L = g->length(); i < L; ++i) {
-      append_singleline_part_to_buffer(",");
-      (*g)[i]->perform(this);
-    }
-  }
-
-  void Output_Compressed::append_singleline_part_to_buffer(const string& text)
-  {
-    append_to_buffer(text);
-  }
-
-  // compile output implementation
-  template class Output<Output_Compressed>;
-
-}
diff --git a/output_compressed.hpp b/output_compressed.hpp
deleted file mode 100644
index d7374c2d69..0000000000
--- a/output_compressed.hpp
+++ /dev/null
@@ -1,92 +0,0 @@
-#ifndef SASS_OUTPUT_COMPRESSED_H
-#define SASS_OUTPUT_COMPRESSED_H
-
-#include <string>
-#include "output.hpp"
-
-namespace Sass {
-  using namespace std;
-  struct Context;
-
-  class Output_Compressed : public Output<Output_Compressed> {
-    // import all the class-specific methods and override as desired
-    // using Operation_CRTP<void, Output_Compressed>::operator();
-
-    // string buffer;
-    // string rendered_imports;
-    // Context* ctx;
-    bool seen_utf8;
-
-    void fallback_impl(AST_Node* n);
-
-    void append_singleline_part_to_buffer(const string& text);
-
-  public:
-    Output_Compressed(Context* ctx = 0);
-    virtual ~Output_Compressed();
-
-    // statements
-    virtual void operator()(Block*);
-    virtual void operator()(Ruleset*);
-    // virtual void operator()(Propset*);
-    virtual void operator()(Media_Block*);
-    virtual void operator()(At_Rule*);
-    virtual void operator()(Keyframe_Rule*);
-    virtual void operator()(Declaration*);
-    // virtual void operator()(Assignment*);
-    virtual void operator()(Import*);
-    // virtual void operator()(Import_Stub*);
-    // virtual void operator()(Warning*);
-    // virtual void operator()(Error*);
-    // virtual void operator()(Debug*);
-    virtual void operator()(Comment*);
-    // virtual void operator()(If*);
-    // virtual void operator()(For*);
-    // virtual void operator()(Each*);
-    // virtual void operator()(While*);
-    // virtual void operator()(Return*);
-    // virtual void operator()(Extension*);
-    // virtual void operator()(Definition*);
-    // virtual void operator()(Mixin_Call*);
-    // virtual void operator()(Content*);
-    // // expressions
-    virtual void operator()(List*);
-    // virtual void operator()(Binary_Expression*);
-    // virtual void operator()(Unary_Expression*);
-    // virtual void operator()(Function_Call*);
-    // virtual void operator()(Function_Call_Schema*);
-    // virtual void operator()(Variable*);
-    // virtual void operator()(Textual*);
-    // virtual void operator()(Number*);
-    virtual void operator()(Color*);
-    // virtual void operator()(Boolean*);
-    // virtual void operator()(String_Schema*);
-    // virtual void operator()(String_Constant* x);
-    // virtual void operator()(Media_Query*);
-    virtual void operator()(Media_Query_Expression*);
-    virtual void operator()(Null*);
-    // // parameters and arguments
-    // virtual void operator()(Parameter*);
-    // virtual void operator()(Parameters*);
-    virtual void operator()(Argument*);
-    virtual void operator()(Arguments*);
-    // // selectors
-    // virtual void operator()(Selector_Schema*);
-    // virtual void operator()(Selector_Reference*);
-    // virtual void operator()(Selector_Placeholder*);
-    // virtual void operator()(Type_Selector*);
-    // virtual void operator()(Selector_Qualifier*);
-    // virtual void operator()(Attribute_Selector*);
-    // virtual void operator()(Pseudo_Selector*);
-    // virtual void operator()(Wrapped_Selector*);
-    // virtual void operator()(Compound_Selector*);
-    virtual void operator()(Complex_Selector*);
-    virtual void operator()(Selector_List*);
-
-    template <typename U>
-    void fallback(U x) { fallback_impl(x); }
-  };
-
-}
-
-#endif
diff --git a/output_nested.cpp b/output_nested.cpp
deleted file mode 100644
index fb2fcb6c33..0000000000
--- a/output_nested.cpp
+++ /dev/null
@@ -1,471 +0,0 @@
-#include <iostream>
-#include <sstream>
-#include <typeinfo>
-
-#include "ast.hpp"
-#include "util.hpp"
-#include "context.hpp"
-#include "inspect.hpp"
-#include "to_string.hpp"
-#include "output_nested.hpp"
-
-namespace Sass {
-  using namespace std;
-
-  Output_Nested::Output_Nested(bool source_comments, Context* ctx)
-  : Output(ctx),
-    indentation(0),
-    source_comments(source_comments),
-    in_directive(false),
-    in_keyframes(false)
-  { }
-  Output_Nested::~Output_Nested() { }
-
-  inline void Output_Nested::fallback_impl(AST_Node* n)
-  {
-    Inspect i(ctx);
-    n->perform(&i);
-    append_to_buffer(i.get_buffer());
-  }
-
-  void Output_Nested::operator()(Import* imp)
-  {
-    // Inspect insp(ctx);
-    // imp->perform(&insp);
-    // insp.get_buffer();
-    top_imports.push_back(imp);
-  }
-
-  void Output_Nested::operator()(Block* b)
-  {
-    if (!b->is_root()) return;
-    for (size_t i = 0, L = b->length(); i < L; ++i) {
-      size_t old_len = buffer.length();
-      (*b)[i]->perform(this);
-      if (i < L-1 && old_len < buffer.length()) append_to_buffer(ctx->linefeed);
-    }
-  }
-
-  void Output_Nested::operator()(Comment* c)
-  {
-    To_String to_string;
-    string txt = c->text()->perform(&to_string);
-    if (buffer.size() + top_imports.size() == 0) {
-      top_comments.push_back(c);
-    } else {
-      Inspect i(ctx);
-      c->perform(&i);
-      append_to_buffer(i.get_buffer());
-    }
-  }
-
-  void Output_Nested::operator()(Ruleset* r)
-  {
-    Selector* s     = r->selector();
-    Block*    b     = r->block();
-    bool      decls = false;
-
-    // disabled to avoid clang warning [-Wunused-function]
-    // Selector_List* sl = static_cast<Selector_List*>(s);
-
-    // Filter out rulesets that aren't printable (process its children though)
-    if (!Util::isPrintable(r)) {
-      for (size_t i = 0, L = b->length(); i < L; ++i) {
-        Statement* stm = (*b)[i];
-        if (dynamic_cast<Has_Block*>(stm)) {
-          stm->perform(this);
-        }
-      }
-      return;
-    }
-
-    if (b->has_non_hoistable()) {
-      decls = true;
-      indentation += r->tabs();
-      indent();
-      if (source_comments) {
-        stringstream ss;
-        ss << "/* line " << r->pstate().line+1 << ", " << r->pstate().path << " */" << endl;
-        append_to_buffer(ss.str());
-        indent();
-      }
-      s->perform(this);
-      append_to_buffer(" {" + ctx->linefeed);
-      ++indentation;
-      for (size_t i = 0, L = b->length(); i < L; ++i) {
-        Statement* stm = (*b)[i];
-        bool bPrintExpression = true;
-        // Check print conditions
-        if (typeid(*stm) == typeid(Declaration)) {
-          Declaration* dec = static_cast<Declaration*>(stm);
-          if (dec->value()->concrete_type() == Expression::STRING) {
-            String_Constant* valConst = static_cast<String_Constant*>(dec->value());
-            string val(valConst->value());
-            if (val.empty()) {
-              bPrintExpression = false;
-            }
-          }
-          else if (dec->value()->concrete_type() == Expression::LIST) {
-            List* list = static_cast<List*>(dec->value());
-            bool all_invisible = true;
-            for (size_t list_i = 0, list_L = list->length(); list_i < list_L; ++list_i) {
-              Expression* item = (*list)[list_i];
-              if (!item->is_invisible()) all_invisible = false;
-            }
-            if (all_invisible) bPrintExpression = false;
-          }
-        }
-        // Print if OK
-        if (!stm->is_hoistable() && bPrintExpression) {
-          if (!stm->block()) indent();
-          stm->perform(this);
-          if (i < L-1) append_to_buffer(ctx->linefeed);
-        }
-      }
-      --indentation;
-      indentation -= r->tabs();
-
-      while (buffer.substr(buffer.length()-ctx->linefeed.length()) == ctx->linefeed) {
-        buffer.erase(buffer.length()-1);
-        if (ctx) ctx->source_map.remove_line();
-      }
-
-      append_to_buffer(" }");
-      if (r->group_end()) append_to_buffer(ctx->linefeed);
-      // Match Sass 3.4.9 behaviour
-      if (in_directive && !in_keyframes) append_to_buffer(ctx->linefeed);
-    }
-
-    if (b->has_hoistable()) {
-      if (decls) ++indentation;
-      // indent();
-      for (size_t i = 0, L = b->length(); i < L; ++i) {
-        Statement* stm = (*b)[i];
-        if (stm->is_hoistable()) {
-          stm->perform(this);
-        }
-      }
-      if (decls) --indentation;
-    }
-  }
-
-  void Output_Nested::operator()(Keyframe_Rule* r)
-  {
-    String* v       = r->rules();
-    Block*  b       = r->block();
-    bool    decls   = false;
-
-    // indent();
-    if (v) {
-      append_to_buffer(" ");
-      v->perform(this);
-    }
-
-    if (!b) {
-      append_to_buffer(";");
-      return;
-    }
-
-    append_to_buffer(" {" + ctx->linefeed);
-
-    bool old_in_directive = in_directive;
-    in_directive = true;
-
-    ++indentation;
-    decls = true;
-    for (size_t i = 0, L = b->length(); i < L; ++i) {
-      Statement* stm = (*b)[i];
-      if (!stm->is_hoistable()) {
-        if (!stm->block()) indent();
-        stm->perform(this);
-        append_to_buffer(ctx->linefeed);
-      }
-    }
-    --indentation;
-
-    if (decls) ++indentation;
-    for (size_t i = 0, L = b->length(); i < L; ++i) {
-      Statement* stm = (*b)[i];
-      if (stm->is_hoistable()) {
-        stm->perform(this);
-        // append_to_buffer(ctx->linefeed);
-      }
-    }
-    if (decls) --indentation;
-
-    while (buffer.substr(buffer.length()-ctx->linefeed.length()) == ctx->linefeed) {
-      buffer.erase(buffer.length()-1);
-      if (ctx) ctx->source_map.remove_line();
-    }
-
-    in_directive = old_in_directive;
-
-    append_to_buffer(" }");
-  }
-
-  void Output_Nested::operator()(Feature_Block* f)
-  {
-    if (f->is_invisible()) return;
-
-    Feature_Query* q    = f->feature_queries();
-    Block* b            = f->block();
-
-    // Filter out feature blocks that aren't printable (process its children though)
-    if (!Util::isPrintable(f)) {
-      for (size_t i = 0, L = b->length(); i < L; ++i) {
-        Statement* stm = (*b)[i];
-        if (dynamic_cast<Has_Block*>(stm)) {
-          stm->perform(this);
-        }
-      }
-      return;
-    }
-
-    indentation += f->tabs();
-    indent();
-    append_to_buffer("@supports", f);
-    append_to_buffer(" ");
-    q->perform(this);
-    append_to_buffer(" ");
-    append_to_buffer("{");
-    append_to_buffer(ctx->linefeed);
-
-    bool old_in_directive = in_directive;
-    in_directive = true;
-
-    Selector* e = f->selector();
-    if (e && b->has_non_hoistable()) {
-      // JMA - hoisted, output the non-hoistable in a nested block, followed by the hoistable
-      ++indentation;
-      indent();
-      e->perform(this);
-      append_to_buffer(" {" + ctx->linefeed);
-
-      ++indentation;
-      for (size_t i = 0, L = b->length(); i < L; ++i) {
-        Statement* stm = (*b)[i];
-        if (!stm->is_hoistable()) {
-          if (!stm->block()) indent();
-          stm->perform(this);
-          if (i < L-1) append_to_buffer(ctx->linefeed);
-        }
-      }
-      --indentation;
-
-      in_directive = old_in_directive;
-
-      // buffer.erase(buffer.length()-1);
-      // if (ctx) ctx->source_map.remove_line();
-      append_to_buffer(" }" + ctx->linefeed);
-      --indentation;
-
-      ++indentation;
-      ++indentation;
-      for (size_t i = 0, L = b->length(); i < L; ++i) {
-        Statement* stm = (*b)[i];
-        if (stm->is_hoistable()) {
-          stm->perform(this);
-        }
-      }
-      --indentation;
-      --indentation;
-    }
-    else {
-      // JMA - not hoisted, just output in order
-      ++indentation;
-      for (size_t i = 0, L = b->length(); i < L; ++i) {
-        Statement* stm = (*b)[i];
-        if (!stm->is_hoistable()) {
-          if (!stm->block()) indent();
-        }
-        stm->perform(this);
-        if (!stm->is_hoistable()) append_to_buffer(ctx->linefeed);
-      }
-      --indentation;
-    }
-
-    while (buffer.substr(buffer.length()-ctx->linefeed.length()) == ctx->linefeed) {
-      buffer.erase(buffer.length()-1);
-      if (ctx) ctx->source_map.remove_line();
-    }
-
-    in_directive = old_in_directive;
-
-    append_to_buffer(" }");
-    if (f->group_end() || in_directive) append_to_buffer(ctx->linefeed);
-
-    indentation -= f->tabs();
-  }
-
-  void Output_Nested::operator()(Media_Block* m)
-  {
-    if (m->is_invisible()) return;
-
-    List*  q     = m->media_queries();
-    Block* b     = m->block();
-
-    // Filter out media blocks that aren't printable (process its children though)
-    if (!Util::isPrintable(m)) {
-      for (size_t i = 0, L = b->length(); i < L; ++i) {
-        Statement* stm = (*b)[i];
-        if (dynamic_cast<Has_Block*>(stm)) {
-          stm->perform(this);
-        }
-      }
-      return;
-    }
-
-    indentation += m->tabs();
-    indent();
-    append_to_buffer("@media", m);
-    append_to_buffer(" ");
-    q->perform(this);
-    append_to_buffer(" ");
-    append_to_buffer("{");
-    append_to_buffer(ctx->linefeed);
-
-    bool old_in_directive = in_directive;
-    in_directive = true;
-
-    Selector* e = m->selector();
-    if (e && b->has_non_hoistable()) {
-      // JMA - hoisted, output the non-hoistable in a nested block, followed by the hoistable
-      ++indentation;
-      indent();
-      e->perform(this);
-      append_to_buffer(" {" + ctx->linefeed);
-
-      ++indentation;
-      for (size_t i = 0, L = b->length(); i < L; ++i) {
-        Statement* stm = (*b)[i];
-        if (!stm->is_hoistable()) {
-          if (!stm->block()) indent();
-          stm->perform(this);
-          if (i < L-1) append_to_buffer(ctx->linefeed);
-        }
-      }
-      --indentation;
-
-      in_directive = old_in_directive;
-
-      // buffer.erase(buffer.length()-1);
-      // if (ctx) ctx->source_map.remove_line();
-      append_to_buffer(" }" + ctx->linefeed);
-      --indentation;
-
-      ++indentation;
-      ++indentation;
-      for (size_t i = 0, L = b->length(); i < L; ++i) {
-        Statement* stm = (*b)[i];
-        if (stm->is_hoistable()) {
-          stm->perform(this);
-        }
-      }
-      --indentation;
-      --indentation;
-    }
-    else {
-      // JMA - not hoisted, just output in order
-      ++indentation;
-      for (size_t i = 0, L = b->length(); i < L; ++i) {
-        Statement* stm = (*b)[i];
-        if (!stm->is_hoistable()) {
-          if (!stm->block()) indent();
-        }
-        stm->perform(this);
-        if (!stm->is_hoistable()) append_to_buffer(ctx->linefeed);
-      }
-      --indentation;
-    }
-
-    while (buffer.substr(buffer.length()-ctx->linefeed.length()) == ctx->linefeed) {
-      buffer.erase(buffer.length()-1);
-      if (ctx) ctx->source_map.remove_line();
-    }
-
-    in_directive = old_in_directive;
-
-    append_to_buffer(" }");
-    if (m->group_end() || in_directive) append_to_buffer(ctx->linefeed);
-
-    indentation -= m->tabs();
-  }
-
-  void Output_Nested::operator()(At_Rule* a)
-  {
-    string      kwd   = a->keyword();
-    Selector*   s     = a->selector();
-    Expression* v     = a->value();
-    Block*      b     = a->block();
-    bool        decls = false;
-
-    // indent();
-    append_to_buffer(kwd);
-    if (s) {
-      append_to_buffer(" ");
-      s->perform(this);
-    }
-    else if (v) {
-      append_to_buffer(" ");
-      v->perform(this);
-    }
-
-    if (!b) {
-      append_to_buffer(";");
-      return;
-    }
-
-    append_to_buffer(" {" + ctx->linefeed);
-
-    bool old_in_directive = in_directive;
-    in_directive = true;
-    in_keyframes = kwd.compare("@keyframes") == 0;
-
-    ++indentation;
-    decls = true;
-    for (size_t i = 0, L = b->length(); i < L; ++i) {
-      Statement* stm = (*b)[i];
-      if (!stm->is_hoistable()) {
-        if (!stm->block()) indent();
-        stm->perform(this);
-        append_to_buffer(ctx->linefeed);
-      }
-    }
-    --indentation;
-
-    if (decls) ++indentation;
-    for (size_t i = 0, L = b->length(); i < L; ++i) {
-      Statement* stm = (*b)[i];
-      if (stm->is_hoistable()) {
-        stm->perform(this);
-        // append_to_buffer(ctx->linefeed);
-      }
-    }
-    if (decls) --indentation;
-
-    while (buffer.substr(buffer.length()-ctx->linefeed.length()) == ctx->linefeed) {
-      buffer.erase(buffer.length()-1);
-      if (ctx) ctx->source_map.remove_line();
-    }
-
-    in_directive = old_in_directive;
-    in_keyframes = false;
-
-    append_to_buffer(" }");
-
-    // Match Sass 3.4.9 behaviour
-    if (kwd.compare("@font-face") != 0 && kwd.compare("@keyframes") != 0) append_to_buffer(ctx->linefeed);
-  }
-
-  void Output_Nested::indent()
-  {
-    string indent = "";
-    for (size_t i = 0; i < indentation; i++)
-      indent += ctx->indent;
-    append_to_buffer(indent);
-  }
-
-  // compile output implementation
-  template class Output<Output_Nested>;
-
-}
diff --git a/output_nested.hpp b/output_nested.hpp
deleted file mode 100644
index eaa13e367b..0000000000
--- a/output_nested.hpp
+++ /dev/null
@@ -1,99 +0,0 @@
-#ifndef SASS_OUTPUT_NESTED_H
-#define SASS_OUTPUT_NESTED_H
-
-#include <string>
-#include "output.hpp"
-
-namespace Sass {
-  using namespace std;
-  struct Context;
-
-  class Output_Nested : public Output<Output_Nested> {
-
-    size_t indentation;
-    bool source_comments;
-    bool in_directive;
-    bool in_keyframes;
-    void indent();
-
-    void fallback_impl(AST_Node* n);
-
-  public:
-
-    Output_Nested(bool source_comments = false, Context* ctx = 0);
-    virtual ~Output_Nested();
-
-    string get_buffer()
-    {
-      // call parent method for result
-      return Output<Output_Nested>::get_buffer();
-    }
-
-    // statements
-    virtual void operator()(Block*);
-    virtual void operator()(Ruleset*);
-    // virtual void operator()(Propset*);
-    virtual void operator()(Feature_Block*);
-    virtual void operator()(Media_Block*);
-    virtual void operator()(At_Rule*);
-    virtual void operator()(Keyframe_Rule*);
-    // virtual void operator()(Declaration*);
-    // virtual void operator()(Assignment*);
-    virtual void operator()(Import*);
-    // virtual void operator()(Import_Stub*);
-    // virtual void operator()(Warning*);
-    // virtual void operator()(Error*);
-    // virtual void operator()(Debug*);
-    virtual void operator()(Comment*);
-    // virtual void operator()(If*);
-    // virtual void operator()(For*);
-    // virtual void operator()(Each*);
-    // virtual void operator()(While*);
-    // virtual void operator()(Return*);
-    // virtual void operator()(Extension*);
-    // virtual void operator()(Definition*);
-    // virtual void operator()(Mixin_Call*);
-    // virtual void operator()(Content*);
-    // // expressions
-    // virtual void operator()(List*);
-    // virtual void operator()(Binary_Expression*);
-    // virtual void operator()(Unary_Expression*);
-    // virtual void operator()(Function_Call*);
-    // virtual void operator()(Function_Call_Schema*);
-    // virtual void operator()(Variable*);
-    // virtual void operator()(Textual*);
-    // virtual void operator()(Number*);
-    // virtual void operator()(Color*);
-    // virtual void operator()(Boolean*);
-    // virtual void operator()(String_Schema*);
-    // virtual void operator()(String_Constant* x);
-    // virtual void operator()(Media_Query*);
-    // virtual void operator()(Media_Query_Expression*);
-    // // parameters and arguments
-    // virtual void operator()(Parameter*);
-    // virtual void operator()(Parameters*);
-    // virtual void operator()(Argument*);
-    // virtual void operator()(Arguments*);
-    // // selectors
-    // virtual void operator()(Selector_Schema*);
-    // virtual void operator()(Selector_Reference*);
-    // virtual void operator()(Selector_Placeholder*);
-    // virtual void operator()(Type_Selector*);
-    // virtual void operator()(Selector_Qualifier*);
-    // virtual void operator()(Attribute_Selector*);
-    // virtual void operator()(Pseudo_Selector*);
-    // virtual void operator()(Wrapped_Selector*);
-    // virtual void operator()(Compound_Selector*);
-    // virtual void operator()(Complex_Selector*);
-    // virtual void operator()(Selector_List*);
-
-    template <typename U>
-    void fallback(U x) { fallback_impl(x); }
-  };
-
-  string unquote(const string&);
-  string quote(const string&, char);
-
-}
-
-#endif
diff --git a/parser.cpp b/parser.cpp
index 7d632e6548..39b15879c0 100644
--- a/parser.cpp
+++ b/parser.cpp
@@ -25,13 +25,26 @@ namespace Sass {
     return p;
   }
 
+  Parser Parser::from_c_str(const char* beg, const char* end, Context& ctx, ParserState pstate)
+  {
+    Parser p(ctx, pstate);
+    p.source   = beg;
+    p.position = p.source;
+    p.end      = end;
+    return p;
+  }
+
+  bool Parser::peek_newline(const char* start)
+  {
+    return peek_linefeed(start ? start : position);
+  }
+
   Parser Parser::from_token(Token t, Context& ctx, ParserState pstate)
   {
     Parser p(ctx, pstate);
     p.source   = t.begin;
     p.position = p.source;
     p.end      = t.end;
-    p.dequote  = true;
     return p;
   }
 
@@ -44,8 +57,9 @@ namespace Sass {
     Selector_Lookahead lookahead_result;
     while (position < end) {
       if (lex< block_comment >()) {
+        bool is_important = lexed.begin[2] == '!';
         String*  contents = parse_interpolated_chunk(lexed);
-        Comment* comment  = new (ctx.mem) Comment(pstate, contents);
+        Comment* comment  = new (ctx.mem) Comment(pstate, contents, is_important);
         (*root) << comment;
       }
       else if (peek< import >()) {
@@ -65,9 +79,9 @@ namespace Sass {
         (*root) << parse_assignment();
         if (!lex< one_plus< exactly<';'> > >()) error("top-level variable binding must be terminated by ';'", pstate);
       }
-      else if (peek< sequence< optional< exactly<'*'> >, alternatives< identifier_schema, identifier >, optional_spaces, exactly<':'>, optional_spaces, exactly<'{'> > >(position)) {
+      /*else if (peek< sequence< optional< exactly<'*'> >, alternatives< identifier_schema, identifier >, optional_spaces, exactly<':'>, optional_spaces, exactly<'{'> > >(position)) {
         (*root) << parse_propset();
-      }
+      }*/
       else if (peek< include >() /* || peek< exactly<'+'> >() */) {
         Mixin_Call* mixin_call = parse_mixin_call();
         (*root) << mixin_call;
@@ -142,7 +156,7 @@ namespace Sass {
     }
 
     if (extension == ".css") {
-      String_Constant* loc = new (ctx.mem) String_Constant(pstate, import_path, true);
+      String_Constant* loc = new (ctx.mem) String_Constant(pstate, unquote(import_path));
       Argument* loc_arg = new (ctx.mem) Argument(pstate, loc);
       Arguments* loc_args = new (ctx.mem) Arguments(pstate);
       (*loc_args) << loc_arg;
@@ -211,7 +225,7 @@ namespace Sass {
             !unquote(import_path).substr(0, 8).compare("https://") ||
             !unquote(import_path).substr(0, 2).compare("//"))
         {
-          imp->urls().push_back(new (ctx.mem) String_Constant(pstate, import_path));
+          imp->urls().push_back(new (ctx.mem) String_Quoted(pstate, import_path));
         }
         else {
           add_single_file(imp, import_path);
@@ -360,6 +374,7 @@ namespace Sass {
     return var;
   }
 
+  /* not used anymore - remove?
   Propset* Parser::parse_propset()
   {
     String* property_segment;
@@ -368,17 +383,20 @@ namespace Sass {
     }
     else {
       lex< sequence< optional< exactly<'*'> >, identifier > >();
-      property_segment = new (ctx.mem) String_Constant(pstate, lexed);
+      property_segment = new (ctx.mem) String_Quoted(pstate, lexed);
     }
     Propset* propset = new (ctx.mem) Propset(pstate, property_segment);
+    // debug_ast(property_segment);
     lex< exactly<':'> >();
 
     if (!peek< exactly<'{'> >()) error("expected a '{' after namespaced property", pstate);
 
     propset->block(parse_block());
 
+    propset->tabs(indentation);
+
     return propset;
-  }
+  } */
 
   Ruleset* Parser::parse_ruleset(Selector_Lookahead lookahead)
   {
@@ -404,23 +422,23 @@ namespace Sass {
   {
     lex< optional_spaces >();
     const char* i = position;
-    const char* p;
     String_Schema* schema = new (ctx.mem) String_Schema(pstate);
-
     while (i < end_of_selector) {
-      p = find_first_in_interval< exactly<hash_lbrace> >(i, end_of_selector);
-      if (p) {
-        // accumulate the preceding segment if there is one
-        if (i < p) (*schema) << new (ctx.mem) String_Constant(pstate, Token(i, p, Position(0, 0)));
-        // find the end of the interpolant and parse it
-        const char* j = find_first_in_interval< exactly<rbrace> >(p, end_of_selector);
-        Expression* interp_node = Parser::from_token(Token(p+2, j, Position(0, 0)), ctx, pstate).parse_list();
-        interp_node->is_interpolant(true);
-        (*schema) << interp_node;
-        i = j + 1;
-      }
-      else { // no interpolants left; add the last segment if there is one
-        if (i < end_of_selector) (*schema) << new (ctx.mem) String_Constant(pstate, Token(i, end_of_selector, Position(0, 0)));
+      // try to parse mutliple interpolants
+      if (const char* p = find_first_in_interval< exactly<hash_lbrace> >(i, end_of_selector)) {
+        // accumulate the preceding segment if the position has advanced
+        if (i < p) (*schema) << new (ctx.mem) String_Quoted(pstate, string(i, p));
+        // skip to the delimiter by skipping occurences in quoted strings
+        const char* j = skip_over_scopes< exactly<hash_lbrace>, exactly<rbrace> >(p + 2, end_of_selector);
+        Expression* interpolant = Parser::from_c_str(p+2, j, ctx, pstate).parse_list();
+        interpolant->is_interpolant(true);
+        (*schema) << interpolant;
+        i = j;
+      }
+      // no more interpolants have been found
+      // add the last segment if there is one
+      else {
+        if (i < end_of_selector) (*schema) << new (ctx.mem) String_Quoted(pstate, string(i, end_of_selector));
         break;
       }
     }
@@ -430,10 +448,12 @@ namespace Sass {
 
   Selector_List* Parser::parse_selector_group()
   {
-    To_String to_string;
+    bool reloop = true;
+    To_String to_string(&ctx);
     lex< optional_spaces_and_comments >();
     Selector_List* group = new (ctx.mem) Selector_List(pstate);
     do {
+      reloop = false;
       if (peek< exactly<'{'> >() ||
           peek< exactly<'}'> >() ||
           peek< exactly<')'> >() ||
@@ -453,17 +473,28 @@ namespace Sass {
           comb = new (ctx.mem) Complex_Selector(sel_source_position, Complex_Selector::ANCESTOR_OF, ref_wrap, comb);
           comb->has_reference(true);
         }
+        if (peek_newline()) ref_wrap->has_line_break(true);
+      }
+      while (peek< sequence< optional_spaces_and_comments, exactly<','> > >())
+      {
+        // consume everything up and including the comma speparator
+        reloop = lex< sequence< optional_spaces_and_comments, exactly<','> > >();
+        // remember line break (also between some commas)
+        if (peek_newline()) comb->has_line_feed(true);
+        if (comb->tail() && peek_newline()) comb->tail()->has_line_feed(true);
+        if (comb->tail() && comb->tail()->head() && peek_newline()) comb->tail()->head()->has_line_feed(true);
+        // remember line break (also between some commas)
       }
       (*group) << comb;
     }
-    while (lex< one_plus< sequence< optional_spaces_and_comments, exactly<','> > > >());
+    while (reloop);
     while (lex< optional >());    // JMA - ignore optional flag if it follows the selector group
     return group;
   }
 
   Complex_Selector* Parser::parse_selector_combination()
   {
-    lex< optional_spaces_and_comments >();
+    // lex< optional_spaces_and_comments >();
     Position sel_source_position(-1);
     Compound_Selector* lhs;
     if (peek< exactly<'+'> >() ||
@@ -475,6 +506,7 @@ namespace Sass {
     else {
       lhs = parse_simple_selector_sequence();
       sel_source_position = before_token;
+      lhs->has_line_break(peek_newline());
     }
 
     Complex_Selector::Combinator cmb;
@@ -482,6 +514,7 @@ namespace Sass {
     else if (lex< exactly<'~'> >()) cmb = Complex_Selector::PRECEDES;
     else if (lex< exactly<'>'> >()) cmb = Complex_Selector::PARENT_OF;
     else                            cmb = Complex_Selector::ANCESTOR_OF;
+    bool cpx_lf = peek_newline();
 
     Complex_Selector* rhs;
     if (peek< exactly<','> >() ||
@@ -498,7 +531,9 @@ namespace Sass {
       sel_source_position = before_token;
     }
     if (!sel_source_position.line) sel_source_position = before_token;
-    return new (ctx.mem) Complex_Selector(ParserState(path, sel_source_position, Offset(0, 0)), cmb, lhs, rhs);
+    Complex_Selector* cpx = new (ctx.mem) Complex_Selector(ParserState(path, sel_source_position, Offset(0, 0)), cmb, lhs, rhs);
+    if (cpx_lf) cpx->has_line_break(cpx_lf);
+    return cpx;
   }
 
   Compound_Selector* Parser::parse_simple_selector_sequence()
@@ -510,13 +545,13 @@ namespace Sass {
       (*seq) << new (ctx.mem) Selector_Reference(pstate);
       sawsomething = true;
       // if you see a space after a &, then you're done
-      if(lex< spaces >()) {
+      if(peek< spaces >()) {
         return seq;
       }
     }
     if (sawsomething && lex< sequence< negate< functional >, alternatives< identifier_fragment, universal, quoted_string, dimension, percentage, number > > >()) {
       // saw an ampersand, then allow type selectors with arbitrary number of hyphens at the beginning
-      (*seq) << new (ctx.mem) Type_Selector(pstate, lexed);
+      (*seq) << new (ctx.mem) Type_Selector(pstate, unquote(lexed));
     } else if (lex< sequence< negate< functional >, alternatives< type_selector, universal, quoted_string, dimension, percentage, number > > >()) {
       // if you see a type selector
       (*seq) << new (ctx.mem) Type_Selector(pstate, lexed);
@@ -544,10 +579,10 @@ namespace Sass {
   Simple_Selector* Parser::parse_simple_selector()
   {
     if (lex< id_name >() || lex< class_name >()) {
-      return new (ctx.mem) Selector_Qualifier(pstate, lexed);
+      return new (ctx.mem) Selector_Qualifier(pstate, unquote(lexed));
     }
     else if (lex< quoted_string >() || lex< number >()) {
-      return new (ctx.mem) Type_Selector(pstate, lexed);
+      return new (ctx.mem) Type_Selector(pstate, unquote(lexed));
     }
     else if (peek< pseudo_not >()) {
       return parse_negated_selector();
@@ -559,7 +594,7 @@ namespace Sass {
       return parse_attribute_selector();
     }
     else if (lex< placeholder >()) {
-      return new (ctx.mem) Selector_Placeholder(pstate, lexed);
+      return new (ctx.mem) Selector_Placeholder(pstate, unquote(lexed));
     }
     else {
       error("invalid selector after " + lexed.to_string(), pstate);
@@ -587,16 +622,16 @@ namespace Sass {
       ParserState p = pstate;
       Selector* wrapped = 0;
       if (lex< alternatives< even, odd > >()) {
-        expr = new (ctx.mem) String_Constant(p, lexed);
+        expr = new (ctx.mem) String_Quoted(p, lexed);
       }
       else if (peek< binomial >(position)) {
         lex< sequence< optional< coefficient >, exactly<'n'> > >();
-        String_Constant* var_coef = new (ctx.mem) String_Constant(p, lexed);
+        String_Constant* var_coef = new (ctx.mem) String_Quoted(p, lexed);
         lex< sign >();
-        String_Constant* op = new (ctx.mem) String_Constant(p, lexed);
+        String_Constant* op = new (ctx.mem) String_Quoted(p, lexed);
         // Binary_Expression::Type op = (lexed == "+" ? Binary_Expression::ADD : Binary_Expression::SUB);
         lex< digits >();
-        String_Constant* constant = new (ctx.mem) String_Constant(p, lexed);
+        String_Constant* constant = new (ctx.mem) String_Quoted(p, lexed);
         // expr = new (ctx.mem) Binary_Expression(p, op, var_coef, constant);
         String_Schema* schema = new (ctx.mem) String_Schema(p, 3);
         *schema << var_coef << op << constant;
@@ -610,17 +645,17 @@ namespace Sass {
         lex< sequence< optional<sign>,
                        optional<digits>,
                        exactly<'n'> > >();
-        expr = new (ctx.mem) String_Constant(p, lexed);
+        expr = new (ctx.mem) String_Quoted(p, lexed);
       }
       else if (lex< sequence< optional<sign>, digits > >()) {
-        expr = new (ctx.mem) String_Constant(p, lexed);
+        expr = new (ctx.mem) String_Quoted(p, lexed);
       }
       else if (peek< sequence< identifier, optional_spaces_and_comments, exactly<')'> > >()) {
         lex< identifier >();
-        expr = new (ctx.mem) String_Constant(p, lexed);
+        expr = new (ctx.mem) String_Quoted(p, lexed);
       }
       else if (lex< quoted_string >()) {
-        expr = new (ctx.mem) String_Constant(p, lexed);
+        expr = new (ctx.mem) String_Quoted(p, lexed);
       }
       else if (peek< exactly<')'> >()) {
         expr = new (ctx.mem) String_Constant(p, "");
@@ -635,7 +670,7 @@ namespace Sass {
       return new (ctx.mem) Pseudo_Selector(p, name, expr);
     }
     else if (lex < sequence< pseudo_prefix, identifier > >()) {
-      return new (ctx.mem) Pseudo_Selector(pstate, lexed);
+      return new (ctx.mem) Pseudo_Selector(pstate, unquote(lexed));
     }
     else {
       error("unrecognized pseudo-class or pseudo-element", pstate);
@@ -659,10 +694,10 @@ namespace Sass {
 
     String* value = 0;
     if (lex< identifier >()) {
-      value = new (ctx.mem) String_Constant(p, lexed, true);
+      value = new (ctx.mem) String_Constant(p, lexed);
     }
     else if (lex< quoted_string >()) {
-      value = parse_interpolated_chunk(lexed);
+      value = parse_interpolated_chunk(lexed, true); // needed!
     }
     else {
       error("expected a string constant or identifier in attribute selector for " + name, pstate);
@@ -681,8 +716,9 @@ namespace Sass {
 
     // JMA - ensure that a block containing only block_comments is parsed
     while (lex< block_comment >()) {
+      bool is_important = lexed.begin[2] == '!';
       String*  contents = parse_interpolated_chunk(lexed);
-      Comment* comment  = new (ctx.mem) Comment(pstate, contents);
+      Comment* comment  = new (ctx.mem) Comment(pstate, contents, is_important);
       (*block) << comment;
     }
 
@@ -693,15 +729,17 @@ namespace Sass {
         }
         semicolon = false;
         while (lex< block_comment >()) {
+          bool is_important = lexed.begin[2] == '!';
           String*  contents = parse_interpolated_chunk(lexed);
-          Comment* comment  = new (ctx.mem) Comment(pstate, contents);
+          Comment* comment  = new (ctx.mem) Comment(pstate, contents, is_important);
           (*block) << comment;
         }
         if (lex< sequence< exactly<'}'>, zero_plus< exactly<';'> > > >()) break;
       }
       if (lex< block_comment >()) {
+        bool is_important = lexed.begin[2] == '!';
         String*  contents = parse_interpolated_chunk(lexed);
-        Comment* comment  = new (ctx.mem) Comment(pstate, contents);
+        Comment* comment  = new (ctx.mem) Comment(pstate, contents, is_important);
         (*block) << comment;
       }
       else if (peek< import >(position)) {
@@ -805,23 +843,28 @@ namespace Sass {
       }
       else if ((lookahead_result = lookahead_for_selector(position)).found) {
         (*block) << parse_ruleset(lookahead_result);
-      }
+      }/* not used anymore - remove?
       else if (peek< sequence< optional< exactly<'*'> >, alternatives< identifier_schema, identifier >, optional_spaces, exactly<':'>, optional_spaces, exactly<'{'> > >(position)) {
         (*block) << parse_propset();
-      }
+      }*/
       else if (!peek< exactly<';'> >()) {
+        bool indent = ! peek< sequence< optional< exactly<'*'> >, alternatives< identifier_schema, identifier >, optional_spaces, exactly<':'>, optional_spaces, exactly<'{'> > >(position);
+        /* not used anymore - remove?
         if (peek< sequence< optional< exactly<'*'> >, identifier_schema, exactly<':'>, exactly<'{'> > >()) {
           (*block) << parse_propset();
         }
         else if (peek< sequence< optional< exactly<'*'> >, identifier, exactly<':'>, exactly<'{'> > >()) {
           (*block) << parse_propset();
         }
-        else {
+        else */ {
           Declaration* decl = parse_declaration();
+          decl->tabs(indentation);
           (*block) << decl;
           if (peek< exactly<'{'> >()) {
             // parse a propset that rides on the declaration's property
+            if (indent) indentation++;
             Propset* ps = new (ctx.mem) Propset(pstate, decl->property(), parse_block());
+            if (indent) indentation--;
             (*block) << ps;
           }
           else {
@@ -832,8 +875,9 @@ namespace Sass {
       }
       else lex< one_plus< exactly<';'> > >();
       while (lex< block_comment >()) {
+        bool is_important = lexed.begin[2] == '!';
         String*  contents = parse_interpolated_chunk(lexed);
-        Comment* comment  = new (ctx.mem) Comment(pstate, contents);
+        Comment* comment  = new (ctx.mem) Comment(pstate, contents, is_important);
         (*block) << comment;
       }
     }
@@ -846,10 +890,10 @@ namespace Sass {
       prop = parse_identifier_schema();
     }
     else if (lex< sequence< optional< exactly<'*'> >, identifier > >()) {
-      prop = new (ctx.mem) String_Constant(pstate, lexed);
+      prop = new (ctx.mem) String_Quoted(pstate, lexed);
     }
     else if (lex< custom_property_name >()) {
-      prop = new (ctx.mem) String_Constant(pstate, lexed);
+      prop = new (ctx.mem) String_Quoted(pstate, lexed);
     }
     else {
       error("invalid property name", pstate);
@@ -866,7 +910,7 @@ namespace Sass {
 
   Expression* Parser::parse_map()
   {
-    To_String to_string;
+    To_String to_string(&ctx);
     Expression* key = parse_list();
 
     // it's not a map so return the lexed value as a list value
@@ -1173,8 +1217,9 @@ namespace Sass {
     if (lex< important >())
     { return new (ctx.mem) String_Constant(pstate, "!important"); }
 
-    if (lex< value_schema >())
-    { return Parser::from_token(lexed, ctx, pstate).parse_value_schema(); }
+    const char* stop;
+    if ((stop = peek< value_schema >()))
+    { return parse_value_schema(stop); }
 
     if (lex< sequence< true_val, negate< identifier > > >())
     { return new (ctx.mem) Boolean(pstate, true); }
@@ -1186,9 +1231,9 @@ namespace Sass {
     { return new (ctx.mem) Null(pstate); }
 
     if (lex< identifier >()) {
-      String_Constant* str = new (ctx.mem) String_Constant(pstate, lexed);
+      String_Constant* str = new (ctx.mem) String_Quoted(pstate, lexed);
       // Dont' delay this string if it is a name color. Fixes #652.
-      str->is_delayed(ctx.names_to_colors.count(lexed) == 0);
+      str->is_delayed(ctx.names_to_colors.count(unquote(lexed)) == 0);
       return str;
     }
 
@@ -1214,7 +1259,7 @@ namespace Sass {
 
     // Special case handling for `%` proceeding an interpolant.
     if (lex< sequence< exactly<'%'>, optional< percentage > > >())
-    { return new (ctx.mem) String_Constant(pstate, lexed); }
+    { return new (ctx.mem) String_Quoted(pstate, lexed); }
 
     error("error reading values after " + lexed.to_string(), pstate);
 
@@ -1222,32 +1267,37 @@ namespace Sass {
     return 0;
   }
 
-  String* Parser::parse_interpolated_chunk(Token chunk)
+  // this parses interpolation inside other strings
+  // means the result should later be quoted again
+  String* Parser::parse_interpolated_chunk(Token chunk, bool constant)
   {
     const char* i = chunk.begin;
     // see if there any interpolants
-    const char* p = find_first_in_interval< sequence< negate< exactly<'\\'> >, exactly<hash_lbrace> > >(chunk.begin, chunk.end);
+    const char* p = find_first_in_interval< sequence< negate< exactly<'\\'> >, exactly<hash_lbrace> > >(i, chunk.end);
     if (!p) {
-      String_Constant* str_node = new (ctx.mem) String_Constant(pstate, chunk, dequote);
-      str_node->is_delayed(true);
-      return str_node;
+      String_Quoted* str_quoted = new (ctx.mem) String_Quoted(pstate, string(i, chunk.end));
+      if (!constant && str_quoted->quote_mark()) str_quoted->quote_mark('*');
+      str_quoted->is_delayed(true);
+      return str_quoted;
     }
 
     String_Schema* schema = new (ctx.mem) String_Schema(pstate);
-    schema->quote_mark(*chunk.begin);
     while (i < chunk.end) {
       p = find_first_in_interval< sequence< negate< exactly<'\\'> >, exactly<hash_lbrace> > >(i, chunk.end);
       if (p) {
         if (i < p) {
-          (*schema) << new (ctx.mem) String_Constant(pstate, Token(i, p, before_token)); // accumulate the preceding segment if it's nonempty
+          // accumulate the preceding segment if it's nonempty
+          (*schema) << new (ctx.mem) String_Quoted(pstate, string(i, p));
         }
-        const char* j = find_first_in_interval< exactly<rbrace> >(p, chunk.end); // find the closing brace
-        if (j) {
+        // we need to skip anything inside strings
+        // create a new target in parser/prelexer
+        const char* j = skip_over_scopes< exactly<hash_lbrace>, exactly<rbrace> >(p + 2, chunk.end); // find the closing brace
+        if (j) { --j;
           // parse the interpolant and accumulate it
           Expression* interp_node = Parser::from_token(Token(p+2, j, before_token), ctx, pstate).parse_list();
           interp_node->is_interpolant(true);
           (*schema) << interp_node;
-          i = j+1;
+          i = j;
         }
         else {
           // throw an error if the interpolant is unterminated
@@ -1255,9 +1305,11 @@ namespace Sass {
         }
       }
       else { // no interpolants left; add the last segment if nonempty
-        if (i < chunk.end) (*schema) << new (ctx.mem) String_Constant(pstate, Token(i, chunk.end, before_token));
+        // check if we need quotes here (was not sure after merge)
+        if (i < chunk.end) (*schema) << new (ctx.mem) String_Quoted(pstate, string(i, chunk.end));
         break;
       }
+      ++ i;
     }
     return schema;
   }
@@ -1269,51 +1321,15 @@ namespace Sass {
     --str.end;
     --position;
     String_Constant* str_node = new (ctx.mem) String_Constant(pstate, str);
-    str_node->is_delayed(true);
+    // str_node->is_delayed(true);
     return str_node;
   }
 
   String* Parser::parse_string()
   {
     lex< quoted_string >();
-    Token str(lexed);
-    return parse_interpolated_chunk(str);
-    // const char* i = str.begin;
-    // // see if there any interpolants
-    // const char* p = find_first_in_interval< sequence< negate< exactly<'\\'> >, exactly<hash_lbrace> > >(str.begin, str.end);
-    // if (!p) {
-    //   String_Constant* str_node = new (ctx.mem) String_Constant(pstate, str);
-    //   str_node->is_delayed(true);
-    //   return str_node;
-    // }
-
-    // String_Schema* schema = new (ctx.mem) String_Schema(pstate);
-    // schema->quote_mark(*str.begin);
-    // while (i < str.end) {
-    //   p = find_first_in_interval< sequence< negate< exactly<'\\'> >, exactly<hash_lbrace> > >(i, str.end);
-    //   if (p) {
-    //     if (i < p) {
-    //       (*schema) << new (ctx.mem) String_Constant(pstate, Token(i, p)); // accumulate the preceding segment if it's nonempty
-    //     }
-    //     const char* j = find_first_in_interval< exactly<rbrace> >(p, str.end); // find the closing brace
-    //     if (j) {
-    //       // parse the interpolant and accumulate it
-    //       Expression* interp_node = Parser::from_token(Token(p+2, j), ctx, pstate).parse_list();
-    //       interp_node->is_interpolant(true);
-    //       (*schema) << interp_node;
-    //       i = j+1;
-    //     }
-    //     else {
-    //       // throw an error if the interpolant is unterminated
-    //       error("unterminated interpolant inside string constant " + str.to_string(), pstate);
-    //     }
-    //   }
-    //   else { // no interpolants left; add the last segment if nonempty
-    //     if (i < str.end) (*schema) << new (ctx.mem) String_Constant(pstate, Token(i, str.end));
-    //     break;
-    //   }
-    // }
-    // return schema;
+    Token token(lexed);
+    return parse_interpolated_chunk(token);
   }
 
   String* Parser::parse_ie_property()
@@ -1324,7 +1340,7 @@ namespace Sass {
     // see if there any interpolants
     const char* p = find_first_in_interval< sequence< negate< exactly<'\\'> >, exactly<hash_lbrace> > >(str.begin, str.end);
     if (!p) {
-      String_Constant* str_node = new (ctx.mem) String_Constant(pstate, str);
+      String_Constant* str_node = new (ctx.mem) String_Constant(pstate, normalize_wspace(string(str.begin, str.end)));
       str_node->is_delayed(true);
       return str_node;
     }
@@ -1334,15 +1350,15 @@ namespace Sass {
       p = find_first_in_interval< sequence< negate< exactly<'\\'> >, exactly<hash_lbrace> > >(i, str.end);
       if (p) {
         if (i < p) {
-          (*schema) << new (ctx.mem) String_Constant(pstate, Token(i, p, before_token)); // accumulate the preceding segment if it's nonempty
+          (*schema) << new (ctx.mem) String_Constant(pstate, string(i, p)); // accumulate the preceding segment if it's nonempty
         }
-        const char* j = find_first_in_interval< exactly<rbrace> >(p, str.end); // find the closing brace
+        const char* j = skip_over_scopes< exactly<hash_lbrace>, exactly<rbrace> >(p+2, str.end); // find the closing brace
         if (j) {
           // parse the interpolant and accumulate it
           Expression* interp_node = Parser::from_token(Token(p+2, j, before_token), ctx, pstate).parse_list();
           interp_node->is_interpolant(true);
           (*schema) << interp_node;
-          i = j+1;
+          i = j;
         }
         else {
           // throw an error if the interpolant is unterminated
@@ -1350,7 +1366,7 @@ namespace Sass {
         }
       }
       else { // no interpolants left; add the last segment if nonempty
-        if (i < str.end) (*schema) << new (ctx.mem) String_Constant(pstate, Token(i, str.end, before_token));
+        if (i < str.end) (*schema) << new (ctx.mem) String_Constant(pstate, string(i, str.end));
         break;
       }
     }
@@ -1360,27 +1376,27 @@ namespace Sass {
   String* Parser::parse_ie_keyword_arg()
   {
     String_Schema* kwd_arg = new (ctx.mem) String_Schema(pstate, 3);
-    if (lex< variable >()) *kwd_arg << new (ctx.mem) Variable(pstate, Util::normalize_underscores(lexed));
-    else {
+    if (lex< variable >()) {
+      *kwd_arg << new (ctx.mem) Variable(pstate, Util::normalize_underscores(lexed));
+    } else {
       lex< alternatives< identifier_schema, identifier > >();
-      *kwd_arg << new (ctx.mem) String_Constant(pstate, lexed);
+      *kwd_arg << new (ctx.mem) String_Quoted(pstate, lexed);
     }
     lex< exactly<'='> >();
-    *kwd_arg << new (ctx.mem) String_Constant(pstate, lexed);
+    *kwd_arg << new (ctx.mem) String_Quoted(pstate, lexed);
     if (peek< variable >()) *kwd_arg << parse_list();
     else if (lex< number >()) *kwd_arg << new (ctx.mem) Textual(pstate, Textual::NUMBER, Util::normalize_decimals(lexed));
-    else {
-      lex< alternatives< identifier_schema, identifier, number, hex > >();
-      *kwd_arg << new (ctx.mem) String_Constant(pstate, lexed);
+    else if (lex< alternatives< identifier_schema, identifier, number, hexa, hex > >()) {
+      *kwd_arg << new (ctx.mem) String_Quoted(pstate, lexed);
     }
     return kwd_arg;
   }
 
-  String_Schema* Parser::parse_value_schema()
+  String_Schema* Parser::parse_value_schema(const char* stop)
   {
     String_Schema* schema = new (ctx.mem) String_Schema(pstate);
     size_t num_items = 0;
-    while (position < end) {
+    while (position < stop) {
       if (lex< interpolant >()) {
         Token insides(Token(lexed.begin + 2, lexed.end - 1, before_token));
         Expression* interp_node = Parser::from_token(insides, ctx, pstate).parse_list();
@@ -1391,7 +1407,7 @@ namespace Sass {
         (*schema) << new (ctx.mem) String_Constant(pstate, lexed);
       }
       else if (lex< identifier >()) {
-        (*schema) << new (ctx.mem) String_Constant(pstate, lexed);
+        (*schema) << new (ctx.mem) String_Quoted(pstate, lexed);
       }
       else if (lex< percentage >()) {
         (*schema) << new (ctx.mem) Textual(pstate, Textual::PERCENTAGE, lexed);
@@ -1403,11 +1419,10 @@ namespace Sass {
         (*schema) << new (ctx.mem) Textual(pstate, Textual::NUMBER, lexed);
       }
       else if (lex< hex >()) {
-        (*schema) << new (ctx.mem) Textual(pstate, Textual::HEX, lexed);
+        (*schema) << new (ctx.mem) Textual(pstate, Textual::HEX, unquote(lexed));
       }
       else if (lex< quoted_string >()) {
         (*schema) << new (ctx.mem) String_Constant(pstate, lexed);
-        if (!num_items) schema->quote_mark(*lexed.begin);
       }
       else if (lex< variable >()) {
         (*schema) << new (ctx.mem) Variable(pstate, Util::normalize_underscores(lexed));
@@ -1420,6 +1435,7 @@ namespace Sass {
     return schema;
   }
 
+  /* not used anymore - remove?
   String_Schema* Parser::parse_url_schema()
   {
     String_Schema* schema = new (ctx.mem) String_Schema(pstate);
@@ -1427,7 +1443,7 @@ namespace Sass {
     while (position < end) {
       if (position[0] == '/') {
         lexed = Token(position, position+1, before_token);
-        (*schema) << new (ctx.mem) String_Constant(pstate, lexed);
+        (*schema) << new (ctx.mem) String_Quoted(pstate, lexed);
         ++position;
       }
       else if (lex< interpolant >()) {
@@ -1437,27 +1453,30 @@ namespace Sass {
         (*schema) << interp_node;
       }
       else if (lex< sequence< identifier, exactly<':'> > >()) {
-        (*schema) << new (ctx.mem) String_Constant(pstate, lexed);
+        (*schema) << new (ctx.mem) String_Quoted(pstate, lexed);
       }
       else if (lex< filename >()) {
-        (*schema) << new (ctx.mem) String_Constant(pstate, lexed);
+        (*schema) << new (ctx.mem) String_Quoted(pstate, lexed);
       }
       else {
         error("error parsing interpolated url", pstate);
       }
     }
     return schema;
-  }
+  } */
 
+  // this parses interpolation outside other strings
+  // means the result must not be quoted again later
   String* Parser::parse_identifier_schema()
   {
+    // first lex away whatever we have found
     lex< sequence< optional< exactly<'*'> >, identifier_schema > >();
     Token id(lexed);
     const char* i = id.begin;
     // see if there any interpolants
     const char* p = find_first_in_interval< sequence< negate< exactly<'\\'> >, exactly<hash_lbrace> > >(id.begin, id.end);
     if (!p) {
-      return new (ctx.mem) String_Constant(pstate, id);
+      return new (ctx.mem) String_Quoted(pstate, string(id.begin, id.end));
     }
 
     String_Schema* schema = new (ctx.mem) String_Schema(pstate);
@@ -1465,16 +1484,19 @@ namespace Sass {
       p = find_first_in_interval< sequence< negate< exactly<'\\'> >, exactly<hash_lbrace> > >(i, id.end);
       if (p) {
         if (i < p) {
-          (*schema) << new (ctx.mem) String_Constant(pstate, Token(i, p, before_token)); // accumulate the preceding segment if it's nonempty
+          // accumulate the preceding segment if it's nonempty
+          (*schema) << new (ctx.mem) String_Constant(pstate, string(i, p));
         }
-        const char* j = find_first_in_interval< exactly<rbrace> >(p, id.end); // find the closing brace
+        // we need to skip anything inside strings
+        // create a new target in parser/prelexer
+        const char* j = skip_over_scopes< exactly<hash_lbrace>, exactly<rbrace> >(p+2, id.end); // find the closing brace
         if (j) {
           // parse the interpolant and accumulate it
           Expression* interp_node = Parser::from_token(Token(p+2, j, before_token), ctx, pstate).parse_list();
           interp_node->is_interpolant(true);
           (*schema) << interp_node;
           schema->has_interpolants(true);
-          i = j+1;
+          i = j;
         }
         else {
           // throw an error if the interpolant is unterminated
@@ -1482,7 +1504,7 @@ namespace Sass {
         }
       }
       else { // no interpolants left; add the last segment if nonempty
-        if (i < id.end) (*schema) << new (ctx.mem) String_Constant(pstate, Token(i, id.end, before_token));
+        if (i < end) (*schema) << new (ctx.mem) String_Quoted(pstate, string(i, id.end));
         break;
       }
     }
@@ -1637,7 +1659,7 @@ namespace Sass {
     else if (lex< exactly< only_kwd > >()) media_query->is_restricted(true);
 
     if (peek< identifier_schema >()) media_query->media_type(parse_identifier_schema());
-    else if (lex< identifier >())    media_query->media_type(new (ctx.mem) String_Constant(pstate, lexed));
+    else if (lex< identifier >())    media_query->media_type(new (ctx.mem) String_Quoted(pstate, lexed));
     else                             (*media_query) << parse_media_expression();
 
     while (lex< exactly< and_kwd > >()) (*media_query) << parse_media_expression();
@@ -1792,7 +1814,7 @@ namespace Sass {
 
     if (!peek< alternatives< with_directive, without_directive > >()) {
       const char* i = position;
-      const char* p = peek< until_closing_paren >(i);
+      const char* p = peek< until<')'> >(i);
       Token* t = new Token(i, p, Position(0, 0));
       error("Invalid CSS after \"(\": expected \"with\" or \"without\", was \""+t->to_string()+"\"", pstate);
     }
diff --git a/parser.hpp b/parser.hpp
index ab3c714ed3..fbefbb5c32 100644
--- a/parser.hpp
+++ b/parser.hpp
@@ -6,7 +6,7 @@
 #include <iostream>
 
 #include "ast.hpp"
-#include "token.hpp"
+#include "position.hpp"
 #include "context.hpp"
 #include "position.hpp"
 #include "prelexer.hpp"
@@ -38,19 +38,20 @@ namespace Sass {
     Position before_token;
     Position after_token;
     ParserState pstate;
+    int indentation;
 
 
     Token lexed;
-    bool dequote;
     bool in_at_root;
 
     Parser(Context& ctx, ParserState pstate)
     : ParserState(pstate), ctx(ctx), stack(vector<Syntactic_Context>()),
-      source(0), position(0), end(0), before_token(pstate), after_token(pstate), pstate("[NULL]")
-    { dequote = false; in_at_root = false; stack.push_back(nothing); }
+      source(0), position(0), end(0), before_token(pstate), after_token(pstate), pstate("[NULL]"), indentation(0)
+    { in_at_root = false; stack.push_back(nothing); }
 
-    static Parser from_string(string src, Context& ctx, ParserState pstate = ParserState("[STRING]"));
+    static Parser from_string(const string& src, Context& ctx, ParserState pstate = ParserState("[STRING]"));
     static Parser from_c_str(const char* src, Context& ctx, ParserState pstate = ParserState("[CSTRING]"));
+    static Parser from_c_str(const char* beg, const char* end, Context& ctx, ParserState pstate = ParserState("[CSTRING]"));
     static Parser from_token(Token t, Context& ctx, ParserState pstate = ParserState("[TOKEN]"));
 
 #ifdef __clang__
@@ -65,6 +66,9 @@ namespace Sass {
 
 #endif
 
+
+    bool peek_newline(const char* start = 0);
+
     template <prelexer mx>
     const char* peek(const char* start = 0)
     {
@@ -77,7 +81,7 @@ namespace Sass {
       else if (/*mx == ancestor_of ||*/ mx == no_spaces) {
         it_before_token = position;
       }
-      else if (mx == spaces || mx == ancestor_of) {
+      else if (mx == spaces) {
         it_before_token = mx(start);
         if (it_before_token) {
           return it_before_token;
@@ -111,6 +115,9 @@ namespace Sass {
     const char* lex()
     {
 
+      // remeber interesting position
+      const char* wspace_start = position;
+
       // advance position for next call
       before_token = after_token;
 
@@ -121,7 +128,7 @@ namespace Sass {
         // a block comment can be preceded by spaces and/or line comments
         it_before_token = zero_plus< alternatives<spaces, line_comment> >(position);
       }
-      else if (mx == url || mx == ancestor_of || mx == no_spaces) {
+      else if (mx == url || mx == no_spaces) {
         // parse everything literally
         it_before_token = position;
       }
@@ -136,6 +143,10 @@ namespace Sass {
         }
       }
 
+      else if (mx == optional_spaces_and_comments) {
+        it_before_token = position;
+      }
+
       else if (mx == optional_spaces) {
         // ToDo: what are optiona_spaces ???
         it_before_token = optional_spaces(position);
@@ -180,9 +191,9 @@ namespace Sass {
       after_token = after_token + size;
 
       // create parsed token string (public member)
-      lexed = Token(it_before_token, it_after_token, before_token);
-
-      pstate = ParserState(path, Position(before_token.file, before_token.line, before_token.column), size);
+      lexed = Token(wspace_start, it_before_token, it_after_token, optional_spaces_and_comments(it_after_token) ? optional_spaces_and_comments(it_after_token) : it_after_token, before_token);
+      Position pos(before_token.file, before_token.line, before_token.column);
+      pstate = ParserState(path, lexed, pos, size);
 
       // advance internal char iterator
       return position = it_after_token;
@@ -207,7 +218,7 @@ namespace Sass {
     Arguments* parse_arguments();
     Argument* parse_argument();
     Assignment* parse_assignment();
-    Propset* parse_propset();
+    // Propset* parse_propset();
     Ruleset* parse_ruleset(Selector_Lookahead lookahead);
     Selector_Schema* parse_selector_schema(const char* end_of_selector);
     Selector_List* parse_selector_group();
@@ -234,14 +245,14 @@ namespace Sass {
     Function_Call* parse_calc_function();
     Function_Call* parse_function_call();
     Function_Call_Schema* parse_function_call_schema();
-    String* parse_interpolated_chunk(Token);
+    String* parse_interpolated_chunk(Token, bool constant = false);
     String* parse_string();
     String_Constant* parse_static_value();
     String* parse_ie_property();
     String* parse_ie_keyword_arg();
-    String_Schema* parse_value_schema();
+    String_Schema* parse_value_schema(const char* stop);
     String* parse_identifier_schema();
-    String_Schema* parse_url_schema();
+    // String_Schema* parse_url_schema();
     If* parse_if_directive(bool else_if = false);
     For* parse_for_directive();
     Each* parse_each_directive();
diff --git a/position.cpp b/position.cpp
index 0a7a358797..0217faf4f6 100644
--- a/position.cpp
+++ b/position.cpp
@@ -42,6 +42,9 @@ namespace Sass {
   Position::Position(const size_t file)
   : Offset(0, 0), file(file) { }
 
+  Position::Position(const size_t file, const Offset& offset)
+  : Offset(offset), file(file) { }
+
   Position::Position(const size_t line, const size_t column)
   : Offset(line, column), file(-1) { }
 
@@ -50,28 +53,22 @@ namespace Sass {
 
 
   ParserState::ParserState(string path)
-  : Position(-1, 0, 0), path(path), offset(0, 0) { }
+  : Position(-1, 0, 0), path(path), offset(0, 0), token() { }
 
   ParserState::ParserState(string path, const size_t file)
-  : Position(file, 0, 0), path(path), offset(0, 0) { }
+  : Position(file, 0, 0), path(path), offset(0, 0), token() { }
 
   ParserState::ParserState(string path, Position position, Offset offset)
-  : Position(position), path(path), offset(offset) { }
+  : Position(position), path(path), offset(offset), token() { }
 
+  ParserState::ParserState(string path, Token token, Position position, Offset offset)
+  : Position(position), path(path), offset(offset), token(token) { }
 
   Position Position::inc(const char* begin, const char* end) const
   {
-    Position pos(file, line, column);
-    while (begin < end && *begin) {
-      if (*begin == '\n') {
-        ++ pos.line;
-        pos.column = 0;
-      } else {
-        ++ pos.column;
-      }
-      ++begin;
-    }
-    return pos;
+    Offset offset(line, column);
+    offset.inc(begin, end);
+    return Position(file, offset);
   }
 
   bool Position::operator== (const Position &pos) const
@@ -89,19 +86,21 @@ namespace Sass {
     return Position(file, line + off.line, off.line > 0 ? off.column : off.column + column);
   }
 
+  /* not used anymore - remove?
   std::ostream& operator<<(std::ostream& strm, const Offset& off)
   {
     if (off.line == string::npos) strm << "-1:"; else strm << off.line << ":";
     if (off.column == string::npos) strm << "-1"; else strm << off.column;
     return strm;
-  }
+  } */
 
+  /* not used anymore - remove?
   std::ostream& operator<<(std::ostream& strm, const Position& pos)
   {
     if (pos.file != string::npos) strm << pos.file << ":";
     if (pos.line == string::npos) strm << "-1:"; else strm << pos.line << ":";
     if (pos.column == string::npos) strm << "-1"; else strm << pos.column;
     return strm;
-  }
+  } */
 
 }
\ No newline at end of file
diff --git a/position.hpp b/position.hpp
index 07866f3275..b73424f414 100644
--- a/position.hpp
+++ b/position.hpp
@@ -2,7 +2,9 @@
 #define SASS_POSITION_H
 
 #include <string>
+#include <cstring>
 #include <cstdlib>
+#include <sstream>
 #include <iostream>
 
 namespace Sass {
@@ -23,7 +25,7 @@ namespace Sass {
       const Offset operator+ (const Offset &off) const;
 
     public: // overload output stream operator
-      friend ostream& operator<<(ostream& strm, const Offset& off);
+      // friend ostream& operator<<(ostream& strm, const Offset& off);
 
     public:
       Offset off() { return *this; };
@@ -38,6 +40,7 @@ namespace Sass {
 
     public: // c-tor
       Position(const size_t file); // line(0), column(0)
+      Position(const size_t file, const Offset& offset);
       Position(const size_t line, const size_t column); // file(-1)
       Position(const size_t file, const size_t line, const size_t column);
 
@@ -49,27 +52,61 @@ namespace Sass {
       Position inc(const char* begin, const char* end) const;
 
     public: // overload output stream operator
-      friend ostream& operator<<(ostream& strm, const Position& pos);
+      // friend ostream& operator<<(ostream& strm, const Position& pos);
 
     public:
       size_t file;
 
   };
 
-  class ParserState : public Position{
+  // Token type for representing lexed chunks of text
+  class Token {
+  public:
+    const char* prefix;
+    const char* begin;
+    const char* end;
+    const char* suffix;
+    Position start;
+    Position stop;
+
+    Token()
+    : prefix(0), begin(0), end(0), suffix(0), start(0), stop(0) { }
+    Token(const char* b, const char* e, const Position pos)
+    : prefix(b), begin(b), end(e), suffix(e), start(pos), stop(pos.inc(b, e)) { }
+    Token(const char* s, const Position pos)
+    : prefix(s), begin(s), end(s + strlen(s)), suffix(end), start(pos), stop(pos.inc(s, s + strlen(s))) { }
+    Token(const char* p, const char* b, const char* e, const char* s, const Position pos)
+    : prefix(p), begin(b), end(e), suffix(s), start(pos), stop(pos.inc(b, e)) { }
+
+    size_t length()    const { return end - begin; }
+    string ws_before() const { return string(prefix, begin); }
+    string to_string() const { return string(begin, end); }
+    string ws_after() const { return string(end, suffix); }
+
+    // string unquote() const;
+
+    operator bool()   { return begin && end && begin >= end; }
+    operator string() { return to_string(); }
+
+    bool operator==(Token t)  { return to_string() == t.to_string(); }
+  };
 
-    public:
+  class ParserState : public Position {
+
+    public: // c-tor
       ParserState(string path);
       ParserState(string path, const size_t file);
       ParserState(string path, Position position, Offset offset);
+      ParserState(string path, Token token, Position position, Offset offset);
 
-    public:
+    public: // down casts
       Offset off() { return *this; };
       Position pos() { return *this; };
 
     public:
       string path;
       Offset offset;
+      Token token;
 
   };
 
diff --git a/prelexer.cpp b/prelexer.cpp
index 900f981fd6..f3de77f3e7 100644
--- a/prelexer.cpp
+++ b/prelexer.cpp
@@ -2,9 +2,10 @@
 #include <cstddef>
 #include <iostream>
 #include <iomanip>
-#include "constants.hpp"
-#include "prelexer.hpp"
 #include "util.hpp"
+#include "position.hpp"
+#include "prelexer.hpp"
+#include "constants.hpp"
 
 
 namespace Sass {
@@ -13,13 +14,15 @@ namespace Sass {
   namespace Prelexer {
     using std::ptrdiff_t;
     // Matches zero characters (always succeeds without consuming input).
+    /* not used anymore - remove?
     const char* epsilon(char *src) {
       return src;
-    }
+    }*/
     // Matches the empty string.
+    /* not used anymore - remove?
     const char* empty(char *src) {
       return *src ? 0 : src;
-    }
+    }*/
 
     // Match any single character.
     const char* any_char(const char* src) { return *src ? src+1 : src; }
@@ -57,6 +60,15 @@ namespace Sass {
       return alternatives<block_comment, line_comment>(src);
     }
 
+    const char* wspaces(const char* src) {
+      return
+      alternatives<
+        exactly<' '>,
+        exactly<'\t'>
+      >(src);
+    }
+
+    /* not used anymore - remove?
     const char* newline(const char* src) {
       return
       alternatives<
@@ -65,29 +77,26 @@ namespace Sass {
         exactly<'\r'>,
         exactly<'\f'>
       >(src);
-    }
+    }*/
 
+    /* not used anymore - remove?
     const char* whitespace(const char* src) {
-      return
-      alternatives<
-        newline,
-        exactly<' '>,
-        exactly<'\t'>
-      >(src);
-    }
+      return spaces(src);
+    }*/
 
+    /* not used anymore - remove?
     const char* escape(const char* src) {
       return
       sequence<
         exactly<'\\'>,
         any_char
       >(src);
-    }
+    }*/
 
 
     // Whitespace handling.
     const char* optional_spaces(const char* src) { return optional<spaces>(src); }
-    const char* optional_comment(const char* src) { return optional<comment>(src); }
+    // const char* optional_comment(const char* src) { return optional<comment>(src); }
     const char* optional_spaces_and_comments(const char* src) {
       return zero_plus< alternatives<spaces, comment> >(src);
     }
@@ -120,6 +129,7 @@ namespace Sass {
     }
 
     // Match CSS selectors.
+    /* not used anymore - remove?
     const char* sel_ident(const char* src) {
       return sequence< optional< alternatives< exactly<'-'>, exactly<'|'> > >,
                        alternatives< alpha, exactly<'_'>, backslash_something, exactly<'|'> >,
@@ -128,7 +138,7 @@ namespace Sass {
                                                 exactly<'_'>,
                                                 exactly<'|'>,
                                                 backslash_something > > >(src);
-    }
+    }*/
 
     // Match CSS css variables.
     const char* custom_property_name(const char* src) {
@@ -146,7 +156,7 @@ namespace Sass {
 
     // interpolants can be recursive/nested
     const char* interpolant(const char* src) {
-      return smartdel_by<hash_lbrace, rbrace, false>(src);
+      return recursive_scopes< exactly<hash_lbrace>, exactly<rbrace> >(src);
     }
 
     // $re_squote = /'(?:$re_itplnt|\\.|[^'])*'/
@@ -202,11 +212,12 @@ namespace Sass {
                                  interpolant,
                                  zero_plus< alternatives< identifier, percentage, dimension, hex, number, quoted_string, exactly<'%'> > > > >(src);
     }
+    /* not used anymore - remove?
     const char* filename_schema(const char* src) {
       return one_plus< sequence< zero_plus< alternatives< identifier, number, exactly<'.'>, exactly<'/'> > >,
                                  interpolant,
                                  zero_plus< alternatives< identifier, number, exactly<'.'>, exactly<'/'> > > > >(src);
-    }
+    }*/
 
     const char* filename(const char* src) {
       return one_plus< alternatives< identifier, number, exactly<'.'> > >(src);
@@ -233,10 +244,6 @@ namespace Sass {
       return exactly<without_kwd>(src);
     }
 
-    const char* until_closing_paren(const char* src) {
-      return until<')'>(src);
-    }
-
     const char* media(const char* src) {
       return exactly<media_kwd>(src);
     }
@@ -245,17 +252,20 @@ namespace Sass {
       return exactly<supports_kwd>(src);
     }
 
+    /* not used anymore - remove?
     const char* keyframes(const char* src) {
       return sequence< exactly<'@'>, optional< vendor_prefix >, exactly< keyframes_kwd > >(src);
-    }
+    } */
 
+    /* not used anymore - remove?
     const char* vendor_prefix(const char* src) {
       return alternatives< exactly< vendor_opera_kwd >, exactly< vendor_webkit_kwd >, exactly< vendor_mozilla_kwd >, exactly< vendor_ms_kwd >, exactly< vendor_khtml_kwd > >(src);
-    }
+    } */
 
+    /* not used anymore - remove?
     const char* keyf(const char* src) {
       return one_plus< alternatives< to, from, percentage > >(src);
-    }
+    } */
 
     const char* mixin(const char* src) {
       return exactly<mixin_kwd>(src);
@@ -342,9 +352,10 @@ namespace Sass {
       return exactly<debug_kwd>(src);
     }
 
+    /* not used anymore - remove?
     const char* directive(const char* src) {
       return sequence< exactly<'@'>, identifier >(src);
-    }
+    } */
 
     const char* null(const char* src) {
       return exactly<null_kwd>(src);
@@ -413,9 +424,10 @@ namespace Sass {
       return sequence< number, exactly<'%'> >(src);
     }
 
+    /* not used anymore - remove?
     const char* em(const char* src) {
       return sequence< number, exactly<em_kwd> >(src);
-    }
+    } */
     const char* dimension(const char* src) {
       return sequence<number, one_plus< alpha > >(src);
     }
@@ -435,31 +447,35 @@ namespace Sass {
       return (len != 5 && len != 8) ? 0 : p;
     }
 
+    /* no longer used - remove?
     const char* rgb_prefix(const char* src) {
       return exactly<rgb_kwd>(src);
-    }
+    }*/
     // Match CSS uri specifiers.
 
     const char* uri_prefix(const char* src) {
       return exactly<url_kwd>(src);
     }
     // TODO: rename the following two functions
+    /* no longer used - remove?
     const char* uri(const char* src) {
       return sequence< exactly<url_kwd>,
                        optional<spaces>,
                        quoted_string,
                        optional<spaces>,
                        exactly<')'> >(src);
-    }
+    }*/
+    /* no longer used - remove?
     const char* url_value(const char* src) {
       return sequence< optional< sequence< identifier, exactly<':'> > >, // optional protocol
                        one_plus< sequence< zero_plus< exactly<'/'> >, filename > >, // one or more folders and/or trailing filename
                        optional< exactly<'/'> > >(src);
-    }
+    }*/
+    /* no longer used - remove?
     const char* url_schema(const char* src) {
       return sequence< optional< sequence< identifier, exactly<':'> > >, // optional protocol
                        filename_schema >(src); // optional trailing slash
-    }
+    }*/
     // Match CSS "!important" keyword.
     const char* important(const char* src) {
       return sequence< exactly<'!'>,
@@ -514,6 +530,7 @@ namespace Sass {
     const char* suffix_match(const char* src) { return exactly<dollar_equal>(src); }
     const char* substring_match(const char* src) { return exactly<star_equal>(src); }
     // Match CSS combinators.
+    /* not used anymore - remove?
     const char* adjacent_to(const char* src) {
       return sequence< optional_spaces, exactly<'+'> >(src);
     }
@@ -525,7 +542,7 @@ namespace Sass {
     }
     const char* ancestor_of(const char* src) {
       return sequence< spaces, negate< exactly<'{'> > >(src);
-    }
+    }*/
 
     // Match SCSS variable names.
     const char* variable(const char* src) {
@@ -627,13 +644,14 @@ namespace Sass {
     }
 
     // Path matching functions.
+    /* not used anymore - remove?
     const char* folder(const char* src) {
       return sequence< zero_plus< any_char_except<'/'> >,
                        exactly<'/'> >(src);
     }
     const char* folders(const char* src) {
       return zero_plus< folder >(src);
-    }
+    }*/
 
     const char* chunk(const char* src) {
       char inside_str = 0;
@@ -663,26 +681,30 @@ namespace Sass {
     }
 
     // follow the CSS spec more closely and see if this helps us scan URLs correctly
+    /* not used anymore - remove?
     const char* NL(const char* src) {
       return alternatives< exactly<'\n'>,
                            sequence< exactly<'\r'>, exactly<'\n'> >,
                            exactly<'\r'>,
                            exactly<'\f'> >(src);
-    }
+    }*/
 
+    /* not used anymore - remove?
     const char* H(const char* src) {
       return std::isxdigit(*src) ? src+1 : 0;
-    }
+    }*/
 
+    /* not used anymore - remove?
     const char* unicode(const char* src) {
       return sequence< exactly<'\\'>,
                        between<H, 1, 6>,
                        optional< class_char<url_space_chars> > >(src);
-    }
+    }*/
 
+    /* not used anymore - remove?
     const char* ESCAPE(const char* src) {
       return alternatives< unicode, class_char<escape_chars> >(src);
-    }
+    }*/
 
     const char* url(const char* src) {
       return chunk(src);
diff --git a/prelexer.hpp b/prelexer.hpp
index 2c33242c99..e0950b5061 100644
--- a/prelexer.hpp
+++ b/prelexer.hpp
@@ -88,26 +88,25 @@ namespace Sass {
       }
     }
 
-    // Match a sequence of characters delimited by the supplied chars.
-    template <char beg, char end, bool esc>
-    const char* smartdel_by(const char* src) {
+    // skip to delimiter (mx) inside given range
+    // this will savely skip over all quoted strings
+    // recursive skip stuff delimited by start/stop
+    // first start/opener must be consumed already!
+    template<prelexer start, prelexer stop>
+    const char* skip_over_scopes(const char* src, const char* end = 0) {
 
       size_t level = 0;
       bool in_squote = false;
       bool in_dquote = false;
       // bool in_braces = false;
 
-      src = exactly<beg>(src);
-
-      if (!src) return 0;
-
-      while (1) {
+      while (*src) {
 
-        // end of string?
-        if (!*src) return 0;
+        // check for abort condition
+        if (end && src >= end) break;
 
         // has escaped sequence?
-        if (!esc && *src == '\\') {
+        if (*src == '\\') {
           ++ src; // skip this (and next)
         }
         else if (*src == '"') {
@@ -121,23 +120,35 @@ namespace Sass {
         }
 
         // find another opener inside?
-        else if (exactly<beg>(src)) {
+        else if (start(src)) {
           ++ level; // increase counter
         }
 
         // look for the closer (maybe final, maybe not)
-        else if (const char* stop = exactly<end>(src)) {
+        else if (const char* final = stop(src)) {
           // only close one level?
           if (level > 0) -- level;
           // return position at end of stop
           // delimiter may be multiple chars
-          else return stop;
+          else return final;
         }
 
         // next
         ++ src;
-
       }
+
+      return 0;
+    }
+
+    // Match a sequence of characters delimited by the supplied chars.
+    template <prelexer start, prelexer stop>
+    const char* recursive_scopes(const char* src) {
+      // parse opener
+      src = start(src);
+      // abort if not found
+      if (!src) return 0;
+      // parse the rest until final closer
+      return skip_over_scopes<start, stop>(src);
     }
 
     // Match a sequence of characters delimited by the supplied strings.
@@ -154,58 +165,6 @@ namespace Sass {
       }
     }
 
-    // Match a sequence of characters delimited by the supplied strings.
-    template <const char* beg, const char* end, bool esc>
-    const char* smartdel_by(const char* src) {
-
-      size_t level = 0;
-      bool in_squote = false;
-      bool in_dquote = false;
-      // bool in_braces = false;
-
-      src = exactly<beg>(src);
-
-      if (!src) return 0;
-
-      while (1) {
-
-        // end of string?
-        if (!*src) return 0;
-
-        // has escaped sequence?
-        if (!esc && *src == '\\') {
-          ++ src; // skip this (and next)
-        }
-        else if (*src == '"') {
-          in_dquote = ! in_dquote;
-        }
-        else if (*src == '\'') {
-          in_squote = ! in_squote;
-        }
-        else if (in_dquote || in_squote) {
-          // take everything literally
-        }
-
-        // find another opener inside?
-        else if (exactly<beg>(src)) {
-          ++ level; // increase counter
-        }
-
-        // look for the closer (maybe final, maybe not)
-        else if (const char* stop = exactly<end>(src)) {
-          // only close one level?
-          if (level > 0) -- level;
-          // return position at end of stop
-          // delimiter may be multiple chars
-          else return stop;
-        }
-
-        // next
-        ++ src;
-
-      }
-    }
-
     // Match any single character.
     const char* any_char(const char* src);
     // Match any single character except the supplied one.
@@ -215,10 +174,10 @@ namespace Sass {
     }
 
     // Matches zero characters (always succeeds without consuming input).
-    const char* epsilon(const char*);
+    // const char* epsilon(const char*);
 
     // Matches the empty string.
-    const char* empty(const char*);
+    // const char* empty(const char*);
 
     // Succeeds of the supplied matcher fails, and vice versa.
     template <prelexer mx>
@@ -415,6 +374,10 @@ namespace Sass {
     const char* xdigits(const char* src);
     const char* alnums(const char* src);
     const char* puncts(const char* src);
+    // Match certain white-space charactes.
+    const char* wspaces(const char* src);
+    // const char* newline(const char* src);
+    // const char* whitespace(const char* src);
 
     // Match a line comment.
     const char* line_comment(const char* src);
@@ -434,7 +397,7 @@ namespace Sass {
 
     // Whitespace handling.
     const char* optional_spaces(const char* src);
-    const char* optional_comment(const char* src);
+    // const char* optional_comment(const char* src);
     const char* optional_spaces_and_comments(const char* src);
     const char* spaces_and_comments(const char* src);
     const char* no_spaces(const char* src);
@@ -447,15 +410,14 @@ namespace Sass {
     const char* identifier(const char* src);
     const char* identifier_fragment(const char* src);
     // Match selector names.
-    const char* sel_ident(const char* src);
-    const char* until_closing_paren(const char* src);
+    // const char* sel_ident(const char* src);
     // Match interpolant schemas
     const char* identifier_schema(const char* src);
     const char* value_schema(const char* src);
     const char* filename(const char* src);
-    const char* filename_schema(const char* src);
-    const char* url_schema(const char* src);
-    const char* url_value(const char* src);
+    // const char* filename_schema(const char* src);
+    // const char* url_schema(const char* src);
+    // const char* url_value(const char* src);
     const char* vendor_prefix(const char* src);
     // Match CSS '@' keywords.
     const char* at_keyword(const char* src);
@@ -465,8 +427,8 @@ namespace Sass {
     const char* without_directive(const char* src);
     const char* media(const char* src);
     const char* supports(const char* src);
-    const char* keyframes(const char* src);
-    const char* keyf(const char* src);
+    // const char* keyframes(const char* src);
+    // const char* keyf(const char* src);
     const char* mixin(const char* src);
     const char* function(const char* src);
     const char* return_directive(const char* src);
@@ -492,7 +454,7 @@ namespace Sass {
     const char* err(const char* src);
     const char* dbg(const char* src);
 
-    const char* directive(const char* src);
+    // const char* directive(const char* src);
     const char* at_keyword(const char* src);
 
     const char* null(const char* src);
@@ -522,10 +484,10 @@ namespace Sass {
     const char* hex(const char* src);
     const char* hexa(const char* src);
     const char* hex0(const char* src);
-    const char* rgb_prefix(const char* src);
+    // const char* rgb_prefix(const char* src);
     // Match CSS uri specifiers.
     const char* uri_prefix(const char* src);
-    const char* uri(const char* src);
+    // const char* uri(const char* src);
     const char* url(const char* src);
     // Match CSS "!important" keyword.
     const char* important(const char* src);
@@ -551,10 +513,10 @@ namespace Sass {
     const char* suffix_match(const char* src);
     const char* substring_match(const char* src);
     // Match CSS combinators.
-    const char* adjacent_to(const char* src);
-    const char* precedes(const char* src);
-    const char* parent_of(const char* src);
-    const char* ancestor_of(const char* src);
+    // const char* adjacent_to(const char* src);
+    // const char* precedes(const char* src);
+    // const char* parent_of(const char* src);
+    // const char* ancestor_of(const char* src);
 
     // Match SCSS variable names.
     const char* variable(const char* src);
@@ -582,8 +544,8 @@ namespace Sass {
     const char* url(const char* src);
 
     // Path matching functions.
-    const char* folder(const char* src);
-    const char* folders(const char* src);
+    // const char* folder(const char* src);
+    // const char* folders(const char* src);
 
 
     const char* static_string(const char* src);
diff --git a/sass.cpp b/sass.cpp
index b58dd32ea5..dbc24021d2 100644
--- a/sass.cpp
+++ b/sass.cpp
@@ -4,14 +4,14 @@
 #include <sstream>
 
 #include "sass.h"
-#include "inspect.hpp"
+#include "util.hpp"
 
 extern "C" {
   using namespace std;
 
   // caller must free the returned memory
-  char* ADDCALL sass_string_quote (const char *str, const char quotemark) {
-    string quoted = Sass::quote(str, quotemark);
+  char* ADDCALL sass_string_quote (const char *str, const char quote_mark) {
+    string quoted = Sass::quote(str, quote_mark);
     char *cstr = (char*) malloc(quoted.length() + 1);
     std::strcpy(cstr, quoted.c_str());
     return cstr;
diff --git a/sass.h b/sass.h
index f169e05fd8..95ce1d877f 100644
--- a/sass.h
+++ b/sass.h
@@ -46,7 +46,7 @@ enum Sass_Output_Style {
 };
 
 // Some convenient string helper function
-ADDAPI char* ADDCALL sass_string_quote (const char *str, const char quotemark);
+ADDAPI char* ADDCALL sass_string_quote (const char *str, const char quote_mark);
 ADDAPI char* ADDCALL sass_string_unquote (const char *str);
 
 // Get compiled libsass version
diff --git a/sass_context.cpp b/sass_context.cpp
index af1faa84e3..bc2dabc0ea 100644
--- a/sass_context.cpp
+++ b/sass_context.cpp
@@ -1,7 +1,9 @@
 #ifdef _WIN32
 #include <io.h>
+#define LFEED "\n"
 #else
 #include <unistd.h>
+#define LFEED "\n"
 #endif
 
 #include <cstring>
@@ -329,7 +331,7 @@ extern "C" {
              .include_paths_array(include_paths)
              .include_paths(vector<string>())
              .precision(c_ctx->precision ? c_ctx->precision : 5)
-             .linefeed(c_ctx->linefeed ? c_ctx->linefeed : "\n")
+             .linefeed(c_ctx->linefeed ? c_ctx->linefeed : LFEED)
              .indent(c_ctx->indent ? c_ctx->indent : "  ");
 
       // create new c++ Context
diff --git a/sass_interface.cpp b/sass_interface.cpp
index ceb0d1de6a..46d9ec15cb 100644
--- a/sass_interface.cpp
+++ b/sass_interface.cpp
@@ -1,7 +1,9 @@
 #ifdef _WIN32
 #include <io.h>
+#define LFEED "\n"
 #else
 #include <unistd.h>
+#define LFEED "\n"
 #endif
 
 #include <string>
@@ -120,7 +122,7 @@ extern "C" {
                        .include_paths(vector<string>())
                        .precision(c_ctx->options.precision ? c_ctx->options.precision : 5)
                        .indent(c_ctx->options.indent ? c_ctx->options.indent : "  ")
-                       .linefeed(c_ctx->options.linefeed ? c_ctx->options.linefeed : "\n")
+                       .linefeed(c_ctx->options.linefeed ? c_ctx->options.linefeed : LFEED)
                        .importer(0)
       );
       if (c_ctx->c_functions) {
diff --git a/sass_util.cpp b/sass_util.cpp
index ddeaeb3ea0..7510e718b2 100644
--- a/sass_util.cpp
+++ b/sass_util.cpp
@@ -38,7 +38,7 @@ namespace Sass {
     end
 	*/
   Node paths(const Node& arrs, Context& ctx) {
-    To_String to_string;
+    To_String to_string(&ctx);
 
     Node loopStart = Node::createCollection();
     loopStart.collection()->push_back(Node::createCollection());
diff --git a/source_map.cpp b/source_map.cpp
index 88f8247ec6..ba72c730cb 100644
--- a/source_map.cpp
+++ b/source_map.cpp
@@ -106,15 +106,6 @@ namespace Sass {
     return result;
   }
 
-  void SourceMap::remove_line()
-  {
-    // prevent removing non existing lines
-    if (current_position.line > 1) {
-      current_position.line -= 1;
-      current_position.column = 1;
-    }
-  }
-
   void SourceMap::update_column(const string& str)
   {
     const ptrdiff_t new_line_count = std::count(str.begin(), str.end(), '\n');
diff --git a/source_map.hpp b/source_map.hpp
index 9178708e41..386105ff43 100644
--- a/source_map.hpp
+++ b/source_map.hpp
@@ -19,7 +19,9 @@ namespace Sass {
     SourceMap();
     SourceMap(const string& file);
 
-    void remove_line();
+    void setFile(const string& str) {
+      file = str;
+    }
     void update_column(const string& str);
     void add_open_mapping(AST_Node* node);
     void add_close_mapping(AST_Node* node);
@@ -33,7 +35,9 @@ namespace Sass {
 
     vector<Mapping> mappings;
     Position current_position;
+public:
     string file;
+private:
     Base64VLQ base64vlq;
   };
 
diff --git a/subset_map.hpp b/subset_map.hpp
index 09bbd1f793..b9ce01a23b 100644
--- a/subset_map.hpp
+++ b/subset_map.hpp
@@ -107,9 +107,7 @@ namespace Sass {
     sort(sorted.begin(), sorted.end());
     vector<pair<size_t, vector<K> > > indices;
     for (size_t i = 0, S = s.size(); i < S; ++i) {
-      // cerr << "looking for " << s[i] << endl;
       if (!hash_.count(s[i])) {
-        // cerr << "didn't find " << s[i] << endl;
         continue;
       }
       vector<triple<vector<K>, set<K>, size_t> > subsets = hash_[s[i]];
diff --git a/to_string.cpp b/to_string.cpp
index 9cfa2cfa9c..b61c235b0d 100644
--- a/to_string.cpp
+++ b/to_string.cpp
@@ -11,16 +11,24 @@
 namespace Sass {
   using namespace std;
 
-  To_String::To_String(Context* ctx) : ctx(ctx) { }
+  To_String::To_String(Context* ctx)
+  : ctx(ctx) { }
   To_String::~To_String() { }
 
   inline string To_String::fallback_impl(AST_Node* n)
   {
-    Inspect i(ctx);
+    Emitter emitter(ctx);
+    Inspect i(emitter);
+    i.in_declaration_list = true;
     n->perform(&i);
     return i.get_buffer();
   }
 
+  inline string To_String::operator()(String_Constant* s)
+  {
+    return s->value();
+  }
+
   inline string To_String::operator()(Null* n)
   { return ""; }
 }
diff --git a/to_string.hpp b/to_string.hpp
index 8476163ca4..937ddd079f 100644
--- a/to_string.hpp
+++ b/to_string.hpp
@@ -24,6 +24,7 @@ namespace Sass {
     virtual ~To_String();
 
     string operator()(Null* n);
+    string operator()(String_Constant*);
 
     template <typename U>
     string fallback(U n) { return fallback_impl(n); }
diff --git a/token.hpp b/token.hpp
deleted file mode 100644
index df248c527b..0000000000
--- a/token.hpp
+++ /dev/null
@@ -1,42 +0,0 @@
-#ifndef SASS_TOKEN_H
-#define SASS_TOKEN_H
-
-#include <cstring>
-#include <string>
-#include <sstream>
-
-#include "position.hpp"
-
-namespace Sass {
-  using namespace std;
-
-  // Token type for representing lexed chunks of text
-  class Token {
-  public:
-    const char* begin;
-    const char* end;
-    Position before;
-    Position after;
-
-    Token()
-    : begin(0), end(0), before(0), after(0) { }
-    Token(const char* b, const char* e, const Position pos)
-    : begin(b), end(e), before(pos), after(pos.inc(b, e)) { }
-    Token(const char* s, const Position pos)
-    : begin(s), end(s + strlen(s)), before(pos), after(pos.inc(s, s + strlen(s))) { }
-
-    size_t length()    const { return end - begin; }
-    string to_string() const { return string(begin, end - begin); }
-
-    string unquote() const;
-    void   unquote_to_stream(stringstream& buf) const;
-
-    operator bool()   { return begin && end && begin >= end; }
-    operator string() { return to_string(); }
-
-    bool operator==(Token t)  { return to_string() == t.to_string(); }
-  };
-
-}
-
-#endif
diff --git a/units.cpp b/units.cpp
index 8cd5adaf20..d9b78bcd0d 100644
--- a/units.cpp
+++ b/units.cpp
@@ -45,10 +45,11 @@ namespace Sass {
     return factor;
   }
 
+  /* not used anymore - remove?
   double convert(double n, const string& from, const string& to)
   {
     double factor = conversion_factor(from, to);
     return factor ? factor * n : n;
-  }
+  } */
 
 }
diff --git a/units.hpp b/units.hpp
index bdb780ffd1..d58c1be583 100644
--- a/units.hpp
+++ b/units.hpp
@@ -9,7 +9,7 @@ namespace Sass {
   extern double conversion_factors[10][10];
   Unit string_to_unit(const string&);
   double conversion_factor(const string&, const string&);
-  double convert(double, const string&, const string&);
+  // double convert(double, const string&, const string&);
 }
 
 #endif
diff --git a/util.cpp b/util.cpp
index 106d571999..12e007c56b 100644
--- a/util.cpp
+++ b/util.cpp
@@ -1,6 +1,349 @@
+#include<stdint.h>
+#include "ast.hpp"
 #include "util.hpp"
+#include "prelexer.hpp"
+#include "utf8/checked.h"
 
 namespace Sass {
+
+  // double escape every escape sequences
+  // escape unescaped quotes and backslashes
+  string string_escape(const string& str)
+  {
+    string out("");
+    for (auto i : str) {
+      // escape some characters
+      if (i == '"') out += '\\';
+      if (i == '\'') out += '\\';
+      if (i == '\\') out += '\\';
+      out += i;
+    }
+    return out;
+  }
+
+  // unescape every escape sequence
+  // only removes unescaped backslashes
+  string string_unescape(const string& str)
+  {
+    string out("");
+    bool esc = false;
+    for (auto i : str) {
+      if (esc || i != '\\') {
+        esc = false;
+        out += i;
+      } else {
+        esc = true;
+      }
+    }
+    // open escape sequence at end
+    // maybe it should thow an error
+    if (esc) { out += '\\'; }
+    return out;
+  }
+
+  // evacuate unescaped quoted
+  // leave everything else untouched
+  string evacuate_quotes(const string& str)
+  {
+    string out("");
+    bool esc = false;
+    for (auto i : str) {
+      if (!esc) {
+        // ignore next character
+        if (i == '\\') esc = true;
+        // evacuate unescaped quotes
+        else if (i == '"') out += '\\';
+        else if (i == '\'') out += '\\';
+      }
+      // get escaped char now
+      else { esc = false; }
+      // remove nothing
+      out += i;
+    }
+    return out;
+  }
+
+  // double escape all escape sequences
+  // keep unescaped quotes and backslashes
+  string evacuate_escapes(const string& str)
+  {
+    string out("");
+    bool esc = false;
+    for (auto i : str) {
+      if (i == '\\' && !esc) {
+        out += '\\';
+        out += '\\';
+        esc = true;
+      } else if (esc && i == '"') {
+        out += '\\';
+        out += i;
+        esc = false;
+      } else if (esc && i == '\'') {
+        out += '\\';
+        out += i;
+        esc = false;
+      } else if (esc && i == '\\') {
+        out += '\\';
+        out += i;
+        esc = false;
+      } else {
+        esc = false;
+        out += i;
+      }
+    }
+    if (esc) out += 'Z';
+    return out;
+  }
+
+  // bell character is replaces with space
+  string string_to_output(const string& str)
+  {
+    string out("");
+    for (auto i : str) {
+      if (i == 10) {
+        out += ' ';
+      } else {
+        out += i;
+      }
+    }
+    return out;
+  }
+
+  string comment_to_string(const string& text)
+  {
+    string str = "";
+    size_t has = 0;
+    bool clean = false;
+    for (auto i : text) {
+      if (clean) {
+        if (i == '\n') { has = 0; }
+        else if (i == '\r') { has = 0; }
+        else if (i == '\t') { ++ has; }
+        else if (i == ' ') { ++ has; }
+        else if (i == '*') {}
+        else {
+          clean = false;
+          str += ' ';
+          str += i;
+        }
+      } else if (i == '\n') {
+        clean = true;
+      } else if (i == '\r') {
+        clean = true;
+      } else {
+        str += i;
+      }
+    }
+    if (has) return str;
+    else return text;
+  }
+
+  string normalize_wspace(const string& str) {
+    bool ws = false;
+    bool esc = false;
+    char inside_str = 0;
+    string text = "";
+    for(auto i : str) {
+      if (!esc && i == '\\') {
+        esc = true;
+        text += i;
+      } else if (esc) {
+        esc = false;
+        text += i;
+      } else if (!inside_str && (i == '"' || i == '\'')) {
+        inside_str = i;
+        text += i;
+      } else if (inside_str) {
+        if (i == inside_str)
+          inside_str = false;
+        text += i;
+      } else if (
+        i == ' ' ||
+        i == '\r' ||
+        i == '\n' ||
+        i == '	'
+      ) {
+        // only add one space
+        if (!ws) text += ' ';
+        ws = true;
+      } else {
+        ws = false;
+        text += i;
+      }
+    }
+    if (esc) text += '\\';
+    return text;
+  }
+
+  // find best quote_mark by detecting if the string contains any single
+  // or double quotes. When a single quote is found, we not we want a double
+  // quote as quote_mark. Otherwise we check if the string cotains any double
+  // quotes, which will trigger the use of single quotes as best quote_mark.
+  char detect_best_quotemark(const char* s, char qm)
+  {
+    // ensure valid fallback quote_mark
+    char quote_mark = qm && qm != '*' ? qm : '"';
+    while (*s) {
+      // force double quotes as soon
+      // as one single quote is found
+      if (*s == '\'') { return '"'; }
+      // a single does not force quote_mark
+      // maybe we see a double quote later
+      else if (*s == '"') { quote_mark = '\''; }
+      ++ s;
+    }
+    return quote_mark;
+  }
+
+  string unquote(const string& s, char* qd)
+  {
+
+    // not enough room for quotes
+    // no possibility to unquote
+    if (s.length() < 2) return s;
+
+    char q;
+    bool skipped = false;
+
+    // this is no guarantee that the unquoting will work
+    // what about whitespace before/after the quote_mark?
+    if      (*s.begin() == '"'  && *s.rbegin() == '"')  q = '"';
+    else if (*s.begin() == '\'' && *s.rbegin() == '\'') q = '\'';
+    else                                                return s;
+
+    string unq;
+    unq.reserve(s.length()-2);
+
+    for (size_t i = 1, L = s.length() - 1; i < L; ++i) {
+
+      // implement the same strange ruby sass behavior
+      // an escape sequence can also mean a unicode char
+      if (s[i] == '\\' && !skipped) {
+        // remember
+        skipped = true;
+
+        // skip it
+        // ++ i;
+
+        // if (i == L) break;
+
+        // escape length
+        size_t len = 1;
+
+        // parse as many sequence chars as possible
+        // ToDo: Check if ruby aborts after possible max
+        while (i + len < L && s[i + len] && isxdigit(s[i + len])) ++ len;
+
+        // hex string?
+        if (len > 1) {
+
+          // convert the extracted hex string to code point value
+          // ToDo: Maybe we could do this without creating a substring
+          uint32_t cp = strtol(s.substr (i + 1, len - 1).c_str(), nullptr, 16);
+
+          // assert invalid code points
+          if (cp == 0) cp = 0xFFFD;
+          // replace bell character
+          // if (cp == 10) cp = 32;
+
+          // use a very simple approach to convert via utf8 lib
+          // maybe there is a more elegant way; maybe we shoud
+          // convert the whole output from string to a stream!?
+          // allocate memory for utf8 char and convert to utf8
+          unsigned char u[5] = {0,0,0,0,0}; utf8::append(cp, u);
+          for(size_t m = 0; u[m] && m < 5; m++) unq.push_back(u[m]);
+
+          // skip some more chars?
+          i += len - 1; skipped = false;
+
+        }
+
+
+      }
+      // check for unexpected delimiter
+      // be strict and throw error back
+      else if (!skipped && q == s[i]) {
+        // don't be that strict
+        return s;
+        // this basically always means an internal error and not users fault
+        error("Unescaped delimiter in string to unquote found. [" + s + "]", ParserState("[UNQUOTE]", -1));
+      }
+      else {
+        skipped = false;
+        unq.push_back(s[i]);
+      }
+
+    }
+    if (skipped) { return s; }
+    if (qd) *qd = q;
+    return unq;
+
+  }
+
+  string quote(const string& s, char q)
+  {
+
+    // return an empty quoted string
+    if (s.empty()) return string(2, q ? q : '"');
+
+    // autodetect with fallback to given quote
+    q = detect_best_quotemark(s.c_str(), q);
+
+    string quoted;
+    quoted.reserve(s.length()+2);
+    quoted.push_back(q);
+
+    const char* it = s.c_str();
+    const char* end = it + strlen(it) + 1;
+    while (*it && it < end) {
+      const char* now = it;
+
+      if (*it == q) {
+        quoted.push_back('\\');
+      } else if (*it == '\\') {
+        quoted.push_back('\\');
+      }
+
+      int cp = utf8::next(it, end);
+
+      if (cp == 10) {
+        quoted.push_back('\\');
+        quoted.push_back('a');
+      } else if (cp < 127) {
+        quoted.push_back((char) cp);
+      } else {
+        while (now < it) {
+          quoted.push_back(*now);
+          ++ now;
+        }
+      }
+    }
+
+    quoted.push_back(q);
+    return quoted;
+  }
+
+  bool is_hex_doublet(double n)
+  {
+    return n == 0x00 || n == 0x11 || n == 0x22 || n == 0x33 ||
+           n == 0x44 || n == 0x55 || n == 0x66 || n == 0x77 ||
+           n == 0x88 || n == 0x99 || n == 0xAA || n == 0xBB ||
+           n == 0xCC || n == 0xDD || n == 0xEE || n == 0xFF ;
+  }
+
+  bool is_color_doublet(double r, double g, double b)
+  {
+    return is_hex_doublet(r) && is_hex_doublet(g) && is_hex_doublet(b);
+  }
+
+  bool peek_linefeed(const char* start)
+  {
+    if(*start == '\n' || *start == '\r') return true;;
+    const char* linefeed = Prelexer::wspaces(start);
+    if (linefeed == 0) return false;
+    return *linefeed == '\n' || *linefeed == '\r';
+  }
+
   namespace Util {
     using std::string;
 
@@ -37,7 +380,7 @@ namespace Sass {
       }
     }
 
-    bool isPrintable(Ruleset* r) {
+    bool isPrintable(Ruleset* r, Output_Style style) {
       if (r == NULL) {
         return false;
       }
@@ -56,9 +399,15 @@ namespace Sass {
         Statement* stm = (*b)[i];
         if (dynamic_cast<Has_Block*>(stm)) {
           Block* pChildBlock = ((Has_Block*)stm)->block();
-          if (isPrintable(pChildBlock)) {
+          if (isPrintable(pChildBlock, style)) {
             hasPrintableChildBlocks = true;
           }
+        } else if (Comment* c = dynamic_cast<Comment*>(stm)) {
+          if (style == COMPRESSED) {
+            hasDeclarations = c->is_important();
+          } else {
+            hasDeclarations = true;
+          }
         } else {
           hasDeclarations = true;
         }
@@ -71,7 +420,7 @@ namespace Sass {
       return false;
     }
 
-    bool isPrintable(Feature_Block* f) {
+    bool isPrintable(Feature_Block* f, Output_Style style) {
       if (f == NULL) {
         return false;
       }
@@ -95,7 +444,7 @@ namespace Sass {
         }
         else if (dynamic_cast<Has_Block*>(stm)) {
           Block* pChildBlock = ((Has_Block*)stm)->block();
-          if (isPrintable(pChildBlock)) {
+          if (isPrintable(pChildBlock, style)) {
             hasPrintableChildBlocks = true;
           }
         }
@@ -108,7 +457,7 @@ namespace Sass {
       return false;
     }
 
-    bool isPrintable(Media_Block* m) {
+    bool isPrintable(Media_Block* m, Output_Style style) {
       if (m == NULL) {
         return false;
       }
@@ -132,7 +481,7 @@ namespace Sass {
         }
         else if (dynamic_cast<Has_Block*>(stm)) {
           Block* pChildBlock = ((Has_Block*)stm)->block();
-          if (isPrintable(pChildBlock)) {
+          if (isPrintable(pChildBlock, style)) {
             hasPrintableChildBlocks = true;
           }
         }
@@ -145,7 +494,7 @@ namespace Sass {
       return false;
     }
 
-    bool isPrintable(Block* b) {
+    bool isPrintable(Block* b, Output_Style style) {
       if (b == NULL) {
         return false;
       }
@@ -154,26 +503,29 @@ namespace Sass {
         Statement* stm = (*b)[i];
         if (typeid(*stm) == typeid(Declaration) || typeid(*stm) == typeid(At_Rule)) {
           return true;
+        }
+        else if (typeid(*stm) == typeid(Comment)) {
+
         }
         else if (typeid(*stm) == typeid(Ruleset)) {
           Ruleset* r = (Ruleset*) stm;
-          if (isPrintable(r)) {
+          if (isPrintable(r, style)) {
             return true;
           }
         }
         else if (typeid(*stm) == typeid(Feature_Block)) {
           Feature_Block* f = (Feature_Block*) stm;
-          if (isPrintable(f)) {
+          if (isPrintable(f, style)) {
             return true;
           }
         }
         else if (typeid(*stm) == typeid(Media_Block)) {
           Media_Block* m = (Media_Block*) stm;
-          if (isPrintable(m)) {
+          if (isPrintable(m, style)) {
             return true;
           }
         }
-        else if (dynamic_cast<Has_Block*>(stm) && isPrintable(((Has_Block*)stm)->block())) {
+        else if (dynamic_cast<Has_Block*>(stm) && isPrintable(((Has_Block*)stm)->block(), style)) {
           return true;
         }
       }
diff --git a/util.hpp b/util.hpp
index d3df0d2ef9..cf47691d49 100644
--- a/util.hpp
+++ b/util.hpp
@@ -1,12 +1,31 @@
 #ifndef SASS_UTIL_H
 #define SASS_UTIL_H
 
-#include "ast.hpp"
-
+#include <vector>
 #include <string>
+#include "ast_fwd_decl.hpp"
+
 namespace Sass {
+  using namespace std;
+
+  string string_escape(const string& str);
+  string string_unescape(const string& str);
+  string evacuate_quotes(const string& str);
+  string evacuate_escapes(const string& str);
+  string string_to_output(const string& str);
+  string comment_to_string(const string& text);
+  string normalize_wspace(const string& str);
+
+  string quote(const string&, char q = 0);
+  string unquote(const string&, char* q = 0);
+  char detect_best_quotemark(const char* s, char qm = '"');
+
+  bool is_hex_doublet(double n);
+  bool is_color_doublet(double r, double g, double b);
+
+  bool peek_linefeed(const char* start);
+
   namespace Util {
-    using namespace std;
 
     string normalize_underscores(const string& str);
     string normalize_decimals(const string& str);
@@ -15,10 +34,10 @@ namespace Sass {
     string vecJoin(const vector<string>& vec, const string& sep);
     bool containsAnyPrintableStatements(Block* b);
 
-    bool isPrintable(Ruleset* r);
-    bool isPrintable(Feature_Block* r);
-    bool isPrintable(Media_Block* r);
-    bool isPrintable(Block* b);
+    bool isPrintable(Ruleset* r, Output_Style style = NESTED);
+    bool isPrintable(Feature_Block* r, Output_Style style = NESTED);
+    bool isPrintable(Media_Block* r, Output_Style style = NESTED);
+    bool isPrintable(Block* b, Output_Style style = NESTED);
     bool isAscii(int ch);
 
   }
diff --git a/win/libsass.filters b/win/libsass.filters
index 6d53a53bfa..a165dd0433 100644
--- a/win/libsass.filters
+++ b/win/libsass.filters
@@ -69,10 +69,10 @@
     <ClCompile Include="..\node.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\output_compressed.cpp">
+    <ClCompile Include="..\output.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\output_nested.cpp">
+    <ClCompile Include="..\emitter.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
     <ClCompile Include="..\parser.cpp">
@@ -224,10 +224,10 @@
     <ClInclude Include="..\operation.hpp">
       <Filter>Header Files</Filter>
     </ClInclude>
-    <ClInclude Include="..\output_compressed.hpp">
+    <ClInclude Include="..\output.hpp">
       <Filter>Header Files</Filter>
     </ClInclude>
-    <ClInclude Include="..\output_nested.hpp">
+    <ClInclude Include="..\emitter.hpp">
       <Filter>Header Files</Filter>
     </ClInclude>
     <ClInclude Include="..\parser.hpp">
diff --git a/win/libsass.vcxproj b/win/libsass.vcxproj
index b119a9d5d2..434f80767d 100644
--- a/win/libsass.vcxproj
+++ b/win/libsass.vcxproj
@@ -175,8 +175,8 @@
     <ClCompile Include="..\inspect.cpp" />
     <ClCompile Include="..\json.cpp" />
     <ClCompile Include="..\node.cpp" />
-    <ClCompile Include="..\output_compressed.cpp" />
-    <ClCompile Include="..\output_nested.cpp" />
+    <ClCompile Include="..\emitter.cpp" />
+    <ClCompile Include="..\output.cpp" />
     <ClCompile Include="..\parser.cpp" />
     <ClCompile Include="..\position.cpp" />
     <ClCompile Include="..\prelexer.cpp" />
@@ -225,8 +225,8 @@
     <ClInclude Include="..\memory_manager.hpp" />
     <ClInclude Include="..\node.hpp" />
     <ClInclude Include="..\operation.hpp" />
-    <ClInclude Include="..\output_compressed.hpp" />
-    <ClInclude Include="..\output_nested.hpp" />
+    <ClInclude Include="..\emitter.hpp" />
+    <ClInclude Include="..\output.hpp" />
     <ClInclude Include="..\parser.hpp" />
     <ClInclude Include="..\paths.hpp" />
     <ClInclude Include="..\position.hpp" />