diff --git a/Bindings/Libsass/Values.hs b/Bindings/Libsass/Values.hs
--- a/Bindings/Libsass/Values.hs
+++ b/Bindings/Libsass/Values.hs
@@ -67,6 +67,15 @@
     :: Ptr SassValue
     -> IO CString
 
+foreign import ccall unsafe "sass_values.h" sass_string_is_quoted
+    :: Ptr SassValue
+    -> IO Bool
+
+foreign import ccall unsafe "sass_values.h" sass_string_set_quoted
+    :: Ptr SassValue
+    -> Bool
+    -> IO ()
+
 foreign import ccall unsafe "sass_values.h" sass_string_set_value
     :: Ptr SassValue
     -> CString
@@ -193,6 +202,10 @@
     -> IO (Ptr SassValue)
 
 foreign import ccall unsafe "sass_values.h" sass_make_string
+    :: CString
+    -> IO (Ptr SassValue)
+
+foreign import ccall unsafe "sass_values.h" sass_make_qstring
     :: CString
     -> IO (Ptr SassValue)
 
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,23 @@
+# Change Log
+All notable changes to this project will be documented in this file.
+
+## [0.1.1.1] - 2015-04-12
+### Added
+- This CHANGELOG file.
+- `.editorconfig` file.
+- Tests for Libsass version.
+
+### Fixed
+- libsass is not specified twice in extra libraries.
+
+## [0.1.1.0] - 2015-04-11
+### Fixed
+- Build process - `cabal install` now works correctly
+
+## 0.1.0.0 - 2015-04-11
+### Added
+- Bindings to Libsass C API
+- Basic tests
+
+[0.1.1.1]: https://github.com/jakubfijalkowski/hlibsass/compare/v10.1.1.0...0.1.1.1
+[0.1.1.0]: https://github.com/jakubfijalkowski/hlibsass/compare/v0.1.0.0...v0.1.1.0
diff --git a/hlibsass.cabal b/hlibsass.cabal
--- a/hlibsass.cabal
+++ b/hlibsass.cabal
@@ -1,5 +1,5 @@
 name:                hlibsass
-version:             0.1.1.0
+version:             0.1.2.0
 license:             MIT
 license-file:        LICENSE
 author:              Jakub Fijałkowski <fiolek94@gmail.com>
@@ -14,7 +14,7 @@
   This package provides (very) low level bindings to libsass. It uses libsass
   compiled to static library, so if you use this in your project, you have to
   link your project with C++ runtime(which libsass does automatically - links
-  with libstd++).
+  with /libstdc++/).
   For documentation visit <https://github.com/sass/libsass>.
 
 extra-source-files:
@@ -28,6 +28,7 @@
   libsass/utf8/*.h
   libsass/Makefile
   libsass/LICENSE
+  CHANGELOG.md
 
 source-repository head
   type:              git
@@ -45,9 +46,8 @@
   hs-source-dirs:      .
   default-language:    Haskell2010
   default-extensions:  ForeignFunctionInterface
-  extra-libraries:     sass
   ghc-options:         -Wall
-  extra-libraries:     stdc++, sass
+  extra-libraries:     sass, stdc++
 
 test-suite tests
   hs-source-dirs:      tests
diff --git a/libsass/Makefile b/libsass/Makefile
--- a/libsass/Makefile
+++ b/libsass/Makefile
@@ -4,9 +4,15 @@
 CP       ?= cp -a
 MKDIR    ?= mkdir
 WINDRES  ?= windres
-CFLAGS   ?= -Wall -O2
-CXXFLAGS ?= -Wall -O2
-LDFLAGS  ?= -Wall -O2 -Wl,--no-undefined
+CFLAGS   ?= -Wall
+CXXFLAGS ?= -Wall
+LDFLAGS  ?= -Wall
+ifneq "$(COVERAGE)" "yes"
+  CFLAGS   += -O2
+  CXXFLAGS += -O2
+  LDFLAGS  += -O2
+endif
+LDFLAGS  += -Wl,-undefined,error
 CAT      ?= $(if $(filter $(OS),Windows_NT),type,cat)
 
 ifneq (,$(findstring /cygdrive/,$(PATH)))
diff --git a/libsass/ast.cpp b/libsass/ast.cpp
--- a/libsass/ast.cpp
+++ b/libsass/ast.cpp
@@ -8,6 +8,8 @@
 namespace Sass {
   using namespace std;
 
+  static Null sass_null(Sass::Null(ParserState("null")));
+
   bool Compound_Selector::operator<(const Compound_Selector& rhs) const
   {
     To_String to_string;
@@ -24,29 +26,29 @@
   }
 
   bool Complex_Selector::operator==(const Complex_Selector& rhs) const {
-  	// TODO: We have to access the tail directly using tail_ since ADD_PROPERTY doesn't provide a const version.
+    // TODO: We have to access the tail directly using tail_ since ADD_PROPERTY doesn't provide a const version.
 
-  	const Complex_Selector* pOne = this;
+    const Complex_Selector* pOne = this;
     const Complex_Selector* pTwo = &rhs;
 
     // Consume any empty references at the beginning of the Complex_Selector
     if (pOne->combinator() == Complex_Selector::ANCESTOR_OF && pOne->head()->is_empty_reference()) {
-    	pOne = pOne->tail_;
+      pOne = pOne->tail_;
     }
     if (pTwo->combinator() == Complex_Selector::ANCESTOR_OF && pTwo->head()->is_empty_reference()) {
-    	pTwo = pTwo->tail_;
+      pTwo = pTwo->tail_;
     }
 
     while (pOne && pTwo) {
-    	if (pOne->combinator() != pTwo->combinator()) {
-      	return false;
+      if (pOne->combinator() != pTwo->combinator()) {
+        return false;
       }
 
       if (*(pOne->head()) != *(pTwo->head())) {
-      	return false;
+        return false;
       }
 
-    	pOne = pOne->tail_;
+      pOne = pOne->tail_;
       pTwo = pTwo->tail_;
     }
 
@@ -66,10 +68,10 @@
 
   bool Simple_Selector::operator==(const Simple_Selector& rhs) const
   {
-  	// Compare the string representations for equality.
+    // Compare the string representations for equality.
 
-  	// Cast away const here. To_String should take a const object, but it doesn't.
-  	Simple_Selector* pLHS = const_cast<Simple_Selector*>(this);
+    // Cast away const here. To_String should take a const object, but it doesn't.
+    Simple_Selector* pLHS = const_cast<Simple_Selector*>(this);
     Simple_Selector* pRHS = const_cast<Simple_Selector*>(&rhs);
 
     To_String to_string;
@@ -77,10 +79,10 @@
   }
 
   bool Simple_Selector::operator<(const Simple_Selector& rhs) const {
-		// Use the string representation for ordering.
+    // Use the string representation for ordering.
 
-  	// Cast away const here. To_String should take a const object, but it doesn't.
-  	Simple_Selector* pLHS = const_cast<Simple_Selector*>(this);
+    // Cast away const here. To_String should take a const object, but it doesn't.
+    Simple_Selector* pLHS = const_cast<Simple_Selector*>(this);
     Simple_Selector* pRHS = const_cast<Simple_Selector*>(&rhs);
 
     To_String to_string;
@@ -215,32 +217,46 @@
     set<string> lpsuedoset, rpsuedoset;
     for (size_t i = 0, L = length(); i < L; ++i)
     {
-    	if ((*this)[i]->is_pseudo_element()) {
-      	string pseudo((*this)[i]->perform(&to_string));
+      if ((*this)[i]->is_pseudo_element()) {
+        string pseudo((*this)[i]->perform(&to_string));
         pseudo = pseudo.substr(pseudo.find_first_not_of(":")); // strip off colons to ensure :after matches ::after since ruby sass is forgiving
-      	lpsuedoset.insert(pseudo);
+        lpsuedoset.insert(pseudo);
       }
     }
     for (size_t i = 0, L = rhs->length(); i < L; ++i)
     {
-    	if ((*rhs)[i]->is_pseudo_element()) {
-      	string pseudo((*rhs)[i]->perform(&to_string));
+      if ((*rhs)[i]->is_pseudo_element()) {
+        string pseudo((*rhs)[i]->perform(&to_string));
         pseudo = pseudo.substr(pseudo.find_first_not_of(":")); // strip off colons to ensure :after matches ::after since ruby sass is forgiving
-	    	rpsuedoset.insert(pseudo);
+        rpsuedoset.insert(pseudo);
       }
     }
-  	if (lpsuedoset != rpsuedoset) {
+    if (lpsuedoset != rpsuedoset) {
       return false;
     }
 
-		// Check the Simple_Selectors
+    // Check the Simple_Selectors
 
     set<string> lset, rset;
 
     if (!lbase) // no lbase; just see if the left-hand qualifiers are a subset of the right-hand selector
     {
       for (size_t i = 0, L = length(); i < L; ++i)
-      { lset.insert((*this)[i]->perform(&to_string)); }
+      {
+        Selector* lhs = (*this)[i];
+        // very special case for wrapped matches selector
+        if (Wrapped_Selector* wrapped = dynamic_cast<Wrapped_Selector*>(lhs)) {
+          if (wrapped->name() == ":matches(" || wrapped->name() == ":-moz-any(") {
+            if (Selector_List* list = dynamic_cast<Selector_List*>(wrapped->selector())) {
+              if (Compound_Selector* comp = dynamic_cast<Compound_Selector*>(rhs)) {
+                if (list->is_superselector_of(comp)) return true;
+              }
+            }
+          }
+        }
+        // match from here on as strings
+        lset.insert(lhs->perform(&to_string));
+      }
       for (size_t i = 0, L = rhs->length(); i < L; ++i)
       { rset.insert((*rhs)[i]->perform(&to_string)); }
       return includes(rset.begin(), rset.end(), lset.begin(), lset.end());
@@ -272,33 +288,33 @@
     set<string> lpsuedoset, rpsuedoset;
     for (size_t i = 0, L = length(); i < L; ++i)
     {
-    	if ((*this)[i]->is_pseudo_element()) {
-      	string pseudo((*this)[i]->perform(&to_string));
+      if ((*this)[i]->is_pseudo_element()) {
+        string pseudo((*this)[i]->perform(&to_string));
         pseudo = pseudo.substr(pseudo.find_first_not_of(":")); // strip off colons to ensure :after matches ::after since ruby sass is forgiving
-      	lpsuedoset.insert(pseudo);
+        lpsuedoset.insert(pseudo);
       }
     }
     for (size_t i = 0, L = rhs.length(); i < L; ++i)
     {
-    	if (rhs[i]->is_pseudo_element()) {
-      	string pseudo(rhs[i]->perform(&to_string));
+      if (rhs[i]->is_pseudo_element()) {
+        string pseudo(rhs[i]->perform(&to_string));
         pseudo = pseudo.substr(pseudo.find_first_not_of(":")); // strip off colons to ensure :after matches ::after since ruby sass is forgiving
-	    	rpsuedoset.insert(pseudo);
+        rpsuedoset.insert(pseudo);
       }
     }
-  	if (lpsuedoset != rpsuedoset) {
+    if (lpsuedoset != rpsuedoset) {
       return false;
     }
 
-		// Check the base
+    // Check the base
 
     const Simple_Selector* const lbase = base();
     const Simple_Selector* const rbase = rhs.base();
 
     if ((lbase && !rbase) ||
-    	(!lbase && rbase) ||
+      (!lbase && rbase) ||
       ((lbase && rbase) && (*lbase != *rbase))) {
-			return false;
+      return false;
     }
 
 
@@ -324,8 +340,6 @@
 
   bool Complex_Selector::is_superselector_of(Compound_Selector* rhs)
   {
-    if (length() != 1)
-    { return false; }
     return base()->is_superselector_of(rhs);
   }
 
@@ -350,6 +364,16 @@
     if (l_len == 1)
     { return lhs->head()->is_superselector_of(rhs->base()); }
 
+    // we have to look one tail deeper, since we cary the
+    // combinator around for it (which is important here)
+    if (rhs->tail() && lhs->tail() && combinator() != Complex_Selector::ANCESTOR_OF) {
+      Complex_Selector* lhs_tail = lhs->tail();
+      Complex_Selector* rhs_tail = rhs->tail();
+      if (lhs_tail->combinator() != rhs_tail->combinator()) return false;
+      if (!lhs_tail->head()->is_superselector_of(rhs_tail->head())) return false;
+    }
+
+
     bool found = false;
     Complex_Selector* marker = rhs;
     for (size_t i = 0, L = rhs->length(); i < L; ++i) {
@@ -456,7 +480,7 @@
     Complex_Selector* cpy = new (ctx.mem) Complex_Selector(*this);
 
     if (head()) {
-    	cpy->head(head()->clone(ctx));
+      cpy->head(head()->clone(ctx));
     }
 
     if (tail()) {
@@ -491,6 +515,50 @@
 #endif
   }
 
+  // it's a superselector if every selector of the right side
+  // list is a superselector of the given left side selector
+  bool Complex_Selector::is_superselector_of(Selector_List *sub)
+  {
+    // Check every rhs selector against left hand list
+    for(size_t i = 0, L = sub->length(); i < L; ++i) {
+      if (!is_superselector_of((*sub)[i])) return false;
+    }
+    return true;
+  }
+
+  // it's a superselector if every selector of the right side
+  // list is a superselector of the given left side selector
+  bool Selector_List::is_superselector_of(Selector_List *sub)
+  {
+    // Check every rhs selector against left hand list
+    for(size_t i = 0, L = sub->length(); i < L; ++i) {
+      if (!is_superselector_of((*sub)[i])) return false;
+    }
+    return true;
+  }
+
+  // it's a superselector if every selector on the right side
+  // is a superselector of any one of the left side selectors
+  bool Selector_List::is_superselector_of(Compound_Selector *sub)
+  {
+    // Check every lhs selector against right hand
+    for(size_t i = 0, L = length(); i < L; ++i) {
+      if ((*this)[i]->is_superselector_of(sub)) return true;
+    }
+    return false;
+  }
+
+  // it's a superselector if every selector on the right side
+  // is a superselector of any one of the left side selectors
+  bool Selector_List::is_superselector_of(Complex_Selector *sub)
+  {
+    // Check every lhs selector against right hand
+    for(size_t i = 0, L = length(); i < L; ++i) {
+      if ((*this)[i]->is_superselector_of(sub)) return true;
+    }
+    return false;
+  }
+
   /* not used anymore - remove?
   Selector_Placeholder* Selector_List::find_placeholder()
   {
@@ -586,6 +654,292 @@
     }
     return result;
   }*/
+
+  Number::Number(ParserState pstate, double val, string u, bool zero)
+  : Expression(pstate),
+    value_(val),
+    zero_(zero),
+    numerator_units_(vector<string>()),
+    denominator_units_(vector<string>()),
+    hash_(0)
+  {
+    size_t l = 0, r = 0;
+    if (!u.empty()) {
+      bool nominator = true;
+      while (true) {
+        r = u.find_first_of("*/", l);
+        string unit(u.substr(l, r - l));
+        if (nominator) numerator_units_.push_back(unit);
+        else denominator_units_.push_back(unit);
+        if (u[r] == '/') nominator = false;
+        if (r == string::npos) break;
+        else l = r + 1;
+      }
+    }
+    concrete_type(NUMBER);
+  }
+
+  string Number::unit() const
+  {
+    stringstream u;
+    for (size_t i = 0, S = numerator_units_.size(); i < S; ++i) {
+      if (i) u << '*';
+      u << numerator_units_[i];
+    }
+    if (!denominator_units_.empty()) u << '/';
+    for (size_t i = 0, S = denominator_units_.size(); i < S; ++i) {
+      if (i) u << '*';
+      u << denominator_units_[i];
+    }
+    return u.str();
+  }
+
+  bool Number::is_unitless()
+  { return numerator_units_.empty() && denominator_units_.empty(); }
+
+  void Number::normalize(const string& prefered)
+  {
+
+    // first make sure same units cancel each other out
+    // it seems that a map table will fit nicely to do this
+    // we basically construct exponents for each unit
+    // has the advantage that they will be pre-sorted
+    map<string, int> exponents;
+
+    // initialize by summing up occurences in unit vectors
+    for (size_t i = 0, S = numerator_units_.size(); i < S; ++i) ++ exponents[numerator_units_[i]];
+    for (size_t i = 0, S = denominator_units_.size(); i < S; ++i) -- exponents[denominator_units_[i]];
+
+    // the final conversion factor
+    double factor = 1;
+
+    // get the first entry of numerators
+    // forward it when entry is converted
+    vector<string>::iterator nom_it = numerator_units_.begin();
+    vector<string>::iterator nom_end = numerator_units_.end();
+    vector<string>::iterator denom_it = denominator_units_.begin();
+    vector<string>::iterator denom_end = denominator_units_.end();
+
+    // main normalization loop
+    // should be close to optimal
+    while (denom_it != denom_end)
+    {
+      // get and increment afterwards
+      const string denom = *(denom_it ++);
+      // skip already canceled out unit
+      if (exponents[denom] >= 0) continue;
+      // skip all units we don't know how to convert
+      if (string_to_unit(denom) == UNKNOWN) continue;
+      // now search for nominator
+      while (nom_it != nom_end)
+      {
+        // get and increment afterwards
+        const string nom = *(nom_it ++);
+        // skip already canceled out unit
+        if (exponents[nom] <= 0) continue;
+        // skip all units we don't know how to convert
+        if (string_to_unit(nom) == UNKNOWN) continue;
+        // we now have two convertable units
+        // add factor for current conversion
+        factor *= conversion_factor(nom, denom);
+        // update nominator/denominator exponent
+        -- exponents[nom]; ++ exponents[denom];
+        // inner loop done
+        break;
+      }
+    }
+
+    // now we can build up the new unit arrays
+    numerator_units_.clear();
+    denominator_units_.clear();
+
+    // build them by iterating over the exponents
+    for (auto exp : exponents)
+    {
+      // maybe there is more effecient way to push
+      // the same item multiple times to a vector?
+      for(size_t i = 0, S = abs(exp.second); i < S; ++i)
+      {
+        // opted to have these switches in the inner loop
+        // makes it more readable and should not cost much
+        if (exp.second < 0) denominator_units_.push_back(exp.first);
+        else if (exp.second > 0) numerator_units_.push_back(exp.first);
+      }
+    }
+
+    // apply factor to value_
+    // best precision this way
+    value_ *= factor;
+
+    // maybe convert to other unit
+    // easier implemented on its own
+    try { convert(prefered); }
+    catch (incompatibleUnits& err)
+    { error(err.what(), pstate()); }
+    catch (...) { throw; }
+
+  }
+
+  void Number::convert(const string& prefered)
+  {
+    // abort if unit is empty
+    if (prefered.empty()) return;
+
+    // first make sure same units cancel each other out
+    // it seems that a map table will fit nicely to do this
+    // we basically construct exponents for each unit
+    // has the advantage that they will be pre-sorted
+    map<string, int> exponents;
+
+    // initialize by summing up occurences in unit vectors
+    for (size_t i = 0, S = numerator_units_.size(); i < S; ++i) ++ exponents[numerator_units_[i]];
+    for (size_t i = 0, S = denominator_units_.size(); i < S; ++i) -- exponents[denominator_units_[i]];
+
+    // the final conversion factor
+    double factor = 1;
+
+    vector<string>::iterator denom_it = denominator_units_.begin();
+    vector<string>::iterator denom_end = denominator_units_.end();
+
+    // main normalization loop
+    // should be close to optimal
+    while (denom_it != denom_end)
+    {
+      // get and increment afterwards
+      const string denom = *(denom_it ++);
+      // check if conversion is needed
+      if (denom == prefered) continue;
+      // skip already canceled out unit
+      if (exponents[denom] >= 0) continue;
+      // skip all units we don't know how to convert
+      if (string_to_unit(denom) == UNKNOWN) continue;
+      // we now have two convertable units
+      // add factor for current conversion
+      factor *= conversion_factor(denom, prefered);
+      // update nominator/denominator exponent
+      ++ exponents[denom]; -- exponents[prefered];
+    }
+
+    vector<string>::iterator nom_it = numerator_units_.begin();
+    vector<string>::iterator nom_end = numerator_units_.end();
+
+    // now search for nominator
+    while (nom_it != nom_end)
+    {
+      // get and increment afterwards
+      const string nom = *(nom_it ++);
+      // check if conversion is needed
+      if (nom == prefered) continue;
+      // skip already canceled out unit
+      if (exponents[nom] <= 0) continue;
+      // skip all units we don't know how to convert
+      if (string_to_unit(nom) == UNKNOWN) continue;
+      // we now have two convertable units
+      // add factor for current conversion
+      factor *= conversion_factor(nom, prefered);
+      // update nominator/denominator exponent
+      -- exponents[nom]; ++ exponents[prefered];
+    }
+
+    // now we can build up the new unit arrays
+    numerator_units_.clear();
+    denominator_units_.clear();
+
+    // build them by iterating over the exponents
+    for (auto exp : exponents)
+    {
+      // maybe there is more effecient way to push
+      // the same item multiple times to a vector?
+      for(size_t i = 0, S = abs(exp.second); i < S; ++i)
+      {
+        // opted to have these switches in the inner loop
+        // makes it more readable and should not cost much
+        if (exp.second < 0) denominator_units_.push_back(exp.first);
+        else if (exp.second > 0) numerator_units_.push_back(exp.first);
+      }
+    }
+
+    // apply factor to value_
+    // best precision this way
+    value_ *= factor;
+
+  }
+
+  // useful for making one number compatible with another
+  string Number::find_convertible_unit() const
+  {
+    for (size_t i = 0, S = numerator_units_.size(); i < S; ++i) {
+      string u(numerator_units_[i]);
+      if (string_to_unit(u) != UNKNOWN) return u;
+    }
+    for (size_t i = 0, S = denominator_units_.size(); i < S; ++i) {
+      string u(denominator_units_[i]);
+      if (string_to_unit(u) != UNKNOWN) return u;
+    }
+    return string();
+  }
+
+
+  bool Number::operator== (Expression* rhs) const
+  {
+    try
+    {
+      Number l(pstate_, value_, unit());
+      Number& r = dynamic_cast<Number&>(*rhs);
+      l.normalize(find_convertible_unit());
+      r.normalize(find_convertible_unit());
+      return l.unit() == r.unit() &&
+             l.value() == r.value();
+    }
+    catch (std::bad_cast&) {}
+    catch (...) { throw; }
+    return false;
+  }
+
+  bool Number::operator== (Expression& rhs) const
+  {
+    return operator==(&rhs);
+  }
+
+  bool List::operator==(Expression* rhs) const
+  {
+    try
+    {
+      List* r = dynamic_cast<List*>(rhs);
+      if (!r || length() != r->length()) return false;
+      if (separator() != r->separator()) return false;
+      for (size_t i = 0, L = r->length(); i < L; ++i)
+        if (*elements()[i] != *(*r)[i]) return false;
+      return true;
+    }
+    catch (std::bad_cast&) {}
+    catch (...) { throw; }
+    return false;
+  }
+
+  bool List::operator== (Expression& rhs) const
+  {
+    return operator==(&rhs);
+  }
+
+  size_t List::size() const {
+    if (!is_arglist_) return length();
+    // arglist expects a list of arguments
+    // so we need to break before keywords
+    for (size_t i = 0, L = length(); i < L; ++i) {
+      if (Argument* arg = dynamic_cast<Argument*>((*this)[i])) {
+        if (!arg->name().empty()) return i;
+      }
+    }
+    return length();
+  }
+
+  Expression* Hashed::at(Expression* k) const
+  {
+    if (elements_.count(k))
+    { return elements_.at(k); }
+    else { return &sass_null; }
+  }
 
 }
 
diff --git a/libsass/ast.hpp b/libsass/ast.hpp
--- a/libsass/ast.hpp
+++ b/libsass/ast.hpp
@@ -113,6 +113,7 @@
     static string type_name() { return ""; }
     virtual bool is_false() { return false; }
     virtual bool operator==( Expression& rhs) const { return false; }
+    virtual void set_delayed(bool delayed) { is_delayed(delayed); }
     virtual size_t hash() { return 0; }
   };
 }
@@ -210,9 +211,10 @@
     size_t length() const                  { return list_.size(); }
     bool empty() const                     { return list_.empty(); }
     bool has(Expression* k) const          { return elements_.count(k) == 1; }
-    Expression* at(Expression* k) const    { return elements_.at(k); }
+    Expression* at(Expression* k) const;
     bool has_duplicate_key() const         { return duplicate_key_ != 0; }
     Expression* get_duplicate_key() const  { return duplicate_key_; }
+    const unordered_map<Expression*, Expression*> elements() { return elements_; }
     Hashed& operator<<(pair<Expression*, Expression*> p)
     {
       reset_hash();
@@ -755,23 +757,9 @@
     bool is_invisible() { return !length(); }
     Expression* value_at_index(size_t i);
 
-    virtual bool operator==(Expression& rhs) const
-    {
-      try
-      {
-        List& l = dynamic_cast<List&>(rhs);
-        if (!(l && length() == l.length() && separator() == l.separator())) return false;
-        for (size_t i = 0, L = l.length(); i < L; ++i)
-          if (!(*(elements()[i]) == *(l[i]))) return false;
-        return true;
-      }
-      catch (std::bad_cast&)
-      {
-        return false;
-      }
-      catch (...) { throw; }
-
-    }
+    virtual size_t size() const;
+    virtual bool operator==(Expression& rhs) const;
+    virtual bool operator==(Expression* rhs) const;
 
     virtual size_t hash()
     {
@@ -785,6 +773,13 @@
       return hash_;
     }
 
+    virtual void set_delayed(bool delayed)
+    {
+      for (size_t i = 0, L = length(); i < L; ++i)
+        (elements()[i])->set_delayed(delayed);
+      is_delayed(delayed);
+    }
+
     ATTACH_OPERATIONS();
   };
 
@@ -850,11 +845,59 @@
     ADD_PROPERTY(Type, type);
     ADD_PROPERTY(Expression*, left);
     ADD_PROPERTY(Expression*, right);
+    size_t hash_;
   public:
     Binary_Expression(ParserState pstate,
                       Type t, Expression* lhs, Expression* rhs)
-    : Expression(pstate), type_(t), left_(lhs), right_(rhs)
+    : Expression(pstate), type_(t), left_(lhs), right_(rhs), hash_(0)
     { }
+    const string type_name() {
+      switch (type_) {
+        case AND: return "and"; break;
+        case OR: return "or"; break;
+        case EQ: return "eq"; break;
+        case NEQ: return "neq"; break;
+        case GT: return "gt"; break;
+        case GTE: return "gte"; break;
+        case LT: return "lt"; break;
+        case LTE: return "lte"; break;
+        case ADD: return "add"; break;
+        case SUB: return "sub"; break;
+        case MUL: return "mul"; break;
+        case DIV: return "div"; break;
+        case MOD: return "mod"; break;
+        case NUM_OPS: return "num_ops"; break;
+        default: return "invalid"; break;
+      }
+    }
+    virtual void set_delayed(bool delayed)
+    {
+      right()->set_delayed(delayed);
+      left()->set_delayed(delayed);
+      is_delayed(delayed);
+    }
+    virtual bool operator==(Expression& rhs) const
+    {
+      try
+      {
+        Binary_Expression& m = dynamic_cast<Binary_Expression&>(rhs);
+        if (m == 0) return false;
+        return type() == m.type() &&
+               left() == m.left() &&
+               right() == m.right();
+      }
+      catch (std::bad_cast&)
+      {
+        return false;
+      }
+      catch (...) { throw; }
+    }
+    virtual size_t hash()
+    {
+      if (hash_ > 0) return hash_;
+      hash_ = left()->hash() ^ right()->hash() ^ std::hash<size_t>()(type_);
+      return hash_;
+    }
     ATTACH_OPERATIONS();
   };
 
@@ -867,10 +910,40 @@
   private:
     ADD_PROPERTY(Type, type);
     ADD_PROPERTY(Expression*, operand);
+    size_t hash_;
   public:
     Unary_Expression(ParserState pstate, Type t, Expression* o)
-    : Expression(pstate), type_(t), operand_(o)
+    : Expression(pstate), type_(t), operand_(o), hash_(0)
     { }
+    const string type_name() {
+      switch (type_) {
+        case PLUS: return "plus"; break;
+        case MINUS: return "minus"; break;
+        case NOT: return "not"; break;
+        default: return "invalid"; break;
+      }
+    }
+    virtual bool operator==(Expression& rhs) const
+    {
+      try
+      {
+        Unary_Expression& m = dynamic_cast<Unary_Expression&>(rhs);
+        if (m == 0) return false;
+        return type() == m.type() &&
+               operand() == m.operand();
+      }
+      catch (std::bad_cast&)
+      {
+        return false;
+      }
+      catch (...) { throw; }
+    }
+    virtual size_t hash()
+    {
+      if (hash_ > 0) return hash_;
+      hash_ = operand()->hash() ^ std::hash<size_t>()(type_);
+      return hash_;
+    }
     ATTACH_OPERATIONS();
   };
 
@@ -898,7 +971,7 @@
       {
         Argument& m = dynamic_cast<Argument&>(rhs);
         if (!(m && name() == m.name())) return false;
-        return *value() == *value();
+        return *value() == *m.value();
       }
       catch (std::bad_cast&)
       {
@@ -1115,129 +1188,22 @@
     vector<string> denominator_units_;
     size_t hash_;
   public:
-    Number(ParserState pstate, double val, string u = "", bool zero = true)
-    : Expression(pstate),
-      value_(val),
-      zero_(zero),
-      numerator_units_(vector<string>()),
-      denominator_units_(vector<string>()),
-      hash_(0)
-    {
-      if (!u.empty()) numerator_units_.push_back(u);
-      concrete_type(NUMBER);
-    }
+    Number(ParserState pstate, double val, string u = "", bool zero = true);
     bool            zero()              { return zero_; }
     vector<string>& numerator_units()   { return numerator_units_; }
     vector<string>& denominator_units() { return denominator_units_; }
     string type() { return "number"; }
     static string type_name() { return "number"; }
-    string unit() const
-    {
-      stringstream u;
-      for (size_t i = 0, S = numerator_units_.size(); i < S; ++i) {
-        if (i) u << '*';
-        u << numerator_units_[i];
-      }
-      if (!denominator_units_.empty()) u << '/';
-      for (size_t i = 0, S = denominator_units_.size(); i < S; ++i) {
-        if (i) u << '*';
-        u << denominator_units_[i];
-      }
-      return u.str();
-    }
-    bool is_unitless()
-    { return numerator_units_.empty() && denominator_units_.empty(); }
-    void normalize(string to = "")
-    {
-      // (multiple passes because I'm too tired to think up something clever)
-      // Find a unit to convert everything to, if one isn't provided.
-      if (to.empty()) {
-        for (size_t i = 0, S = numerator_units_.size(); i < S; ++i) {
-          string u(numerator_units_[i]);
-          if (string_to_unit(u) == INCOMMENSURABLE) {
-            continue;
-          }
-          else {
-            to = u;
-            break;
-          }
-        }
-      }
-      if (to.empty()) {
-        for (size_t i = 0, S = denominator_units_.size(); i < S; ++i) {
-          string u(denominator_units_[i]);
-          if (string_to_unit(u) == INCOMMENSURABLE) {
-            continue;
-          }
-          else {
-            to = u;
-            break;
-          }
-        }
-      }
-      // Now loop through again and do all the conversions.
-      for (size_t i = 0, S = numerator_units_.size(); i < S; ++i) {
-        string from(numerator_units_[i]);
-        if (string_to_unit(from) == INCOMMENSURABLE) continue;
-        value_ *= conversion_factor(from, to);
-        numerator_units_[i] = to;
-      }
-      for (size_t i = 0, S = denominator_units_.size(); i < S; ++i) {
-        string from(denominator_units_[i]);
-        if (string_to_unit(from) == INCOMMENSURABLE) continue;
-        value_ /= conversion_factor(from, to);
-        denominator_units_[i] = to;
-      }
-      // Now divide out identical units in the numerator and denominator.
-      vector<string> ncopy;
-      ncopy.reserve(numerator_units_.size());
-      for (vector<string>::iterator n = numerator_units_.begin();
-           n != numerator_units_.end();
-           ++n) {
-        vector<string>::iterator d = find(denominator_units_.begin(),
-                                          denominator_units_.end(),
-                                          *n);
-        if (d != denominator_units_.end()) {
-          denominator_units_.erase(d);
-        }
-        else {
-          ncopy.push_back(*n);
-        }
-      }
-      numerator_units_ = ncopy;
-      // Sort the units to make them pretty and, well, normal.
-      sort(numerator_units_.begin(), numerator_units_.end());
-      sort(denominator_units_.begin(), denominator_units_.end());
-    }
+    string unit() const;
+
+    bool is_unitless();
+    void convert(const string& unit = "");
+    void normalize(const string& unit = "");
     // useful for making one number compatible with another
-    string find_convertible_unit() const
-    {
-      for (size_t i = 0, S = numerator_units_.size(); i < S; ++i) {
-        string u(numerator_units_[i]);
-        if (string_to_unit(u) != INCOMMENSURABLE) return u;
-      }
-      for (size_t i = 0, S = denominator_units_.size(); i < S; ++i) {
-        string u(denominator_units_[i]);
-        if (string_to_unit(u) != INCOMMENSURABLE) return u;
-      }
-      return string();
-    }
+    string find_convertible_unit() const;
 
-    virtual bool operator==(Expression& rhs) const
-    {
-      try
-      {
-        Number& e(dynamic_cast<Number&>(rhs));
-        if (!e) return false;
-        e.normalize(find_convertible_unit());
-        return unit() == e.unit() && value() == e.value();
-      }
-      catch (std::bad_cast&)
-      {
-        return false;
-      }
-      catch (...) { throw; }
-    }
+    virtual bool operator== (Expression& rhs) const;
+    virtual bool operator== (Expression* rhs) const;
 
     virtual size_t hash()
     {
@@ -1394,21 +1360,22 @@
   ////////////////////////////////////////////////////////
   class String_Constant : public String {
     ADD_PROPERTY(char, quote_mark);
+    ADD_PROPERTY(bool, can_compress_whitespace);
     ADD_PROPERTY(string, value);
   protected:
     size_t hash_;
   public:
     String_Constant(ParserState pstate, string val)
-    : String(pstate), quote_mark_(0), value_(read_css_string(val)), hash_(0)
+    : String(pstate), quote_mark_(0), can_compress_whitespace_(false), value_(read_css_string(val)), hash_(0)
     { }
     String_Constant(ParserState pstate, const char* beg)
-    : String(pstate), quote_mark_(0), value_(read_css_string(string(beg))), hash_(0)
+    : String(pstate), quote_mark_(0), can_compress_whitespace_(false), value_(read_css_string(string(beg))), hash_(0)
     { }
     String_Constant(ParserState pstate, const char* beg, const char* end)
-    : String(pstate), quote_mark_(0), value_(read_css_string(string(beg, end-beg))), hash_(0)
+    : String(pstate), quote_mark_(0), can_compress_whitespace_(false), value_(read_css_string(string(beg, end-beg))), hash_(0)
     { }
     String_Constant(ParserState pstate, const Token& tok)
-    : String(pstate), quote_mark_(0), value_(read_css_string(string(tok.begin, tok.end))), hash_(0)
+    : String(pstate), quote_mark_(0), can_compress_whitespace_(false), value_(read_css_string(string(tok.begin, tok.end))), hash_(0)
     { }
     string type() { return "string"; }
     static string type_name() { return "string"; }
@@ -1976,7 +1943,9 @@
         return (*this)[0];
       return 0;
     }
-    bool is_superselector_of(Compound_Selector* rhs);
+    bool is_superselector_of(Compound_Selector* sub);
+    // bool is_superselector_of(Complex_Selector* sub);
+    // bool is_superselector_of(Selector_List* sub);
     virtual unsigned long specificity()
     {
       int sum = 0;
@@ -2033,8 +2002,9 @@
     Complex_Selector* context(Context&);
     Complex_Selector* innermost();
     size_t length();
-    bool is_superselector_of(Compound_Selector*);
-    bool is_superselector_of(Complex_Selector*);
+    bool is_superselector_of(Compound_Selector* sub);
+    bool is_superselector_of(Complex_Selector* sub);
+    bool is_superselector_of(Selector_List* sub);
     // virtual Selector_Placeholder* find_placeholder();
     Combinator clear_innermost();
     void set_innermost(Complex_Selector*, Combinator);
@@ -2119,6 +2089,9 @@
     : Selector(pstate), Vectorized<Complex_Selector*>(s), wspace_(0)
     { }
     // virtual Selector_Placeholder* find_placeholder();
+    bool is_superselector_of(Compound_Selector* sub);
+    bool is_superselector_of(Complex_Selector* sub);
+    bool is_superselector_of(Selector_List* sub);
     virtual unsigned long specificity()
     {
       unsigned long sum = 0;
diff --git a/libsass/backtrace.hpp b/libsass/backtrace.hpp
--- a/libsass/backtrace.hpp
+++ b/libsass/backtrace.hpp
@@ -41,7 +41,7 @@
              << "\t"
              << (++i == 0 ? "on" : "from")
              << " line "
-             << this_point->pstate.line
+             << this_point->pstate.line + 1
              << " of "
              << rel_path;
         } else {
@@ -49,7 +49,7 @@
              << "\t"
              << rel_path
              << ":"
-             << this_point->pstate.line
+             << this_point->pstate.line + 1
              << this_point->parent->caller;
         }
 
diff --git a/libsass/bind.cpp b/libsass/bind.cpp
--- a/libsass/bind.cpp
+++ b/libsass/bind.cpp
@@ -28,44 +28,108 @@
     size_t ip = 0, LP = ps->length();
     size_t ia = 0, LA = as->length();
     while (ia < LA) {
+      Argument* a = (*as)[ia];
       if (ip >= LP) {
+        // skip empty rest arguments
+        if (a->is_rest_argument()) {
+          if (List* l = dynamic_cast<List*>(a->value())) {
+            if (l->length() == 0) {
+              ++ ia; continue;
+            }
+          }
+        }
         stringstream msg;
         msg << callee << " only takes " << LP << " arguments; "
             << "given " << LA;
         error(msg.str(), as->pstate());
       }
       Parameter* p = (*ps)[ip];
-      Argument*  a = (*as)[ia];
 
       // If the current parameter is the rest parameter, process and break the loop
       if (p->is_rest_parameter()) {
+        // The next argument by coincidence provides a rest argument
         if (a->is_rest_argument()) {
-          // rest param and rest arg -- just add one to the other
-          if (env->has_local(p->name())) {
-            *static_cast<List*>(env->local_frame()[p->name()])
-            += static_cast<List*>(a->value());
+          // We should always get a list for rest arguments
+          if (List* rest = dynamic_cast<List*>(a->value())) {
+            // arg contains a list
+            List* args = rest;
+            // make sure it's an arglist
+            if (rest->is_arglist()) {
+              // can pass it through as it was
+              env->local_frame()[p->name()] = args;
+            }
+            // create a new list and wrap each item as an argument
+            // otherwise we will not be able to fetch it again
+            else {
+              // create a new list object for wrapped items
+              List* arglist = new (ctx.mem) List(p->pstate(),
+                                                 0,
+                                                 rest->separator(),
+                                                 true);
+              // wrap each item from list as an argument
+              for (Expression* item : rest->elements()) {
+                (*arglist) << new (ctx.mem) Argument(item->pstate(),
+                                                     item,
+                                                     "",
+                                                     false,
+                                                     false);
+              }
+              // assign new arglist to environment
+              env->local_frame()[p->name()] = arglist;
+            }
           }
+          // invalid state
           else {
-            env->local_frame()[p->name()] = a->value();
+            throw runtime_error("invalid state");
           }
+        } else if (a->is_keyword_argument()) {
+
+          // expand keyword arguments into their parameters
+          List* arglist = new (ctx.mem) List(p->pstate(), 0, List::COMMA, true);
+          env->local_frame()[p->name()] = arglist;
+          Map* argmap = static_cast<Map*>(a->value());
+          for (auto key : argmap->keys()) {
+            string name = unquote(static_cast<String_Constant*>(key)->value());
+            (*arglist) << new (ctx.mem) Argument(key->pstate(),
+                                                 argmap->at(key),
+                                                 name,
+                                                 false,
+                                                 false);
+          }
+
         } else {
 
-          // copy all remaining arguments into the rest parameter, preserving names
+          // create a new list object for wrapped items
           List* arglist = new (ctx.mem) List(p->pstate(),
                                              0,
                                              List::COMMA,
                                              true);
-          env->local_frame()[p->name()] = arglist;
+          // consume the next args
           while (ia < LA) {
-            a = (*as)[ia];
+            // get and post inc
+            a = (*as)[ia++];
+            // wrap current argument into new object
             (*arglist) << new (ctx.mem) Argument(a->pstate(),
                                                  a->value(),
                                                  a->name(),
+                                                 false,
                                                  false);
-            ++ia;
+            // check if we have rest argument
+            if (a->is_rest_argument()) {
+              // preserve the list separator from rest args
+              if (List* rest = dynamic_cast<List*>(a->value())) {
+                arglist->separator(rest->separator());
+              }
+              // no more arguments
+              break;
+            }
           }
+          // assign new arglist to environment
+          env->local_frame()[p->name()] = arglist;
         }
+        // consumed parameter
         ++ip;
+        // no more paramaters
         break;
       }
 
@@ -82,7 +146,11 @@
           a = static_cast<Argument*>((*arglist)[0]);
         } else {
           Expression* a_to_convert = (*arglist)[0];
-          a = new (ctx.mem) Argument(a_to_convert->pstate(), a_to_convert, "", false);
+          a = new (ctx.mem) Argument(a_to_convert->pstate(),
+                                     a_to_convert,
+                                     "",
+                                     false,
+                                     false);
         }
         arglist->elements().erase(arglist->elements().begin());
         if (!arglist->length() || (!arglist->is_arglist() && ip + 1 == LP)) {
@@ -140,6 +208,7 @@
         env->local_frame()[a->name()] = a->value();
       }
     }
+    // EO while ia
 
     // If we make it here, we're out of args but may have leftover params.
     // That's only okay if they have default values, or were already bound by
diff --git a/libsass/constants.cpp b/libsass/constants.cpp
--- a/libsass/constants.cpp
+++ b/libsass/constants.cpp
@@ -3,6 +3,8 @@
 namespace Sass {
   namespace Constants {
 
+    extern const unsigned long MaxCallStack = 1024;
+
     // https://github.com/sass/libsass/issues/592
     // https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity
     // https://github.com/sass/sass/issues/1495#issuecomment-61189114
@@ -138,7 +140,7 @@
     extern const char arglist_name[]    = "arglist";
 
     // constants for uri parsing (RFC 3986 Appendix A.)
-    extern const char uri_chars[]  = ":;/?!$%&#@[]{}'\"*+-.,_=";
+    extern const char uri_chars[]  = ":;/?!$%&#@|[]{}'`^\"*+-.,_=~";
 
     // some specific constant character classes
     // they must be static to be useable by lexer
diff --git a/libsass/constants.hpp b/libsass/constants.hpp
--- a/libsass/constants.hpp
+++ b/libsass/constants.hpp
@@ -4,6 +4,9 @@
 namespace Sass {
   namespace Constants {
 
+    // The maximum call stack that can be created
+    extern const unsigned long MaxCallStack;
+
     // https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity
     // The following list of selectors is by increasing specificity:
     extern const unsigned long Specificity_Star;
diff --git a/libsass/context.cpp b/libsass/context.cpp
--- a/libsass/context.cpp
+++ b/libsass/context.cpp
@@ -4,6 +4,13 @@
 #define PATH_SEP ':'
 #endif
 
+#include <string>
+#include <cstdlib>
+#include <cstring>
+#include <iomanip>
+#include <sstream>
+#include <iostream>
+
 #include "ast.hpp"
 #include "util.hpp"
 #include "sass.h"
@@ -29,13 +36,6 @@
 #include "prelexer.hpp"
 #include "emitter.hpp"
 
-#include <string>
-#include <cstdlib>
-#include <cstring>
-#include <iomanip>
-#include <sstream>
-#include <iostream>
-
 namespace Sass {
   using namespace Constants;
   using namespace File;
@@ -512,7 +512,6 @@
     register_function(ctx, index_sig, index, env);
     register_function(ctx, join_sig, join, env);
     register_function(ctx, append_sig, append, env);
-    register_function(ctx, compact_sig, compact, env);
     register_function(ctx, zip_sig, zip, env);
     register_function(ctx, list_separator_sig, list_separator, env);
     // Map Functions
@@ -540,6 +539,8 @@
     // Misc Functions
     register_function(ctx, inspect_sig, inspect, env);
     register_function(ctx, unique_id_sig, unique_id, env);
+    // Selector functions
+    register_function(ctx, is_superselector_sig, is_superselector, env);
   }
 
   void register_c_functions(Context& ctx, Env* env, Sass_Function_List descrs)
diff --git a/libsass/contextualize.cpp b/libsass/contextualize.cpp
--- a/libsass/contextualize.cpp
+++ b/libsass/contextualize.cpp
@@ -32,12 +32,19 @@
     Selector_List* ss = 0;
     if (p) {
       ss = new (ctx.mem) Selector_List(s->pstate(), p->length() * s->length());
+      if (s->length() == 0) {
+          Complex_Selector* comb = static_cast<Complex_Selector*>(parent->perform(this));
+          if (parent->has_line_feed()) comb->has_line_feed(true);
+          if (comb) *ss << comb;
+          else cerr << "Warning: contextualize returned null" << endl;
+      }
       for (size_t i = 0, L = p->length(); i < L; ++i) {
         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;
+          else cerr << "Warning: contextualize returned null" << endl;
         }
       }
     }
diff --git a/libsass/contextualize_eval.cpp b/libsass/contextualize_eval.cpp
--- a/libsass/contextualize_eval.cpp
+++ b/libsass/contextualize_eval.cpp
@@ -64,7 +64,7 @@
     // the value might be interpolated; evaluate it
     String* v = s->value();
     if (v && eval) {
-     Eval* eval_with = eval->with(env, backtrace);
+     Eval* eval_with = eval->with(parent, env, backtrace);
      v = static_cast<String*>(v->perform(eval_with));
     }
     To_String toString;
diff --git a/libsass/cssize.cpp b/libsass/cssize.cpp
--- a/libsass/cssize.cpp
+++ b/libsass/cssize.cpp
@@ -423,8 +423,10 @@
         else
         {
           List* mq = merge_media_queries(static_cast<Media_Block*>(b->node()), static_cast<Media_Block*>(parent));
-          static_cast<Media_Block*>(b->node())->media_queries(mq);
-          ss = b->node();
+          if (mq->length()) {
+            static_cast<Media_Block*>(b->node())->media_queries(mq);
+            ss = b->node();
+          }
         }
 
         if (!ss) continue;
diff --git a/libsass/debugger.hpp b/libsass/debugger.hpp
--- a/libsass/debugger.hpp
+++ b/libsass/debugger.hpp
@@ -32,28 +32,45 @@
   return is.str();
 }
 
+inline string pstate_source_position(AST_Node* node)
+{
+  stringstream str;
+  Position start(node->pstate());
+  Position end(start + node->pstate().offset);
+  str << (start.file == string::npos ? -1 : start.file)
+    << "@[" << start.line << ":" << start.column << "]"
+    << "-[" << end.line << ":" << end.column << "]";
+  return str.str();
+}
+
 inline void debug_ast(AST_Node* node, string ind = "", Env* env = 0)
 {
   if (node == 0) return;
   if (ind == "") cerr << "####################################################################\n";
   if (dynamic_cast<Bubble*>(node)) {
     Bubble* bubble = dynamic_cast<Bubble*>(node);
-    cerr << ind << "Bubble " << bubble << " " << bubble->tabs() << endl;
+    cerr << ind << "Bubble " << bubble;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << " " << bubble->tabs();
+    cerr << 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;
+    cerr << ind << "At_Root_Block " << root_block;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << " " << root_block->tabs();
+    cerr << 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
-      << " [block:" << selector->last_block() << "]"
-      << (selector->last_block() && selector->last_block()->is_root() ? " [root]" : "")
-      << " [@media:" << selector->media_block() << "]"
-      << (selector->is_optional() ? " [is_optional]": " -")
-      << (selector->has_line_break() ? " [line-break]": " -")
-      << (selector->has_line_feed() ? " [line-feed]": " -")
-    << endl;
+    cerr << ind << "Selector_List " << selector;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << " [block:" << selector->last_block() << "]";
+    cerr << (selector->last_block() && selector->last_block()->is_root() ? " [root]" : "");
+    cerr << " [@media:" << selector->media_block() << "]";
+    cerr << (selector->is_optional() ? " [is_optional]": " -");
+    cerr << (selector->has_line_break() ? " [line-break]": " -");
+    cerr << (selector->has_line_feed() ? " [line-feed]": " -");
+    cerr << endl;
 
     for(auto i : selector->elements()) { debug_ast(i, ind + " ", env); }
 
@@ -64,12 +81,14 @@
   } else if (dynamic_cast<Parent_Selector*>(node)) {
     Parent_Selector* selector = dynamic_cast<Parent_Selector*>(node);
     cerr << ind << "Parent_Selector " << selector;
+    cerr << " (" << pstate_source_position(node) << ")";
     cerr << " <" << prettyprint(selector->pstate().token.ws_before()) << ">" << endl;
     debug_ast(selector->selector(), ind + "->", env);
 
   } else if (dynamic_cast<Complex_Selector*>(node)) {
     Complex_Selector* selector = dynamic_cast<Complex_Selector*>(node);
     cerr << ind << "Complex_Selector " << selector
+      << " (" << pstate_source_position(node) << ")"
       << " [block:" << selector->last_block() << "]"
       << " [weight:" << longToHex(selector->specificity()) << "]"
       << (selector->last_block() && selector->last_block()->is_root() ? " [root]" : "")
@@ -89,6 +108,7 @@
   } else if (dynamic_cast<Compound_Selector*>(node)) {
     Compound_Selector* selector = dynamic_cast<Compound_Selector*>(node);
     cerr << ind << "Compound_Selector " << selector;
+    cerr << " (" << pstate_source_position(node) << ")";
     cerr << " [block:" << selector->last_block() << "]";
     cerr << " [weight:" << longToHex(selector->specificity()) << "]";
     // cerr << (selector->last_block() && selector->last_block()->is_root() ? " [root]" : "");
@@ -100,26 +120,38 @@
     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;
+    cerr << ind << "Propset " << selector;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << " " << 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;
+    cerr << ind << "Wrapped_Selector " << selector;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << " <<" << 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;
+    cerr << ind << "Pseudo_Selector " << selector;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << " <<" << 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;
+    cerr << ind << "Attribute_Selector " << selector;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << " <<" << 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;
+    cerr << ind << "Selector_Qualifier " << selector;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << " <<" << 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]": " -") <<
+    cerr << ind << "Type_Selector " << selector;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << " <<" << selector->name() << ">>" << (selector->has_line_break() ? " [line-break]": " -") <<
       " <" << prettyprint(selector->pstate().token.ws_before()) << ">" << endl;
   } else if (dynamic_cast<Selector_Placeholder*>(node)) {
 
@@ -134,15 +166,20 @@
 
   } else if (dynamic_cast<Selector_Reference*>(node)) {
     Selector_Reference* selector = dynamic_cast<Selector_Reference*>(node);
-    cerr << ind << "Selector_Reference " << selector << " @ref " << selector->selector() << endl;
+    cerr << ind << "Selector_Reference " << selector;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << " @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;
+    cerr << ind << "Simple_Selector " << selector;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << (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
-      << " [block:" << selector->last_block() << "]"
+    cerr << ind << "Selector_Schema " << selector;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << " [block:" << selector->last_block() << "]"
       << (selector->last_block() && selector->last_block()->is_root() ? " [root]" : "")
       << " [@media:" << selector->media_block() << "]"
       << (selector->has_line_break() ? " [line-break]": " -")
@@ -154,23 +191,26 @@
 
   } else if (dynamic_cast<Selector*>(node)) {
     Selector* selector = dynamic_cast<Selector*>(node);
-    cerr << ind << "Selector " << selector
-      << (selector->has_line_break() ? " [line-break]": " -")
+    cerr << ind << "Selector " << selector;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << (selector->has_line_break() ? " [line-break]": " -")
       << (selector->has_line_feed() ? " [line-feed]": " -")
     << endl;
 
   } else if (dynamic_cast<Media_Query_Expression*>(node)) {
     Media_Query_Expression* block = dynamic_cast<Media_Query_Expression*>(node);
-    cerr << ind << "Media_Query_Expression " << block
-      << (block->is_interpolated() ? " [is_interpolated]": " -")
+    cerr << ind << "Media_Query_Expression " << block;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << (block->is_interpolated() ? " [is_interpolated]": " -")
     << endl;
-    debug_ast(block->feature(), ind + " f) ");
-    debug_ast(block->value(), ind + " v) ");
+    debug_ast(block->feature(), ind + " feature) ");
+    debug_ast(block->value(), ind + " value) ");
 
   } else if (dynamic_cast<Media_Query*>(node)) {
     Media_Query* block = dynamic_cast<Media_Query*>(node);
-    cerr << ind << "Media_Query " << block
-      << (block->is_negated() ? " [is_negated]": " -")
+    cerr << ind << "Media_Query " << block;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << (block->is_negated() ? " [is_negated]": " -")
       << (block->is_restricted() ? " [is_restricted]": " -")
     << endl;
     debug_ast(block->media_type(), ind + " ");
@@ -178,101 +218,160 @@
 
   } else if (dynamic_cast<Media_Block*>(node)) {
     Media_Block* block = dynamic_cast<Media_Block*>(node);
-    cerr << ind << "Media_Block " << block << " " << block->tabs() << endl;
+    cerr << ind << "Media_Block " << block;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << " " << block->tabs() << endl;
     debug_ast(block->media_queries(), ind + " =@ ");
     debug_ast(block->selector(), ind + " -@ ");
     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;
+    cerr << ind << "Feature_Block " << block;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << " " << 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;
+    cerr << ind << "Block " << root_block;
+    cerr << " (" << pstate_source_position(node) << ")";
+    if (root_block->is_root()) cerr << " [root]";
+    cerr << " " << 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;
+    cerr << ind << "Warning " << block;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << " " << block->tabs() << endl;
   } else if (dynamic_cast<Error*>(node)) {
     Error* block = dynamic_cast<Error*>(node);
-    cerr << ind << "Error " << block << " " << block->tabs() << endl;
+    cerr << ind << "Error " << block;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << " " << block->tabs() << endl;
   } else if (dynamic_cast<Debug*>(node)) {
     Debug* block = dynamic_cast<Debug*>(node);
-    cerr << ind << "Debug " << block << " " << block->tabs() << endl;
+    cerr << ind << "Debug " << block;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << " " << block->tabs() << endl;
   } else if (dynamic_cast<Comment*>(node)) {
     Comment* block = dynamic_cast<Comment*>(node);
-    cerr << ind << "Comment " << block << " " << block->tabs() <<
+    cerr << ind << "Comment " << block;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << " " << block->tabs() <<
       " <" << prettyprint(block->pstate().token.ws_before()) << ">" << 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;
+    cerr << ind << "If " << block;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << " " << block->tabs() << endl;
+    debug_ast(block->predicate(), ind + " = ");
+    debug_ast(block->consequent(), ind + " <>");
+    debug_ast(block->alternative(), ind + " ><");
   } else if (dynamic_cast<Return*>(node)) {
     Return* block = dynamic_cast<Return*>(node);
-    cerr << ind << "Return " << block << " " << block->tabs() << endl;
+    cerr << ind << "Return " << block;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << " " << block->tabs() << endl;
   } else if (dynamic_cast<Extension*>(node)) {
     Extension* block = dynamic_cast<Extension*>(node);
-    cerr << ind << "Extension " << block << " " << block->tabs() << endl;
+    cerr << ind << "Extension " << block;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << " " << 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;
+    cerr << ind << "Content " << block;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << " " << 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;
+    cerr << ind << "Import_Stub " << block;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << " " << block->tabs() << endl;
   } else if (dynamic_cast<Import*>(node)) {
     Import* block = dynamic_cast<Import*>(node);
-    cerr << ind << "Import " << block << " " << block->tabs() << endl;
+    cerr << ind << "Import " << block;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << " " << block->tabs() << endl;
+    // debug_ast(block->media_queries(), ind + " @ ");
     // 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;
+    cerr << ind << "Assignment " << block;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << " <<" << 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;
+    cerr << ind << "Declaration " << block;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << " " << block->tabs() << endl;
     debug_ast(block->property(), ind + " prop: ", env);
     debug_ast(block->value(), ind + " value: ", env);
   } else if (dynamic_cast<Keyframe_Rule*>(node)) {
     Keyframe_Rule* has_block = dynamic_cast<Keyframe_Rule*>(node);
-    cerr << ind << "Keyframe_Rule " << has_block << " " << has_block->tabs() << endl;
+    cerr << ind << "Keyframe_Rule " << has_block;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << " " << has_block->tabs() << endl;
     if (has_block->selector()) debug_ast(has_block->selector(), ind + "@");
     if (has_block->block()) for(auto i : has_block->block()->elements()) { debug_ast(i, ind + " ", env); }
   } else if (dynamic_cast<At_Rule*>(node)) {
     At_Rule* block = dynamic_cast<At_Rule*>(node);
-    cerr << ind << "At_Rule " << block << " [" << block->keyword() << "] " << block->tabs() << endl;
+    cerr << ind << "At_Rule " << block;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << " [" << block->keyword() << "] " << 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;
+    cerr << ind << "Each " << block;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << " " << 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;
+    cerr << ind << "For " << block;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << " " << 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;
+    cerr << ind << "While " << block;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << " " << 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;
+    cerr << ind << "Definition " << block;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << " [name: " << block->name() << "] ";
+    cerr << " [type: " << (block->type() == Sass::Definition::Type::MIXIN ? "Mixin " : "Function ") << "] ";
+    // this seems to lead to segfaults some times?
+    // cerr << " [signature: " << block->signature() << "] ";
+    cerr << " [native: " << block->native_function() << "] ";
+    cerr << " " << block->tabs() << endl;
+    debug_ast(block->parameters(), ind + " params: ", env);
     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;
+    cerr << ind << "Mixin_Call " << block << " " << block->tabs();
+    cerr << " [" <<  block->name() << "]" << endl;
+    debug_ast(block->arguments(), ind + " args: ");
     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;
+    cerr << ind << "Ruleset " << ruleset;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << " " << 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;
+    cerr << ind << "Block " << block;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << " " << 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);
@@ -281,88 +380,152 @@
     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;
+    cerr << expression << " [" << expression->value() << "]";
+    if (expression->is_delayed()) cerr << " [delayed]";
+    cerr << endl;
   } else if (dynamic_cast<Variable*>(node)) {
     Variable* expression = dynamic_cast<Variable*>(node);
-    cerr << ind << "Variable " << expression << " [" << expression->name() << "]" << endl;
+    cerr << ind << "Variable " << expression;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << " [" << 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;
+    cerr << ind << "Function_Call_Schema " << expression;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << "" << 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;
+    cerr << ind << "Function_Call " << expression;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << " [" << 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;
+    cerr << ind << "Arguments " << expression;
+    if (expression->is_delayed()) cerr << " [delayed]";
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << 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;
+    cerr << ind << "Argument " << expression;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << " [" << expression->value() << "]";
+    cerr << " [name: " << expression->name() << "] ";
+    cerr << " [rest: " << expression->is_rest_argument() << "] ";
+    cerr << " [keyword: " << expression->is_keyword_argument() << "] " << endl;
     debug_ast(expression->value(), ind + " value: ", env);
+  } else if (dynamic_cast<Parameters*>(node)) {
+    Parameters* expression = dynamic_cast<Parameters*>(node);
+    cerr << ind << "Parameters " << expression;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << " [has_optional: " << expression->has_optional_parameters() << "] ";
+    cerr << " [has_rest: " << expression->has_rest_parameter() << "] ";
+    cerr << endl;
+    for(auto i : expression->elements()) { debug_ast(i, ind + " ", env); }
+  } else if (dynamic_cast<Parameter*>(node)) {
+    Parameter* expression = dynamic_cast<Parameter*>(node);
+    cerr << ind << "Parameter " << expression;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << " [name: " << expression->name() << "] ";
+    cerr << " [default: " << expression->default_value() << "] ";
+    cerr << " [rest: " << expression->is_rest_parameter() << "] " << endl;
   } else if (dynamic_cast<Unary_Expression*>(node)) {
     Unary_Expression* expression = dynamic_cast<Unary_Expression*>(node);
-    cerr << ind << "Unary_Expression " << expression << " [" << expression->type() << "]" << endl;
+    cerr << ind << "Unary_Expression " << expression;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << " [" << 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;
+    cerr << ind << "Binary_Expression " << expression;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << " [" << expression->type_name() << "]" << 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;
+    cerr << ind << "Map " << expression;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << " [Hashed]" << endl;
+    // for (auto i : expression->elements()) {
+    //   debug_ast(i.first, ind + " key: ");
+    //   debug_ast(i.second, ind + " val: ");
+    // }
   } else if (dynamic_cast<List*>(node)) {
     List* expression = dynamic_cast<List*>(node);
-    cerr << ind << "List " << expression << " (" << expression->length() << ") " <<
+    cerr << ind << "List " << expression;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << " (" << expression->length() << ") " <<
       (expression->separator() == Sass::List::Separator::COMMA ? "Comma " : "Space ") <<
       " [delayed: " << expression->is_delayed() << "] " <<
       " [interpolant: " << expression->is_interpolant() << "] " <<
+      " [arglist: " << expression->is_arglist() << "] " <<
       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;
+    cerr << ind << "Content " << expression;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << " [Statement]" << endl;
   } else if (dynamic_cast<Boolean*>(node)) {
     Boolean* expression = dynamic_cast<Boolean*>(node);
-    cerr << ind << "Boolean " << expression << " [" << expression->value() << "]" << endl;
+    cerr << ind << "Boolean " << expression;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << " [" << 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;
+    cerr << ind << "Color " << expression;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << " [" << 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;
+    cerr << ind << "Number " << expression;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << " [" << 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()) << ">" << endl;
+    cerr << ind << "String_Quoted " << expression;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << " [" << prettyprint(expression->value()) << "]";
+    if (expression->is_delayed()) cerr << " [delayed]";
+    if (expression->sass_fix_1291()) cerr << " [sass_fix_1291]";
+    if (expression->quote_mark()) cerr << " [quote_mark: " << expression->quote_mark() << "]";
+    cerr << " <" << prettyprint(expression->pstate().token.ws_before()) << ">" << 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()) << ">" << endl;
+    cerr << ind << "String_Constant " << expression;
+    if (expression->concrete_type()) {
+      cerr << " " << expression->concrete_type();
+    }
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << " [" << prettyprint(expression->value()) << "]";
+    if (expression->is_delayed()) cerr << " [delayed]";
+    if (expression->sass_fix_1291()) cerr << " [sass_fix_1291]";
+    cerr << " <" << prettyprint(expression->pstate().token.ws_before()) << ">" << 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;
+    cerr << ind << "String_Schema " << expression;
+    cerr << " " << expression->concrete_type();
+    if (expression->is_delayed()) cerr << " [delayed]";
+    if (expression->has_interpolants()) cerr << " [has_interpolants]";
+    cerr << " <" << prettyprint(expression->pstate().token.ws_before()) << ">" << 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;
+    cerr << ind << "String " << expression;
+    cerr << " " << expression->concrete_type();
+    cerr << " (" << pstate_source_position(node) << ")";
+    if (expression->sass_fix_1291()) cerr << " [sass_fix_1291]";
+    cerr << " <" << prettyprint(expression->pstate().token.ws_before()) << ">" << endl;
   } else if (dynamic_cast<Expression*>(node)) {
     Expression* expression = dynamic_cast<Expression*>(node);
     cerr << ind << "Expression " << expression;
+    cerr << " (" << pstate_source_position(node) << ")";
     switch (expression->concrete_type()) {
       case Expression::Concrete_Type::NONE: cerr << " [NONE]"; break;
       case Expression::Concrete_Type::BOOLEAN: cerr << " [BOOLEAN]"; break;
@@ -378,11 +541,15 @@
     cerr << 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;
+    cerr << ind << "Has_Block " << has_block;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << " " << 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;
+    cerr << ind << "Statement " << statement;
+    cerr << " (" << pstate_source_position(node) << ")";
+    cerr << " " << statement->tabs() << endl;
   }
 
   if (ind == "") cerr << "####################################################################\n";
diff --git a/libsass/emitter.cpp b/libsass/emitter.cpp
--- a/libsass/emitter.cpp
+++ b/libsass/emitter.cpp
@@ -18,7 +18,8 @@
     in_wrapped(false),
     in_media_block(false),
     in_declaration(false),
-    in_declaration_list(false)
+    in_space_array(false),
+    in_comma_array(false)
   { }
 
   // return buffer as string
@@ -191,7 +192,9 @@
   {
     if (output_style() != COMPRESSED && buffer().size()) {
       char lst = buffer().at(buffer().length() - 1);
-      if (!isspace(lst)) append_mandatory_space();
+      if (!isspace(lst) || scheduled_delimiter) {
+        append_mandatory_space();
+      }
     }
   }
 
diff --git a/libsass/emitter.hpp b/libsass/emitter.hpp
--- a/libsass/emitter.hpp
+++ b/libsass/emitter.hpp
@@ -37,11 +37,17 @@
       bool scheduled_delimiter;
 
     public:
+      // output strings different in comments
       bool in_comment;
+      // selector list does not get linefeeds
       bool in_wrapped;
+      // lists always get a space after delimiter
       bool in_media_block;
+      // nested list must not have parentheses
       bool in_declaration;
-      bool in_declaration_list;
+      // nested lists need parentheses
+      bool in_space_array;
+      bool in_comma_array;
 
     public:
       // return buffer as string
diff --git a/libsass/environment.hpp b/libsass/environment.hpp
--- a/libsass/environment.hpp
+++ b/libsass/environment.hpp
@@ -104,7 +104,7 @@
     // see if we have a lexical we could update
     // either update already existing lexical value
     // or if flag is set, we create one if no lexical found
-    void set_lexical(const string& key, T val, bool global = false)
+    void set_lexical(const string& key, T val)
     {
       auto cur = this;
       while (cur->is_lexical()) {
@@ -114,11 +114,7 @@
         }
         cur = cur->parent_;
       }
-      if (global) {
-        set_global(key, val);
-      } else {
-        set_local(key, val);
-      }
+      set_local(key, val);
     }
 
     // look on the full stack for key
diff --git a/libsass/error_handling.cpp b/libsass/error_handling.cpp
--- a/libsass/error_handling.cpp
+++ b/libsass/error_handling.cpp
@@ -8,18 +8,28 @@
   : type(type), pstate(pstate), message(message)
   { }
 
-  void error(string msg, ParserState pstate)
+  void warn(string msg, ParserState pstate)
   {
-    throw Sass_Error(Sass_Error::syntax, pstate, msg);
+    cerr << "Warning: " << msg<< endl;
   }
 
-  void error(string msg, ParserState pstate, Backtrace* bt)
+  void warn(string msg, ParserState pstate, Backtrace* bt)
   {
-
     Backtrace top(bt, pstate, "");
     msg += top.to_string();
+    warn(msg, pstate);
+  }
 
+  void error(string msg, ParserState pstate)
+  {
     throw Sass_Error(Sass_Error::syntax, pstate, msg);
+  }
+
+  void error(string msg, ParserState pstate, Backtrace* bt)
+  {
+    Backtrace top(bt, pstate, "");
+    msg += "\n" + top.to_string();
+    error(msg, pstate);
   }
 
 }
diff --git a/libsass/error_handling.hpp b/libsass/error_handling.hpp
--- a/libsass/error_handling.hpp
+++ b/libsass/error_handling.hpp
@@ -21,6 +21,9 @@
 
   };
 
+  void warn(string msg, ParserState pstate);
+  void warn(string msg, ParserState pstate, Backtrace* bt);
+
   void error(string msg, ParserState pstate);
   void error(string msg, ParserState pstate, Backtrace* bt);
 
diff --git a/libsass/eval.cpp b/libsass/eval.cpp
--- a/libsass/eval.cpp
+++ b/libsass/eval.cpp
@@ -1,3 +1,10 @@
+#include <cstdlib>
+#include <cmath>
+#include <iostream>
+#include <sstream>
+#include <iomanip>
+#include <typeinfo>
+
 #include "file.hpp"
 #include "eval.hpp"
 #include "ast.hpp"
@@ -11,12 +18,6 @@
 #include "prelexer.hpp"
 #include "parser.hpp"
 
-#include <cstdlib>
-#include <cmath>
-#include <iostream>
-#include <iomanip>
-#include <typeinfo>
-
 namespace Sass {
   using namespace std;
 
@@ -65,19 +66,56 @@
   {
     string var(a->variable());
     if (a->is_global()) {
-      env->set_global(var, a->value()->perform(this));
-    }
-    else if (a->is_default()) {
-      if (env->has_lexical(var)) return 0;
-      if (env->has_global(var)) {
-        Expression* e = static_cast<Expression*>(env->get_global(var));
-        if (e->concrete_type() == Expression::NULL_VAL) {
+      if (a->is_default()) {
+        if (env->has_global(var)) {
+          Expression* e = dynamic_cast<Expression*>(env->get_global(var));
+          if (!e || e->concrete_type() == Expression::NULL_VAL) {
+            env->set_global(var, a->value()->perform(this));
+          }
+        }
+        else {
           env->set_global(var, a->value()->perform(this));
         }
-      } else {
+      }
+      else {
         env->set_global(var, a->value()->perform(this));
       }
     }
+    else if (a->is_default()) {
+      if (env->has_lexical(var)) {
+        auto cur = env;
+        while (cur && cur->is_lexical()) {
+          if (cur->has_local(var)) {
+            if (AST_Node* node = cur->get_local(var)) {
+              Expression* e = dynamic_cast<Expression*>(node);
+              if (!e || e->concrete_type() == Expression::NULL_VAL) {
+                cur->set_local(var, a->value()->perform(this));
+              }
+            }
+            else {
+              throw runtime_error("Env not in sync");
+            }
+            return 0;
+          }
+          cur = cur->parent();
+        }
+        throw runtime_error("Env not in sync");
+      }
+      else if (env->has_global(var)) {
+        if (AST_Node* node = env->get_global(var)) {
+          Expression* e = dynamic_cast<Expression*>(node);
+          if (!e || e->concrete_type() == Expression::NULL_VAL) {
+            env->set_global(var, a->value()->perform(this));
+          }
+        }
+      }
+      else if (env->is_lexical()) {
+        env->set_local(var, a->value()->perform(this));
+      }
+      else {
+        env->set_local(var, a->value()->perform(this));
+      }
+    }
     else {
       env->set_lexical(var, a->value()->perform(this));
     }
@@ -122,7 +160,7 @@
     double end = sass_end->value();
     // only create iterator once in this environment
     Number* it = new (env->mem) Number(low->pstate(), start, sass_end->unit());
-    AST_Node* old_var = env->get_local(variable);
+    AST_Node* old_var = env->has_local(variable) ? env->get_local(variable) : 0;
     env->set_local(variable, it);
     Block* body = f->block();
     Expression* val = 0;
@@ -174,7 +212,7 @@
     // remember variables and then reset them
     vector<AST_Node*> old_vars(variables.size());
     for (size_t i = 0, L = variables.size(); i < L; ++i) {
-      old_vars[i] = env->get_local(variables[i]);
+      old_vars[i] = env->has_local(variables[i]) ? env->get_local(variables[i]) : 0;
       env->set_local(variables[i], 0);
     }
     Block* body = e->block();
@@ -360,6 +398,13 @@
     for (auto key : m->keys()) {
       *mm << std::make_pair(key->perform(this), m->at(key)->perform(this));
     }
+
+    // check for duplicate keys
+    if (mm->has_duplicate_key()) {
+      To_String to_string(&ctx);
+      error("Duplicate key \"" + mm->get_duplicate_key()->perform(&to_string) + "\" in map " + m->perform(&to_string) + ".", m->pstate());
+    }
+
     mm->is_expanded(true);
     return mm;
   }
@@ -398,8 +443,23 @@
     }
     // not a logical connective, so go ahead and eval the rhs
     Expression* rhs = b->right()->perform(this);
-    rhs->is_delayed(false);
-    while (typeid(*rhs) == typeid(Binary_Expression)) rhs = rhs->perform(this);
+    // maybe fully evaluate structure
+    if (op_type == Binary_Expression::EQ ||
+        op_type == Binary_Expression::NEQ ||
+        op_type == Binary_Expression::GT ||
+        op_type == Binary_Expression::GTE ||
+        op_type == Binary_Expression::LT ||
+        op_type == Binary_Expression::LTE)
+    {
+      rhs->is_expanded(false);
+      rhs->set_delayed(false);
+      rhs = rhs->perform(this);
+    }
+    else
+    {
+      rhs->is_delayed(false);
+      rhs = rhs->perform(this);
+    }
 
     // see if it's a relational expression
     switch(op_type) {
@@ -475,6 +535,11 @@
 
   Expression* Eval::operator()(Function_Call* c)
   {
+    if (backtrace->parent != NULL && backtrace->depth() > Constants::MaxCallStack) {
+        ostringstream stm;
+        stm << "Stack depth exceeded max of " << Constants::MaxCallStack;
+        error(stm.str(), c->pstate(), backtrace);
+    }
     string name(Util::normalize_underscores(c->name()));
     string full_name(name + "[f]");
     Arguments* args = c->arguments();
@@ -663,7 +728,11 @@
       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);
+        if (str->quote_mark()) {
+          value = new (ctx.mem) String_Quoted(str->pstate(), str->perform(&to_string));
+        } else {
+          value = new (ctx.mem) String_Constant(str->pstate(), unquote(str->value()));
+        }
       }
     }
     else if (value->concrete_type() == Expression::LIST) {
@@ -748,6 +817,7 @@
 
   Expression* Eval::operator()(Number* n)
   {
+    n->normalize();
     // behave according to as ruby sass (add leading zero)
     return new (ctx.mem) Number(n->pstate(),
                                 n->value(),
@@ -775,12 +845,18 @@
   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());
+        if (str_quoted->quote_mark() == '*' || str_quoted->is_delayed()) {
+          return interpolation(new (ctx.mem) String_Constant(*str_quoted));
+        } else {
+          return string_escape(quote(str_quoted->value(), str_quoted->quote_mark()));
+        }
       } else {
         return evacuate_escapes(str_quoted->value());
       }
     } else if (String_Constant* str_constant = dynamic_cast<String_Constant*>(s)) {
-      return evacuate_escapes(str_constant->value());
+      string str = str_constant->value();
+      if (!str_constant->quote_mark()) str = unquote(str);
+      return evacuate_escapes(str);
     } else if (String_Schema* str_schema = dynamic_cast<String_Schema*>(s)) {
       string res = "";
       for(auto i : str_schema->elements())
@@ -810,6 +886,7 @@
       Expression* value = static_cast<Expression*>((*env)[name]);
       return evacuate_quotes(interpolation(value));
     } else if (Binary_Expression* var = dynamic_cast<Binary_Expression*>(s)) {
+      var->is_delayed(false);
       Expression* ex = var->perform(this);
       return evacuate_quotes(interpolation(ex));
     } else if (Function_Call* var = dynamic_cast<Function_Call*>(s)) {
@@ -835,6 +912,9 @@
   {
     string acc;
     for (size_t i = 0, L = s->length(); i < L; ++i) {
+      // if (String_Quoted* str_quoted = dynamic_cast<String_Quoted*>((*s)[i])) {
+        // if (!str_quoted->is_delayed()) str_quoted->value(string_eval_escapes(str_quoted->value()));
+      // }
       acc += interpolation((*s)[i]);
     }
     String_Quoted* str = new (ctx.mem) String_Quoted(s->pstate(), acc);
@@ -917,8 +997,16 @@
   {
     Expression* feature = e->feature();
     feature = (feature ? feature->perform(this) : 0);
+    if (feature && dynamic_cast<String_Quoted*>(feature)) {
+      feature = new (ctx.mem) String_Constant(feature->pstate(),
+                                              dynamic_cast<String_Quoted*>(feature)->value());
+    }
     Expression* value = e->value();
     value = (value ? value->perform(this) : 0);
+    if (value && dynamic_cast<String_Quoted*>(value)) {
+      value = new (ctx.mem) String_Constant(value->pstate(),
+                                            dynamic_cast<String_Quoted*>(value)->value());
+    }
     return new (ctx.mem) Media_Query_Expression(e->pstate(),
                                                 feature,
                                                 value,
@@ -945,8 +1033,7 @@
         is_rest_argument = false;
         is_keyword_argument = true;
       }
-      else
-      if(val->concrete_type() != Expression::LIST) {
+      else if(val->concrete_type() != Expression::LIST) {
         List* wrapper = new (ctx.mem) List(val->pstate(),
                                            0,
                                            List::COMMA,
@@ -978,9 +1065,13 @@
 
   Expression* Eval::operator()(Parent_Selector* p)
   {
+    // no idea why both calls are needed
     Selector* s = p->perform(contextualize);
+    if (!s) s = p->selector()->perform(contextualize);
     // access to parent selector may return 0
     Selector_List* l = static_cast<Selector_List*>(s);
+    // some spec tests cause this (might be a valid case!)
+    // if (!s) { cerr << "Parent Selector eval error" << endl; }
     if (!s) { l = new (ctx.mem) Selector_List(p->pstate()); }
     return l->perform(listize);
   }
@@ -1005,13 +1096,8 @@
       } break;
 
       case Expression::NUMBER: {
-        Number* l = static_cast<Number*>(lhs);
-        Number* r = static_cast<Number*>(rhs);
-        Number tmp_r(*r);
-        tmp_r.normalize(l->find_convertible_unit());
-        return l->unit() == tmp_r.unit() && l->value() == tmp_r.value()
-               ? true
-               : false;
+        return *static_cast<Number*>(lhs) ==
+               *static_cast<Number*>(rhs);
       } break;
 
       case Expression::COLOR: {
@@ -1024,8 +1110,10 @@
       } break;
 
       case Expression::STRING: {
-        return unquote(static_cast<String_Constant*>(lhs)->value()) ==
-               unquote(static_cast<String_Constant*>(rhs)->value());
+        string slhs = static_cast<String_Quoted*>(lhs)->value();
+        string srhs = static_cast<String_Quoted*>(rhs)->value();
+        return unquote(slhs) == unquote(srhs) &&
+               (!(is_quoted(slhs) || is_quoted(srhs)) || slhs[0] == srhs[0]);
       } break;
 
       case Expression::LIST: {
@@ -1102,8 +1190,8 @@
       v->denominator_units() = r->denominator_units();
     }
 
-    v->value(ops[op](lv, tmp.value()));
     if (op == Binary_Expression::MUL) {
+      v->value(ops[op](lv, rv));
       for (size_t i = 0, S = r->numerator_units().size(); i < S; ++i) {
         v->numerator_units().push_back(r->numerator_units()[i]);
       }
@@ -1112,12 +1200,15 @@
       }
     }
     else if (op == Binary_Expression::DIV) {
+      v->value(ops[op](lv, rv));
       for (size_t i = 0, S = r->numerator_units().size(); i < S; ++i) {
         v->denominator_units().push_back(r->numerator_units()[i]);
       }
       for (size_t i = 0, S = r->denominator_units().size(); i < S; ++i) {
         v->numerator_units().push_back(r->denominator_units()[i]);
       }
+    } else {
+      v->value(ops[op](lv, tmp.value()));
     }
     v->normalize();
     return v;
diff --git a/libsass/expand.cpp b/libsass/expand.cpp
--- a/libsass/expand.cpp
+++ b/libsass/expand.cpp
@@ -54,8 +54,8 @@
     }
 
     Contextualize_Eval* contextual = contextualize_eval->with(selector_stack.back(), env, backtrace);
-    if (old_in_at_root && !r->selector()->has_reference())
-      contextual = contextualize_eval->with(at_root_selector_stack.back(), env, backtrace);
+    // if (old_in_at_root && !r->selector()->has_reference())
+    //   contextual = contextualize_eval->with(selector_stack.back(), env, backtrace);
 
     Selector* sel_ctx = r->selector()->perform(contextual);
     if (sel_ctx == 0) throw "Cannot expand null selector";
@@ -216,19 +216,56 @@
     string var(a->variable());
     Selector* p = selector_stack.size() <= 1 ? 0 : selector_stack.back();
     if (a->is_global()) {
-      env->set_global(var, a->value()->perform(eval->with(p, env, backtrace)));
-    }
-    else if (a->is_default()) {
-      if (env->has_lexical(var)) return 0;
-      if (env->has_global(var)) {
-        Expression* e = static_cast<Expression*>(env->get_global(var));
-        if (e->concrete_type() == Expression::NULL_VAL) {
+      if (a->is_default()) {
+        if (env->has_global(var)) {
+          Expression* e = dynamic_cast<Expression*>(env->get_global(var));
+          if (!e || e->concrete_type() == Expression::NULL_VAL) {
+            env->set_global(var, a->value()->perform(eval->with(p, env, backtrace)));
+          }
+        }
+        else {
           env->set_global(var, a->value()->perform(eval->with(p, env, backtrace)));
         }
-      } else {
+      }
+      else {
         env->set_global(var, a->value()->perform(eval->with(p, env, backtrace)));
       }
     }
+    else if (a->is_default()) {
+      if (env->has_lexical(var)) {
+        auto cur = env;
+        while (cur && cur->is_lexical()) {
+          if (cur->has_local(var)) {
+            if (AST_Node* node = cur->get_local(var)) {
+              Expression* e = dynamic_cast<Expression*>(node);
+              if (!e || e->concrete_type() == Expression::NULL_VAL) {
+                cur->set_local(var, a->value()->perform(eval->with(p, env, backtrace)));
+              }
+            }
+            else {
+              throw runtime_error("Env not in sync");
+            }
+            return 0;
+          }
+          cur = cur->parent();
+        }
+        throw runtime_error("Env not in sync");
+      }
+      else if (env->has_global(var)) {
+        if (AST_Node* node = env->get_global(var)) {
+          Expression* e = dynamic_cast<Expression*>(node);
+          if (!e || e->concrete_type() == Expression::NULL_VAL) {
+            env->set_global(var, a->value()->perform(eval->with(p, env, backtrace)));
+          }
+        }
+      }
+      else if (env->is_lexical()) {
+        env->set_local(var, a->value()->perform(eval->with(p, env, backtrace)));
+      }
+      else {
+        env->set_local(var, a->value()->perform(eval->with(p, env, backtrace)));
+      }
+    }
     else {
       env->set_lexical(var, a->value()->perform(eval->with(p, env, backtrace)));
     }
@@ -315,7 +352,7 @@
     double end = sass_end->value();
     // only create iterator once in this environment
     Number* it = new (env->mem) Number(low->pstate(), start, sass_end->unit());
-    AST_Node* old_var = env->get_local(variable);
+    AST_Node* old_var = env->has_local(variable) ? env->get_local(variable) : 0;
     env->set_local(variable, it);
     Block* body = f->block();
     if (start < end) {
@@ -364,7 +401,7 @@
     // remember variables and then reset them
     vector<AST_Node*> old_vars(variables.size());
     for (size_t i = 0, L = variables.size(); i < L; ++i) {
-      old_vars[i] = env->get_local(variables[i]);
+      old_vars[i] = env->has_local(variables[i]) ? env->get_local(variables[i]) : 0;
       env->set_local(variables[i], 0);
     }
     Block* body = e->block();
diff --git a/libsass/functions.cpp b/libsass/functions.cpp
--- a/libsass/functions.cpp
+++ b/libsass/functions.cpp
@@ -221,9 +221,9 @@
       double w2 = 1 - w1;
 
       return new (ctx.mem) Color(pstate,
-                                 std::floor(w1*color1->r() + w2*color2->r()),
-                                 std::floor(w1*color1->g() + w2*color2->g()),
-                                 std::floor(w1*color1->b() + w2*color2->b()),
+                                 std::round(w1*color1->r() + w2*color2->r()),
+                                 std::round(w1*color1->g() + w2*color2->g()),
+                                 std::round(w1*color1->b() + w2*color2->b()),
                                  color1->a()*p + color2->a()*(1-p));
     }
 
@@ -249,16 +249,16 @@
         h = s = 0; // achromatic
       }
       else {
-        if (l < 0.5) s = del / (2.0 * l);
-        else         s = del / (2.0 - 2.0 * l);
+        if (l < 0.5) s = del / (max + min);
+        else         s = del / (2.0 - max - min);
 
-        if      (r == max) h = 60 * (g - b) / del;
-        else if (g == max) h = 60 * (b - r) / del + 120;
-        else if (b == max) h = 60 * (r - g) / del + 240;
+        if      (r == max) h = (g - b) / del + (g < b ? 6 : 0);
+        else if (g == max) h = (b - r) / del + 2;
+        else if (b == max) h = (r - g) / del + 4;
       }
 
       HSL hsl_struct;
-      hsl_struct.h = h;
+      hsl_struct.h = h / 6 * 360;
       hsl_struct.s = s * 100;
       hsl_struct.l = l * 100;
 
@@ -281,11 +281,18 @@
       s /= 100.0;
       l /= 100.0;
 
+      if (l < 0) l = 0;
+      if (s < 0) s = 0;
+      if (l > 1) l = 1;
+      if (s > 1) s = 1;
+      while (h < 0) h += 1;
+      while (h > 1) h -= 1;
+
       // Algorithm from the CSS3 spec: http://www.w3.org/TR/css3-color/#hsl-color.
       double m2;
       if (l <= 0.5) m2 = l*(s+1.0);
       else m2 = (l+s)-(l*s);
-      double m1 = (l*2)-m2;
+      double m1 = (l*2.0)-m2;
       // round the results -- consider moving this into the Color constructor
       double r = (h_to_rgb(m1, m2, h+1.0/3.0) * 255.0);
       double g = (h_to_rgb(m1, m2, h) * 255.0);
@@ -760,15 +767,18 @@
     Signature unquote_sig = "unquote($string)";
     BUILT_IN(sass_unquote)
     {
-      To_String to_string(&ctx);
       AST_Node* arg = env["$string"];
-      if (String_Quoted* string_quoted = dynamic_cast<String_Quoted*>(arg)) {
+      if (dynamic_cast<Null*>(arg)) {
+        return new (ctx.mem) Null(pstate);
+      }
+      else 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() != 0);
         return result;
       }
-      return new (ctx.mem) String_Constant(pstate, string(arg->perform(&to_string)));
+      To_String to_string(&ctx);
+      return new (ctx.mem) String_Constant(pstate, unquote(string(arg->perform(&to_string))));
     }
 
     Signature quote_sig = "quote($string)";
@@ -906,28 +916,25 @@
       string newstr;
       try {
         String_Constant* s = ARG("$string", String_Constant);
-        Number* n = ARG("$start-at", Number);
-        Number* m = ARG("$end-at", Number);
+        double start_at = ARG("$start-at", Number)->value();
+        double end_at = ARG("$end-at", Number)->value();
 
         string str = unquote(s->value());
 
-        // normalize into 0-based indices
-        size_t start = UTF_8::offset_at_position(str, UTF_8::normalize_index(static_cast<int>(n->value()), UTF_8::code_point_count(str)));
-        size_t end = UTF_8::offset_at_position(str, UTF_8::normalize_index(static_cast<int>(m->value()), UTF_8::code_point_count(str)));
+        size_t size = utf8::distance(str.begin(), str.end());
+        if (end_at <= size * -1.0) { end_at += size; }
+        if (end_at < 0) { end_at += size + 1; }
+        if (end_at > size) { end_at = size; }
+        if (start_at < 0) { start_at += size + 1; }
+        else if (start_at == 0) { ++ start_at; }
 
-        // `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 (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 (start_at <= end_at)
+        {
+          string::iterator start = str.begin();
+          utf8::advance(start, start_at - 1, str.end());
+          string::iterator end = start;
+          utf8::advance(end, end_at - start_at + 1, str.end());
+          newstr = string(start, end);
         }
         if (String_Quoted* ss = dynamic_cast<String_Quoted*>(s)) {
           if(ss->quote_mark()) newstr = quote(newstr);
@@ -1071,16 +1078,16 @@
     BUILT_IN(random)
     {
       Number* l = dynamic_cast<Number*>(env["$limit"]);
-      if (l && trunc(l->value()) != l->value()) error("argument $limit of `" + string(sig) + "` must be an integer", pstate);
       if (l) {
+        if (trunc(l->value()) != l->value() || l->value() == 0) error("argument $limit of `" + string(sig) + "` must be a positive integer", pstate);
         uniform_real_distribution<> distributor(1, l->value() + 1);
         uint_fast32_t distributed = static_cast<uint_fast32_t>(distributor(rand));
         return new (ctx.mem) Number(pstate, (double)distributed);
       }
       else {
         uniform_real_distribution<> distributor(0, 1);
-        uint_fast32_t distributed = static_cast<uint_fast32_t>(distributor(rand));
-        return new (ctx.mem) Number(pstate, trunc(distributed));
+        double distributed = static_cast<double>(distributor(rand));
+        return new (ctx.mem) Number(pstate, distributed);
      }
     }
 
@@ -1100,7 +1107,7 @@
 
       List* list = dynamic_cast<List*>(env["$list"]);
       return new (ctx.mem) Number(pstate,
-                                  list ? list->length() : 1);
+                                  list ? list->size() : 1);
     }
 
     Signature nth_sig = "nth($list, $n)";
@@ -1210,7 +1217,18 @@
       else if (sep_str == "comma") result->separator(List::COMMA);
       else if (sep_str != "auto") error("argument `$separator` of `" + string(sig) + "` must be `space`, `comma`, or `auto`", pstate);
       *result += l;
-      *result << v;
+      bool is_arglist = l->is_arglist();
+      result->is_arglist(is_arglist);
+      if (is_arglist) {
+        *result << new (ctx.mem) Argument(v->pstate(),
+                                          v,
+                                          "",
+                                          false,
+                                          false);
+
+      } else {
+        *result << v;
+      }
       return result;
     }
 
@@ -1244,13 +1262,6 @@
       return zippers;
     }
 
-    Signature compact_sig = "compact($values...)";
-    BUILT_IN(compact)
-    {
-      error("`compact` has been removed from libsass because it's not part of the Sass spec", pstate);
-      return 0; // suppress warning, error will exit anyway
-    }
-
     Signature list_separator_sig = "list_separator($list)";
     BUILT_IN(list_separator)
     {
@@ -1345,13 +1356,10 @@
     {
       List* arglist = new (ctx.mem) List(*ARG("$args", List));
       Map* result = new (ctx.mem) Map(pstate, 1);
-      // The parser ensures the ordering of arguments so we can assert this
-      // isn't keyword argument list the first argument isn't a keyword argument
-      if (!(arglist->empty() || ((Argument*)(*arglist)[0])->is_keyword_argument())) return result;
-      for (size_t i = 0, L = arglist->length(); i < L; ++i) {
+      for (size_t i = arglist->size(), L = arglist->length(); i < L; ++i) {
         string name = string(((Argument*)(*arglist)[i])->name());
-        string sanitized_name = string(name, 1);
-        *result << make_pair(new (ctx.mem) String_Constant(pstate, sanitized_name),
+        name = name.erase(0, 1); // sanitize name (remove dollar sign)
+        *result << make_pair(new (ctx.mem) String_Constant(pstate, name),
                              ((Argument*)(*arglist)[i])->value());
       }
       return result;
@@ -1471,7 +1479,7 @@
       for (size_t i = 0, L = arglist->length(); i < L; ++i) {
         Expression* expr = arglist->value_at_index(i);
         if (arglist->is_arglist()) {
-           Argument* arg = static_cast<Argument*>(expr);
+          Argument* arg = static_cast<Argument*>((*arglist)[i]);
           *args << new (ctx.mem) Argument(pstate,
                                           expr,
                                           "",
@@ -1540,17 +1548,34 @@
       } else if (v->concrete_type() == Expression::STRING) {
         return v;
       } else {
+        bool parentheses = v->concrete_type() == Expression::MAP ||
+                           v->concrete_type() == Expression::LIST;
         Output_Style old_style;
         old_style = ctx.output_style;
         ctx.output_style = NESTED;
-        To_String to_string(&ctx);
+        To_String to_string(&ctx, false);
         string inspect = v->perform(&to_string);
+        if (inspect.empty() && parentheses) inspect = "()";
         ctx.output_style = old_style;
         return new (ctx.mem) String_Constant(pstate, inspect);
 
 
       }
       // return v;
+    }
+
+    Signature is_superselector_sig = "is-superselector($super, $sub)";
+    BUILT_IN(is_superselector)
+    {
+      To_String to_string(&ctx, false);
+      Expression*  ex_sup = ARG("$super", Expression);
+      Expression*  ex_sub = ARG("$sub", Expression);
+      string sup_src = ex_sup->perform(&to_string) + "{";
+      string sub_src = ex_sub->perform(&to_string) + "{";
+      Selector_List* sel_sup = Parser::parse_selector(sup_src.c_str(), ctx);
+      Selector_List* sel_sub = Parser::parse_selector(sub_src.c_str(), ctx);
+      bool result = sel_sup->is_superselector_of(sel_sub);
+      return new (ctx.mem) Boolean(pstate, result);
     }
 
     Signature unique_id_sig = "unique-id()";
diff --git a/libsass/functions.hpp b/libsass/functions.hpp
--- a/libsass/functions.hpp
+++ b/libsass/functions.hpp
@@ -78,7 +78,6 @@
     extern Signature join_sig;
     extern Signature append_sig;
     extern Signature zip_sig;
-    extern Signature compact_sig;
     extern Signature list_separator_sig;
     extern Signature type_of_sig;
     extern Signature unit_sig;
@@ -102,6 +101,7 @@
     extern Signature keywords_sig;
     extern Signature set_nth_sig;
     extern Signature unique_id_sig;
+    extern Signature is_superselector_sig;
 
     BUILT_IN(rgb);
     BUILT_IN(rgba_4);
@@ -153,7 +153,6 @@
     BUILT_IN(join);
     BUILT_IN(append);
     BUILT_IN(zip);
-    BUILT_IN(compact);
     BUILT_IN(list_separator);
     BUILT_IN(type_of);
     BUILT_IN(unit);
@@ -177,6 +176,7 @@
     BUILT_IN(keywords);
     BUILT_IN(set_nth);
     BUILT_IN(unique_id);
+    BUILT_IN(is_superselector);
 
   }
 }
diff --git a/libsass/inspect.cpp b/libsass/inspect.cpp
--- a/libsass/inspect.cpp
+++ b/libsass/inspect.cpp
@@ -1,7 +1,3 @@
-#include "inspect.hpp"
-#include "ast.hpp"
-#include "context.hpp"
-#include "utf8/checked.h"
 #include <cmath>
 #include <string>
 #include <iostream>
@@ -9,6 +5,11 @@
 #include <stdint.h>
 #include <stdint.h>
 
+#include "ast.hpp"
+#include "inspect.hpp"
+#include "context.hpp"
+#include "utf8/checked.h"
+
 namespace Sass {
   using namespace std;
 
@@ -99,9 +100,10 @@
     append_token(at_rule->keyword(), at_rule);
     if (at_rule->selector()) {
       append_mandatory_space();
+      bool was_wrapped = in_wrapped;
       in_wrapped = true;
       at_rule->selector()->perform(this);
-      in_wrapped = false;
+      in_wrapped = was_wrapped;
     }
     if (at_rule->block()) {
       at_rule->block()->perform(this);
@@ -114,6 +116,7 @@
   void Inspect::operator()(Declaration* dec)
   {
     if (dec->value()->concrete_type() == Expression::NULL_VAL) return;
+    bool was_decl = in_declaration;
     in_declaration = true;
     if (output_style() == NESTED)
       indentation += dec->tabs();
@@ -128,7 +131,7 @@
     append_delimiter();
     if (output_style() == NESTED)
       indentation -= dec->tabs();
-    in_declaration = false;
+    in_declaration = was_decl;
   }
 
   void Inspect::operator()(Assignment* assn)
@@ -346,8 +349,20 @@
     else if (in_media_block && sep != " ") sep += " "; // verified
     if (list->empty()) return;
     bool items_output = false;
-    in_declaration_list = in_declaration;
-    for (size_t i = 0, L = list->length(); i < L; ++i) {
+
+    bool was_space_array = in_space_array;
+    bool was_comma_array = in_comma_array;
+    if (!in_declaration && (
+        (list->separator() == List::SPACE && in_space_array) ||
+        (list->separator() == List::COMMA && in_comma_array)
+    )) {
+      append_string("(");
+    }
+
+    if (list->separator() == List::SPACE) in_space_array = true;
+    else if (list->separator() == List::COMMA) in_comma_array = true;
+
+    for (size_t i = 0, L = list->size(); i < L; ++i) {
       Expression* list_item = (*list)[i];
       if (list_item->is_invisible()) {
         continue;
@@ -360,7 +375,16 @@
       list_item->perform(this);
       items_output = true;
     }
-    in_declaration_list = false;
+
+    in_comma_array = was_comma_array;
+    in_space_array = was_space_array;
+    if (!in_declaration && (
+        (list->separator() == List::SPACE && in_space_array) ||
+        (list->separator() == List::COMMA && in_comma_array)
+    )) {
+      append_string(")");
+    }
+
   }
 
   void Inspect::operator()(Binary_Expression* expr)
@@ -416,36 +440,91 @@
 
   void Inspect::operator()(Number* n)
   {
+
+    string res;
+
+    // init stuff
+    n->normalize();
+    int precision = 5;
+    double value = n->value();
+    // get option from optional context
+    if (ctx) precision = ctx->precision;
+
+    // check if the fractional part of the value equals to zero
+    // neat trick from http://stackoverflow.com/a/1521682/1550314
+    // double int_part; bool is_int = modf(value, &int_part) == 0.0;
+
+    // this all cannot be done with one run only, since fixed
+    // output differs from normal output and regular output
+    // can contain scientific notation which we do not want!
+
+    // first sample
     stringstream ss;
-    ss.precision(ctx ? ctx->precision : 5);
-    ss << fixed << n->value();
-    string d(ss.str());
-    // store if the value did not equal zero
-    // if after applying precsision, the value gets
-    // truncated to zero, sass emits 0.0 instead of 0
-    bool nonzero = n->value() != 0;
-    for (size_t i = d.length()-1; d[i] == '0'; --i) {
-      d.resize(d.length()-1);
+    ss.precision(12);
+    ss << value;
+
+    // check if we got scientific notation in result
+    if (ss.str().find_first_of("e") != string::npos) {
+      ss.clear(); ss.str(string());
+      ss.precision(max(12, precision));
+      ss << fixed << value;
     }
-    if (d[d.length()-1] == '.') d.resize(d.length()-1);
+
+    string tmp = ss.str();
+    size_t pos_point = tmp.find_first_of(".,");
+    size_t pos_fract = tmp.find_last_not_of("0");
+    bool is_int = pos_point == pos_fract ||
+                  pos_point == string::npos;
+
+    // reset stream for another run
+    ss.clear(); ss.str(string());
+
+    // take a shortcut for integers
+    if (is_int)
+    {
+      ss.precision(0);
+      ss << fixed << value;
+      res = string(ss.str());
+    }
+    // process floats
+    else
+    {
+      // do we have have too much precision?
+      if (pos_fract < precision + pos_point)
+      { precision = pos_fract - pos_point; }
+      // round value again
+      ss.precision(precision);
+      ss << fixed << value;
+      res = string(ss.str());
+      // maybe we truncated up to decimal point
+      size_t pos = res.find_last_not_of("0");
+      bool at_dec_point = res[pos] == '.' ||
+                          res[pos] == ',';
+      // don't leave a blank point
+      if (at_dec_point) ++ pos;
+      res.resize (pos + 1);
+    }
+
+    // some final cosmetics
+    if (res == "-0.0") res.erase(0, 1);
+    else if (res == "-0") res.erase(0, 1);
+
+    // add unit now
+    res += n->unit();
+
+    // check for a valid unit here
+    // includes result for reporting
     if (n->numerator_units().size() > 1 ||
         n->denominator_units().size() > 0 ||
         (n->numerator_units().size() && n->numerator_units()[0].find_first_of('/') != string::npos) ||
         (n->numerator_units().size() && n->numerator_units()[0].find_first_of('*') != string::npos)
     ) {
-      error(d + n->unit() + " isn't a valid CSS value.", n->pstate());
-    }
-    if (!n->zero() && !in_declaration_list) {
-      if (d.substr(0, 3) == "-0.") d.erase(1, 1);
-      if (d.substr(0, 2) == "0.") d.erase(0, 1);
+      error(res + " isn't a valid CSS value.", n->pstate());
     }
-    // remove the leading minus
-    if (d == "-0") d.erase(0, 1);
-    // use fractional output if we had
-    // a value before it got truncated
-    if (d == "0" && nonzero) d = "0.0";
-    // append number and unit
-    append_token(d + n->unit(), n);
+
+    // output the final token
+    append_token(res, n);
+
   }
 
   // helper function for serializing colors
@@ -562,7 +641,7 @@
   void Inspect::operator()(String_Quoted* s)
   {
     if (s->quote_mark()) {
-      append_token(quote(s->value(), s->quote_mark()), s);
+      append_token(quote(s->value(), s->quote_mark(), true), s);
     } else {
       append_token(s->value(), s);
     }
diff --git a/libsass/json.cpp b/libsass/json.cpp
--- a/libsass/json.cpp
+++ b/libsass/json.cpp
@@ -102,11 +102,11 @@
 {
   size_t length = sb->cur - sb->start;
   size_t alloc = sb->end - sb->start;
-  
+
   do {
     alloc *= 2;
   } while (alloc < length + need);
-  
+
   sb->start = (char*) realloc(sb->start, alloc + 1);
   if (sb->start == NULL)
     out_of_memory();
@@ -150,13 +150,10 @@
  * These are taken from the ccan/charset module and customized a bit.
  * Putting them here means the compiler can (choose to) inline them,
  * and it keeps ccan/json from having a dependency.
- */
-
-/*
- * Type for Unicode codepoints.
+ *
+ * We use uint32_t Type for Unicode codepoints.
  * We need our own because wchar_t might be 16 bits.
  */
-typedef uint32_t uchar_t;
 
 /*
  * Validate a single UTF-8 character starting at @s.
@@ -181,7 +178,7 @@
 static int utf8_validate_cz(const char *s)
 {
   unsigned char c = *s++;
-  
+
   if (c <= 0x7F) {        /* 00..7F */
     return 1;
   } else if (c <= 0xC1) { /* 80..C1 */
@@ -191,33 +188,33 @@
     /* Make sure subsequent byte is in the range 0x80..0xBF. */
     if (((unsigned char)*s++ & 0xC0) != 0x80)
       return 0;
-    
+
     return 2;
   } else if (c <= 0xEF) { /* E0..EF */
     /* Disallow overlong 3-byte sequence. */
     if (c == 0xE0 && (unsigned char)*s < 0xA0)
       return 0;
-    
+
     /* Disallow U+D800..U+DFFF. */
     if (c == 0xED && (unsigned char)*s > 0x9F)
       return 0;
-    
+
     /* Make sure subsequent bytes are in the range 0x80..0xBF. */
     if (((unsigned char)*s++ & 0xC0) != 0x80)
       return 0;
     if (((unsigned char)*s++ & 0xC0) != 0x80)
       return 0;
-    
+
     return 3;
   } else if (c <= 0xF4) { /* F0..F4 */
     /* Disallow overlong 4-byte sequence. */
     if (c == 0xF0 && (unsigned char)*s < 0x90)
       return 0;
-    
+
     /* Disallow codepoints beyond U+10FFFF. */
     if (c == 0xF4 && (unsigned char)*s > 0x8F)
       return 0;
-    
+
     /* Make sure subsequent bytes are in the range 0x80..0xBF. */
     if (((unsigned char)*s++ & 0xC0) != 0x80)
       return 0;
@@ -225,7 +222,7 @@
       return 0;
     if (((unsigned char)*s++ & 0xC0) != 0x80)
       return 0;
-    
+
     return 4;
   } else {                /* F5..FF */
     return 0;
@@ -236,13 +233,13 @@
 static bool utf8_validate(const char *s)
 {
   int len;
-  
+
   for (; *s != 0; s += len) {
     len = utf8_validate_cz(s);
     if (len == 0)
       return false;
   }
-  
+
   return true;
 }
 
@@ -253,10 +250,10 @@
  * This function assumes input is valid UTF-8,
  * and that there are enough characters in front of @s.
  */
-static int utf8_read_char(const char *s, uchar_t *out)
+static int utf8_read_char(const char *s, uint32_t *out)
 {
   const unsigned char *c = (const unsigned char*) s;
-  
+
   assert(utf8_validate_cz(s));
 
   if (c[0] <= 0x7F) {
@@ -265,21 +262,21 @@
     return 1;
   } else if (c[0] <= 0xDF) {
     /* C2..DF (unless input is invalid) */
-    *out = ((uchar_t)c[0] & 0x1F) << 6 |
-           ((uchar_t)c[1] & 0x3F);
+    *out = ((uint32_t)c[0] & 0x1F) << 6 |
+           ((uint32_t)c[1] & 0x3F);
     return 2;
   } else if (c[0] <= 0xEF) {
     /* E0..EF */
-    *out = ((uchar_t)c[0] &  0xF) << 12 |
-           ((uchar_t)c[1] & 0x3F) << 6  |
-           ((uchar_t)c[2] & 0x3F);
+    *out = ((uint32_t)c[0] &  0xF) << 12 |
+           ((uint32_t)c[1] & 0x3F) << 6  |
+           ((uint32_t)c[2] & 0x3F);
     return 3;
   } else {
     /* F0..F4 (unless input is invalid) */
-    *out = ((uchar_t)c[0] &  0x7) << 18 |
-           ((uchar_t)c[1] & 0x3F) << 12 |
-           ((uchar_t)c[2] & 0x3F) << 6  |
-           ((uchar_t)c[3] & 0x3F);
+    *out = ((uint32_t)c[0] &  0x7) << 18 |
+           ((uint32_t)c[1] & 0x3F) << 12 |
+           ((uint32_t)c[2] & 0x3F) << 6  |
+           ((uint32_t)c[3] & 0x3F);
     return 4;
   }
 }
@@ -292,10 +289,10 @@
  *
  * This function will write up to 4 bytes to @out.
  */
-static int utf8_write_char(uchar_t unicode, char *out)
+static int utf8_write_char(uint32_t unicode, char *out)
 {
   unsigned char *o = (unsigned char*) out;
-  
+
   assert(unicode <= 0x10FFFF && !(unicode >= 0xD800 && unicode <= 0xDFFF));
 
   if (unicode <= 0x7F) {
@@ -329,10 +326,10 @@
  * @uc should be 0xD800..0xDBFF, and @lc should be 0xDC00..0xDFFF.
  * If they aren't, this function returns false.
  */
-static bool from_surrogate_pair(uint16_t uc, uint16_t lc, uchar_t *unicode)
+static bool from_surrogate_pair(uint16_t uc, uint16_t lc, uint32_t *unicode)
 {
   if (uc >= 0xD800 && uc <= 0xDBFF && lc >= 0xDC00 && lc <= 0xDFFF) {
-    *unicode = 0x10000 + ((((uchar_t)uc & 0x3FF) << 10) | (lc & 0x3FF));
+    *unicode = 0x10000 + ((((uint32_t)uc & 0x3FF) << 10) | (lc & 0x3FF));
     return true;
   } else {
     return false;
@@ -344,12 +341,12 @@
  *
  * @unicode must be U+10000..U+10FFFF.
  */
-static void to_surrogate_pair(uchar_t unicode, uint16_t *uc, uint16_t *lc)
+static void to_surrogate_pair(uint32_t unicode, uint16_t *uc, uint16_t *lc)
 {
-  uchar_t n;
-  
+  uint32_t n;
+
   assert(unicode >= 0x10000 && unicode <= 0x10FFFF);
-  
+
   n = unicode - 0x10000;
   *uc = ((n >> 10) & 0x3FF) | 0xD800;
   *lc = (n & 0x3FF) | 0xDC00;
@@ -392,17 +389,17 @@
 {
   const char *s = json;
   JsonNode *ret;
-  
+
   skip_space(&s);
   if (!parse_value(&s, &ret))
     return NULL;
-  
+
   skip_space(&s);
   if (*s != 0) {
     json_delete(ret);
     return NULL;
   }
-  
+
   return ret;
 }
 
@@ -415,9 +412,9 @@
 {
   SB sb;
   sb_init(&sb);
-  
+
   emit_string(&sb, str);
-  
+
   return sb_finish(&sb);
 }
 
@@ -425,12 +422,12 @@
 {
   SB sb;
   sb_init(&sb);
-  
+
   if (space != NULL)
     emit_value_indented(&sb, node, space, 0);
   else
     emit_value(&sb, node);
-  
+
   return sb_finish(&sb);
 }
 
@@ -438,7 +435,7 @@
 {
   if (node != NULL) {
     json_remove_from_parent(node);
-    
+
     switch (node->tag) {
       case JSON_STRING:
         free(node->string_);
@@ -455,7 +452,7 @@
       }
       default:;
     }
-    
+
     free(node);
   }
 }
@@ -463,15 +460,15 @@
 bool json_validate(const char *json)
 {
   const char *s = json;
-  
+
   skip_space(&s);
   if (!parse_value(&s, NULL))
     return false;
-  
+
   skip_space(&s);
   if (*s != 0)
     return false;
-  
+
   return true;
 }
 
@@ -479,30 +476,30 @@
 {
   JsonNode *element;
   int i = 0;
-  
+
   if (array == NULL || array->tag != JSON_ARRAY)
     return NULL;
-  
+
   json_foreach(element, array) {
     if (i == index)
       return element;
     i++;
   }
-  
+
   return NULL;
 }
 
 JsonNode *json_find_member(JsonNode *object, const char *name)
 {
   JsonNode *member;
-  
+
   if (object == NULL || object->tag != JSON_OBJECT)
     return NULL;
-  
+
   json_foreach(member, object)
     if (strcmp(member->key, name) == 0)
       return member;
-  
+
   return NULL;
 }
 
@@ -568,7 +565,7 @@
   child->parent = parent;
   child->prev = parent->children.tail;
   child->next = NULL;
-  
+
   if (parent->children.tail != NULL)
     parent->children.tail->next = child;
   else
@@ -581,7 +578,7 @@
   child->parent = parent;
   child->prev = NULL;
   child->next = parent->children.head;
-  
+
   if (parent->children.head != NULL)
     parent->children.head->prev = child;
   else
@@ -599,7 +596,7 @@
 {
   assert(array->tag == JSON_ARRAY);
   assert(element->parent == NULL);
-  
+
   append_node(array, element);
 }
 
@@ -607,7 +604,7 @@
 {
   assert(array->tag == JSON_ARRAY);
   assert(element->parent == NULL);
-  
+
   prepend_node(array, element);
 }
 
@@ -615,7 +612,7 @@
 {
   assert(object->tag == JSON_OBJECT);
   assert(value->parent == NULL);
-  
+
   append_member(object, json_strdup(key), value);
 }
 
@@ -623,7 +620,7 @@
 {
   assert(object->tag == JSON_OBJECT);
   assert(value->parent == NULL);
-  
+
   value->key = json_strdup(key);
   prepend_node(object, value);
 }
@@ -631,7 +628,7 @@
 void json_remove_from_parent(JsonNode *node)
 {
   JsonNode *parent = node->parent;
-  
+
   if (parent != NULL) {
     if (node->prev != NULL)
       node->prev->next = node->next;
@@ -641,9 +638,9 @@
       node->next->prev = node->prev;
     else
       parent->children.tail = node->prev;
-    
+
     free(node->key);
-    
+
     node->parent = NULL;
     node->prev = node->next = NULL;
     node->key = NULL;
@@ -653,7 +650,7 @@
 static bool parse_value(const char **sp, JsonNode **out)
 {
   const char *s = *sp;
-  
+
   switch (*s) {
     case 'n':
       if (expect_literal(&s, "null")) {
@@ -663,7 +660,7 @@
         return true;
       }
       return false;
-    
+
     case 'f':
       if (expect_literal(&s, "false")) {
         if (out)
@@ -672,7 +669,7 @@
         return true;
       }
       return false;
-    
+
     case 't':
       if (expect_literal(&s, "true")) {
         if (out)
@@ -681,7 +678,7 @@
         return true;
       }
       return false;
-    
+
     case '"': {
       char *str;
       if (parse_string(&s, out ? &str : NULL)) {
@@ -692,21 +689,21 @@
       }
       return false;
     }
-    
+
     case '[':
       if (parse_array(&s, out)) {
         *sp = s;
         return true;
       }
       return false;
-    
+
     case '{':
       if (parse_object(&s, out)) {
         *sp = s;
         return true;
       }
       return false;
-    
+
     default: {
       double num;
       if (parse_number(&s, out ? &num : NULL)) {
@@ -725,34 +722,34 @@
   const char *s = *sp;
   JsonNode *ret = out ? json_mkarray() : NULL;
   JsonNode *element;
-  
+
   if (*s++ != '[')
     goto failure;
   skip_space(&s);
-  
+
   if (*s == ']') {
     s++;
     goto success;
   }
-  
+
   for (;;) {
     if (!parse_value(&s, out ? &element : NULL))
       goto failure;
     skip_space(&s);
-    
+
     if (out)
       json_append_element(ret, element);
-    
+
     if (*s == ']') {
       s++;
       goto success;
     }
-    
+
     if (*s++ != ',')
       goto failure;
     skip_space(&s);
   }
-  
+
 success:
   *sp = s;
   if (out)
@@ -770,42 +767,42 @@
   JsonNode *ret = out ? json_mkobject() : NULL;
   char *key;
   JsonNode *value;
-  
+
   if (*s++ != '{')
     goto failure;
   skip_space(&s);
-  
+
   if (*s == '}') {
     s++;
     goto success;
   }
-  
+
   for (;;) {
     if (!parse_string(&s, out ? &key : NULL))
       goto failure;
     skip_space(&s);
-    
+
     if (*s++ != ':')
       goto failure_free_key;
     skip_space(&s);
-    
+
     if (!parse_value(&s, out ? &value : NULL))
       goto failure_free_key;
     skip_space(&s);
-    
+
     if (out)
       append_member(ret, key, value);
-    
+
     if (*s == '}') {
       s++;
       goto success;
     }
-    
+
     if (*s++ != ',')
       goto failure;
     skip_space(&s);
   }
-  
+
 success:
   *sp = s;
   if (out)
@@ -827,10 +824,10 @@
   char throwaway_buffer[4];
     /* enough space for a UTF-8 character */
   char *b;
-  
+
   if (*s++ != '"')
     return false;
-  
+
   if (out) {
     sb_init(&sb);
     sb_need(&sb, 4);
@@ -838,10 +835,10 @@
   } else {
     b = throwaway_buffer;
   }
-  
+
   while (*s != '"') {
     unsigned char c = *s++;
-    
+
     /* Parse next character, and write it to b. */
     if (c == '\\') {
       c = *s++;
@@ -869,11 +866,11 @@
         case 'u':
         {
           uint16_t uc, lc;
-          uchar_t unicode;
-          
+          uint32_t unicode;
+
           if (!parse_hex16(&s, &uc))
             goto failed;
-          
+
           if (uc >= 0xD800 && uc <= 0xDFFF) {
             /* Handle UTF-16 surrogate pair. */
             if (*s++ != '\\' || *s++ != 'u' || !parse_hex16(&s, &lc))
@@ -886,7 +883,7 @@
           } else {
             unicode = uc;
           }
-          
+
           b += utf8_write_char(unicode, b);
           break;
         }
@@ -900,16 +897,16 @@
     } else {
       /* Validate and echo a UTF-8 character. */
       int len;
-      
+
       s--;
       len = utf8_validate_cz(s);
       if (len == 0)
         goto failed; /* Invalid UTF-8 character. */
-      
+
       while (len--)
         *b++ = *s++;
     }
-    
+
     /*
      * Update sb to know about the new bytes,
      * and set up b to write another character.
@@ -923,7 +920,7 @@
     }
   }
   s++;
-  
+
   if (out)
     *out = sb_finish(&sb);
   *sp = s;
@@ -1058,7 +1055,7 @@
 static void emit_array(SB *out, const JsonNode *array)
 {
   const JsonNode *element;
-  
+
   sb_putc(out, '[');
   json_foreach(element, array) {
     emit_value(out, element);
@@ -1072,18 +1069,18 @@
 {
   const JsonNode *element = array->children.head;
   int i;
-  
+
   if (element == NULL) {
     sb_puts(out, "[]");
     return;
   }
-  
+
   sb_puts(out, "[\n");
   while (element != NULL) {
     for (i = 0; i < indent_level + 1; i++)
       sb_puts(out, space);
     emit_value_indented(out, element, space, indent_level + 1);
-    
+
     element = element->next;
     sb_puts(out, element != NULL ? ",\n" : "\n");
   }
@@ -1095,7 +1092,7 @@
 static void emit_object(SB *out, const JsonNode *object)
 {
   const JsonNode *member;
-  
+
   sb_putc(out, '{');
   json_foreach(member, object) {
     emit_string(out, member->key);
@@ -1111,12 +1108,12 @@
 {
   const JsonNode *member = object->children.head;
   int i;
-  
+
   if (member == NULL) {
     sb_puts(out, "{}");
     return;
   }
-  
+
   sb_puts(out, "{\n");
   while (member != NULL) {
     for (i = 0; i < indent_level + 1; i++)
@@ -1124,7 +1121,7 @@
     emit_string(out, member->key);
     sb_puts(out, ": ");
     emit_value_indented(out, member, space, indent_level + 1);
-    
+
     member = member->next;
     sb_puts(out, member != NULL ? ",\n" : "\n");
   }
@@ -1138,20 +1135,20 @@
   bool escape_unicode = false;
   const char *s = str;
   char *b;
-  
+
   assert(utf8_validate(str));
-  
+
   /*
    * 14 bytes is enough space to write up to two
    * \uXXXX escapes and two quotation marks.
    */
   sb_need(out, 14);
   b = out->cur;
-  
+
   *b++ = '"';
   while (*s != 0) {
     unsigned char c = *s++;
-    
+
     /* Encode the next character, and write it to b. */
     switch (c) {
       case '"':
@@ -1184,10 +1181,10 @@
         break;
       default: {
         int len;
-        
+
         s--;
         len = utf8_validate_cz(s);
-        
+
         if (len == 0) {
           /*
            * Handle invalid UTF-8 character gracefully in production
@@ -1210,9 +1207,9 @@
         } else if (c < 0x1F || (c >= 0x80 && escape_unicode)) {
           /* Encode using \u.... */
           uint32_t unicode;
-          
+
           s += utf8_read_char(s, &unicode);
-          
+
           if (unicode <= 0xFFFF) {
             *b++ = '\\';
             *b++ = 'u';
@@ -1234,11 +1231,11 @@
           while (len--)
             *b++ = *s++;
         }
-        
+
         break;
       }
     }
-  
+
     /*
      * Update *out to know about the new bytes,
      * and set up b to write another encoded character.
@@ -1248,7 +1245,7 @@
     b = out->cur;
   }
   *b++ = '"';
-  
+
   out->cur = b;
 }
 
@@ -1262,7 +1259,7 @@
    */
   char buf[64];
   sprintf(buf, "%.16g", num);
-  
+
   if (number_is_valid(buf))
     sb_puts(out, buf);
   else
@@ -1282,11 +1279,11 @@
 static bool expect_literal(const char **sp, const char *str)
 {
   const char *s = *sp;
-  
+
   while (*str != '\0')
     if (*s++ != *str++)
       return false;
-  
+
   *sp = s;
   return true;
 }
@@ -1317,7 +1314,7 @@
     ret <<= 4;
     ret += tmp;
   }
-  
+
   if (out)
     *out = ret;
   *sp = s;
@@ -1331,12 +1328,12 @@
 static int write_hex16(char *out, uint16_t val)
 {
   const char *hex = "0123456789ABCDEF";
-  
+
   *out++ = hex[(val >> 12) & 0xF];
   *out++ = hex[(val >> 8)  & 0xF];
   *out++ = hex[(val >> 4)  & 0xF];
   *out++ = hex[ val        & 0xF];
-  
+
   return 4;
 }
 
@@ -1347,13 +1344,13 @@
         snprintf(errmsg, 256, __VA_ARGS__); \
       return false; \
     } while (0)
-  
+
   if (node->key != NULL && !utf8_validate(node->key))
     problem("key contains invalid UTF-8");
-  
+
   if (!tag_is_valid(node->tag))
     problem("tag is invalid (%u)", node->tag);
-  
+
   if (node->tag == JSON_BOOL) {
     if (node->bool_ != false && node->bool_ != true)
       problem("bool_ is neither false (%d) nor true (%d)", (int)false, (int)true);
@@ -1365,7 +1362,7 @@
   } else if (node->tag == JSON_ARRAY || node->tag == JSON_OBJECT) {
     JsonNode *head = node->children.head;
     JsonNode *tail = node->children.tail;
-    
+
     if (head == NULL || tail == NULL) {
       if (head != NULL)
         problem("tail is NULL, but head is not");
@@ -1374,10 +1371,10 @@
     } else {
       JsonNode *child;
       JsonNode *last = NULL;
-      
+
       if (head->prev != NULL)
         problem("First child's prev pointer is not NULL");
-      
+
       for (child = head; child != NULL; last = child, child = child->next) {
         if (child == node)
           problem("node is its own child");
@@ -1385,27 +1382,27 @@
           problem("child->next == child (cycle)");
         if (child->next == head)
           problem("child->next == head (cycle)");
-        
+
         if (child->parent != node)
           problem("child does not point back to parent");
         if (child->next != NULL && child->next->prev != child)
           problem("child->next does not point back to child");
-        
+
         if (node->tag == JSON_ARRAY && child->key != NULL)
           problem("Array element's key is not NULL");
         if (node->tag == JSON_OBJECT && child->key == NULL)
           problem("Object member's key is NULL");
-        
+
         if (!json_check(child, errmsg))
           return false;
       }
-      
+
       if (last != tail)
         problem("tail does not match pointer found by starting at head and following next links");
     }
   }
-  
+
   return true;
-  
+
   #undef problem
 }
diff --git a/libsass/lexer.cpp b/libsass/lexer.cpp
--- a/libsass/lexer.cpp
+++ b/libsass/lexer.cpp
@@ -31,25 +31,25 @@
     // this even seems to improve performance by quite a bit
     //####################################
 
-    const bool is_alpha(const char& chr)
+    bool is_alpha(const char& chr)
     {
       return unsigned(chr - 'A') <= 'Z' - 'A' ||
              unsigned(chr - 'a') <= 'z' - 'a';
     }
 
-    const bool is_space(const char& chr)
+    bool is_space(const char& chr)
     {
       // adapted the technique from is_alpha
       return chr == ' ' || unsigned(chr - '\t') <= '\r' - '\t';
     }
 
-    const bool is_digit(const char& chr)
+    bool is_digit(const char& chr)
     {
       // adapted the technique from is_alpha
       return unsigned(chr - '0') <= '9' - '0';
     }
 
-    const bool is_xdigit(const char& chr)
+    bool is_xdigit(const char& chr)
     {
       // adapted the technique from is_alpha
       return unsigned(chr - '0') <= '9' - '0' ||
@@ -57,26 +57,26 @@
              unsigned(chr - 'A') <= 'F' - 'A';
     }
 
-    const bool is_punct(const char& chr)
+    bool is_punct(const char& chr)
     {
       // locale independent
       return chr == '.';
     }
 
-    const bool is_alnum(const char& chr)
+    bool is_alnum(const char& chr)
     {
       return is_alpha(chr) || is_digit(chr);
     }
 
     // check if char is outside ascii range
-    const bool is_unicode(const char& chr)
+    bool is_unicode(const char& chr)
     {
       // check for unicode range
       return unsigned(chr) > 127;
     }
 
     // Match word character (look ahead)
-    const bool is_character(const char& chr)
+    bool is_character(const char& chr)
     {
       // valid alpha, numeric or unicode char (plus hyphen)
       return is_alnum(chr) || is_unicode(chr) || chr == '-';
diff --git a/libsass/lexer.hpp b/libsass/lexer.hpp
--- a/libsass/lexer.hpp
+++ b/libsass/lexer.hpp
@@ -25,14 +25,14 @@
     //####################################
 
     // These are locale independant
-    const bool is_space(const char& src);
-    const bool is_alpha(const char& src);
-    const bool is_punct(const char& src);
-    const bool is_digit(const char& src);
-    const bool is_alnum(const char& src);
-    const bool is_xdigit(const char& src);
-    const bool is_unicode(const char& src);
-    const bool is_character(const char& src);
+    bool is_space(const char& src);
+    bool is_alpha(const char& src);
+    bool is_punct(const char& src);
+    bool is_digit(const char& src);
+    bool is_alnum(const char& src);
+    bool is_xdigit(const char& src);
+    bool is_unicode(const char& src);
+    bool is_character(const char& src);
 
     // Match a single ctype predicate.
     const char* space(const char* src);
diff --git a/libsass/output.cpp b/libsass/output.cpp
--- a/libsass/output.cpp
+++ b/libsass/output.cpp
@@ -8,8 +8,7 @@
   Output::Output(Context* ctx)
   : Inspect(Emitter(ctx)),
     charset(""),
-    top_imports(0),
-    top_comments(0)
+    top_nodes(0)
   {}
 
   Output::~Output() { }
@@ -21,7 +20,7 @@
 
   void Output::operator()(Import* imp)
   {
-    top_imports.push_back(imp);
+    top_nodes.push_back(imp);
   }
 
   OutputBuffer Output::get_buffer(void)
@@ -30,15 +29,9 @@
     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);
+    size_t size_nodes = top_nodes.size();
+    for (size_t i = 0; i < size_nodes; i++) {
+      top_nodes[i]->perform(&inspect);
       inspect.append_mandatory_linefeed();
     }
 
@@ -79,8 +72,8 @@
     // 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);
+      if (buffer().size() == 0) {
+        top_nodes.push_back(c);
       } else {
         in_comment = true;
         append_indentation();
@@ -356,11 +349,13 @@
 
     append_scope_opener();
 
+    bool format = kwd != "@font-face";;
+
     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();
+        if (i < L - 1 && format) append_special_linefeed();
       }
     }
 
@@ -368,7 +363,7 @@
       Statement* stm = (*b)[i];
       if (stm->is_hoistable()) {
         stm->perform(this);
-        if (i < L - 1) append_special_linefeed();
+        if (i < L - 1 && format) append_special_linefeed();
       }
     }
 
@@ -390,10 +385,16 @@
   {
     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);
+      string value(s->value());
+      if (s->can_compress_whitespace() && output_style() == COMPRESSED) {
+        value.erase(std::remove_if(value.begin(), value.end(), ::isspace), value.end());
+      }
+      if (!in_comment) {
+        append_token(string_to_output(value), s);
+      } else {
+        append_token(value, s);
+      }
     }
   }
 
diff --git a/libsass/output.hpp b/libsass/output.hpp
--- a/libsass/output.hpp
+++ b/libsass/output.hpp
@@ -30,8 +30,7 @@
 
   protected:
     string charset;
-    vector<Import*> top_imports;
-    vector<Comment*> top_comments;
+    vector<AST_Node*> top_nodes;
 
   public:
     OutputBuffer get_buffer(void);
diff --git a/libsass/parser.cpp b/libsass/parser.cpp
--- a/libsass/parser.cpp
+++ b/libsass/parser.cpp
@@ -40,6 +40,14 @@
     return p;
   }
 
+  Selector_List* Parser::parse_selector(const char* src, Context& ctx, ParserState pstate)
+  {
+    Parser p = Parser::from_c_str(src, ctx, pstate);
+    // ToDo: ruby sass errors on parent references
+    // ToDo: remap the source-map entries somehow
+    return p.parse_selector_group();
+  }
+
   bool Parser::peek_newline(const char* start)
   {
     return peek_linefeed(start ? start : position);
@@ -77,6 +85,8 @@
       }
     }
 
+    bool semicolon = false;
+    string(error_message);
     lex< optional_spaces >();
     Selector_Lookahead lookahead_result;
     while (position < end) {
@@ -89,14 +99,16 @@
             (*root) << new (ctx.mem) Import_Stub(pstate, imp->files()[i]);
           }
         }
-        if (!lex< one_plus< exactly<';'> > >()) error("top-level @import directive must be terminated by ';'", pstate);
+        semicolon = true;
+        error_message = "top-level @import directive must be terminated by ';'";
       }
       else if (peek< kwd_mixin >() || peek< kwd_function >()) {
         (*root) << parse_definition();
       }
       else if (peek< variable >()) {
         (*root) << parse_assignment();
-        if (!lex< one_plus< exactly<';'> > >()) error("top-level variable binding must be terminated by ';'", pstate);
+        semicolon = true;
+        error_message = "top-level variable binding must be terminated by ';'";
       }
       /*else if (peek< sequence< optional< exactly<'*'> >, alternatives< identifier_schema, identifier >, optional_spaces, exactly<':'>, optional_spaces, exactly<'{'> > >(position)) {
         (*root) << parse_propset();
@@ -104,7 +116,10 @@
       else if (peek< kwd_include >() /* || peek< exactly<'+'> >() */) {
         Mixin_Call* mixin_call = parse_mixin_call();
         (*root) << mixin_call;
-        if (!mixin_call->block() && !lex< one_plus< exactly<';'> > >()) error("top-level @include directive must be terminated by ';'", pstate);
+        if (!mixin_call->block()) {
+          semicolon = true;
+          error_message = "top-level @include directive must be terminated by ';'";
+        }
       }
       else if (peek< kwd_if_directive >()) {
         (*root) << parse_if_directive();
@@ -129,15 +144,18 @@
       }
       else if (peek< kwd_warn >()) {
         (*root) << parse_warning();
-        if (!lex< one_plus< exactly<';'> > >()) error("top-level @warn directive must be terminated by ';'", pstate);
+        semicolon = true;
+        error_message = "top-level @warn directive must be terminated by ';'";
       }
       else if (peek< kwd_err >()) {
         (*root) << parse_error();
-        if (!lex< one_plus< exactly<';'> > >()) error("top-level @error directive must be terminated by ';'", pstate);
+        semicolon = true;
+        error_message = "top-level @error directive must be terminated by ';'";
       }
       else if (peek< kwd_dbg >()) {
         (*root) << parse_debug();
-        if (!lex< one_plus< exactly<';'> > >()) error("top-level @debug directive must be terminated by ';'", pstate);
+        semicolon = true;
+        error_message = "top-level @debug directive must be terminated by ';'";
       }
       // ignore the @charset directive for now
       else if (lex< exactly< charset_kwd > >()) {
@@ -147,7 +165,10 @@
       else if (peek< at_keyword >()) {
         At_Rule* at_rule = parse_at_rule();
         (*root) << at_rule;
-        if (!at_rule->block() && !lex< one_plus< exactly<';'> > >()) error("top-level directive must be terminated by ';'", pstate);
+        if (!at_rule->block()){
+          semicolon = true;
+          error_message = "top-level directive must be terminated by ';'";
+        }
       }
       else if ((lookahead_result = lookahead_for_selector(position)).found) {
         (*root) << parse_ruleset(lookahead_result);
@@ -160,6 +181,11 @@
         if (position >= end) break;
         error("invalid top-level expression", after_token);
       }
+      if (semicolon) {
+        if (!lex< one_plus< exactly<';'> > >() && peek_css< optional_css_whitespace >() != end)
+        { error(error_message, pstate); }
+        semicolon = false;
+      }
       lex< optional_spaces >();
     }
     block_stack.pop_back();
@@ -269,10 +295,18 @@
       else if (lex< uri_prefix >()) {
         Arguments* args = new (ctx.mem) Arguments(pstate);
         Function_Call* result = new (ctx.mem) Function_Call(pstate, "url", args);
-        if (lex < uri_value >()) { // chunk seems to work too!
+        if (lex< quoted_string >()) {
+          Expression* the_url = parse_string();
+          *args << new (ctx.mem) Argument(the_url->pstate(), the_url);
+        }
+        else if (lex < uri_value >(position)) { // chunk seems to work too!
           String* the_url = parse_interpolated_chunk(lexed);
           *args << new (ctx.mem) Argument(the_url->pstate(), the_url);
         }
+        else if (peek < skip_over_scopes < exactly < '(' >, exactly < ')' > > >(position)) {
+          Expression* the_url = parse_list(); // parse_interpolated_chunk(lexed);
+          *args << new (ctx.mem) Argument(the_url->pstate(), the_url);
+        }
         else {
           error("malformed URL", pstate);
         }
@@ -415,7 +449,13 @@
     string name(Util::normalize_underscores(lexed));
     ParserState var_source_position = pstate;
     if (!lex< exactly<':'> >()) error("expected ':' after " + name + " in assignment statement", pstate);
-    Expression* val = parse_list();
+    Expression* val;
+    Selector_Lookahead lookahead = lookahead_for_value(position);
+    if (lookahead.has_interpolants && lookahead.found) {
+      val = parse_value_schema(lookahead.found);
+    } else {
+      val = parse_list();
+    }
     val->is_delayed(false);
     bool is_default = false;
     bool is_global = false;
@@ -460,9 +500,9 @@
       sel = parse_selector_group();
     }
     bool old_in_at_root = in_at_root;
+    ParserState r_source_position = pstate;
     lex < css_comments >();
     in_at_root = false;
-    ParserState r_source_position = pstate;
     if (!peek< exactly<'{'> >()) error("expected a '{' after the selector", pstate);
     Block* block = parse_block();
     in_at_root = old_in_at_root;
@@ -482,6 +522,9 @@
         // 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
+        if (peek < sequence < optional_spaces, exactly<rbrace> > >(p+2)) { position = p+2;
+          css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
+        }
         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);
@@ -611,7 +654,7 @@
     seq->media_block(last_media_block);
     seq->last_block(block_stack.back());
     bool sawsomething = false;
-    if (lex< exactly<'&'> >()) {
+    if (lex_css< exactly<'&'> >()) {
       // check if we have a parent selector on the root level block
       if (block_stack.back() && block_stack.back()->is_root()) {
         //error("Base-level rules cannot contain the parent-selector-referencing character '&'.", pstate);
@@ -707,18 +750,9 @@
       if (lex< alternatives< even, odd > >()) {
         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_Quoted(p, lexed);
-        lex< sign >();
-        String_Constant* op = new (ctx.mem) String_Quoted(p, lexed);
-        // Binary_Expression::Type op = (lexed == "+" ? Binary_Expression::ADD : Binary_Expression::SUB);
-        lex< one_plus < digit > >();
-        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;
-        expr = schema;
+      else if (lex< binomial >(position)) {
+        expr = new (ctx.mem) String_Constant(p, lexed);
+        ((String_Constant*)expr)->can_compress_whitespace(true);
       }
       else if (peek< sequence< optional<sign>,
                                zero_plus<digit>,
@@ -980,13 +1014,25 @@
       return new (ctx.mem) Declaration(prop->pstate(), prop, parse_static_value()/*, lex<important>()*/);
     }
     else {
-      Expression* list_ex = parse_list();
-      if (List* list = dynamic_cast<List*>(list_ex)) {
-        if (list->length() == 0 && !peek< exactly <'{'> >()) {
-          css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
+      Expression* value;
+      Selector_Lookahead lookahead = lookahead_for_value(position);
+      if (lookahead.found) {
+        if (lookahead.has_interpolants) {
+          value = parse_value_schema(lookahead.found);
+        } else {
+          value = parse_list();
         }
       }
-      return new (ctx.mem) Declaration(prop->pstate(), prop, list_ex/*, lex<important>()*/);
+      else {
+        value = parse_list();
+        if (List* list = dynamic_cast<List*>(value)) {
+          if (list->length() == 0 && !peek< exactly <'{'> >()) {
+            css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
+          }
+        }
+      }
+
+      return new (ctx.mem) Declaration(prop->pstate(), prop, value/*, lex<important>()*/);
     }
   }
 
@@ -1008,8 +1054,18 @@
 
   Expression* Parser::parse_map()
   {
-    To_String to_string(&ctx);
+    ParserState opstate = pstate;
     Expression* key = parse_list();
+    if (String_Quoted* str = dynamic_cast<String_Quoted*>(key)) {
+      if (!str->quote_mark() && !str->is_delayed()) {
+        if (ctx.names_to_colors.count(str->value())) {
+          Color* c = new (ctx.mem) Color(*ctx.names_to_colors[str->value()]);
+          c->pstate(str->pstate());
+          c->disp(str->value());
+          key = c;
+        }
+      }
+    }
 
     // it's not a map so return the lexed value as a list value
     if (!peek< exactly<':'> >())
@@ -1019,7 +1075,7 @@
 
     Expression* value = parse_space_list();
 
-    Map* map = new (ctx.mem) Map(pstate, 1);
+    Map* map = new (ctx.mem) Map(opstate, 1);
     (*map) << make_pair(key, value);
 
     while (lex_css< exactly<','> >())
@@ -1029,6 +1085,16 @@
       { break; }
 
       Expression* key = parse_list();
+      if (String_Quoted* str = dynamic_cast<String_Quoted*>(key)) {
+        if (!str->quote_mark() && !str->is_delayed()) {
+          if (ctx.names_to_colors.count(str->value())) {
+            Color* c = new (ctx.mem) Color(*ctx.names_to_colors[str->value()]);
+            c->pstate(str->pstate());
+            c->disp(str->value());
+            key = c;
+          }
+        }
+      }
 
       if (!(lex< exactly<':'> >()))
       { error("invalid syntax", pstate); }
@@ -1038,9 +1104,16 @@
       (*map) << make_pair(key, value);
     }
 
-    if (map->has_duplicate_key())
-    { error("Duplicate key \"" + map->get_duplicate_key()->perform(&to_string) + "\" in map " + map->perform(&to_string) + ".", pstate); }
+    // Check was moved to eval step
+    // if (map->has_duplicate_key()) {
+    //   To_String to_string(&ctx);
+    //   error("Duplicate key \"" + map->get_duplicate_key()->perform(&to_string) + "\" in map " + map->perform(&to_string) + ".", pstate);
+    // }
 
+    ParserState ps = map->pstate();
+    ps.offset = pstate - ps + pstate.offset;
+    map->pstate(ps);
+
     return map;
   }
 
@@ -1051,7 +1124,7 @@
 
   Expression* Parser::parse_comma_list()
   {
-    if (peek< alternatives <
+    if (peek_css< alternatives <
           // exactly<'!'>,
           // exactly<':'>,
           exactly<';'>,
@@ -1063,14 +1136,14 @@
     { return new (ctx.mem) List(pstate, 0); }
     Expression* list1 = parse_space_list();
     // if it's a singleton, return it directly; don't wrap it
-    if (!peek< exactly<','> >(position)) return list1;
+    if (!peek_css< exactly<','> >(position)) return list1;
 
     List* comma_list = new (ctx.mem) List(pstate, 2, List::COMMA);
     (*comma_list) << list1;
 
-    while (lex< exactly<','> >())
+    while (lex_css< exactly<','> >())
     {
-      if (peek< alternatives <
+      if (peek_css< alternatives <
             // exactly<'!'>,
             exactly<';'>,
             exactly<'}'>,
@@ -1091,7 +1164,7 @@
   {
     Expression* disj1 = parse_disjunction();
     // if it's a singleton, return it directly; don't wrap it
-    if (peek< alternatives <
+    if (peek_css< alternatives <
           // exactly<'!'>,
           exactly<';'>,
           exactly<'}'>,
@@ -1108,7 +1181,7 @@
     List* space_list = new (ctx.mem) List(pstate, 2, List::SPACE);
     (*space_list) << disj1;
 
-    while (!(peek< alternatives <
+    while (!(peek_css< alternatives <
                // exactly<'!'>,
                exactly<';'>,
                exactly<'}'>,
@@ -1119,7 +1192,7 @@
                exactly<ellipsis>,
                default_flag,
                global_flag
-           > >(position))
+           > >(position)) && peek_css< optional_css_whitespace >() != end
     ) {
       (*space_list) << parse_disjunction();
     }
@@ -1211,6 +1284,11 @@
     }
     // if it's a singleton, return it directly; don't wrap it
     if (!peek< class_char< static_ops > >(position)) return factor;
+    return parse_operators(factor);
+  }
+
+  Expression* Parser::parse_operators(Expression* factor)
+  {
     // parse more factors and operators
     vector<Expression*> operands; // factors
     vector<Binary_Expression::Type> operators; // ops
@@ -1229,9 +1307,9 @@
 
   Expression* Parser::parse_factor()
   {
-    if (lex< exactly<'('> >()) {
+    if (lex_css< exactly<'('> >()) {
       Expression* value = parse_map();
-      if (!lex< exactly<')'> >()) error("unclosed parenthesis", pstate);
+      if (!lex_css< exactly<')'> >()) error("unclosed parenthesis", pstate);
       value->is_delayed(false);
       // make sure wrapped lists and division expressions are non-delayed within parentheses
       if (value->concrete_type() == Expression::LIST) {
@@ -1367,6 +1445,9 @@
         }
         // we need to skip anything inside strings
         // create a new target in parser/prelexer
+        if (peek < sequence < optional_spaces, exactly<rbrace> > >(p+2)) { position = p+2;
+          css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
+        }
         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
@@ -1390,13 +1471,22 @@
     return schema;
   }
 
+  String_Constant* Parser::parse_static_expression()
+  {
+    if (peek< sequence< number, optional_spaces, exactly<'/'>, optional_spaces, number > >()) {
+      return parse_static_value();
+    }
+    return 0;
+  }
+
   String_Constant* Parser::parse_static_value()
   {
     lex< static_value >();
     Token str(lexed);
     --str.end;
     --position;
-    String_Constant* str_node = new (ctx.mem) String_Constant(pstate, str);
+
+    String_Constant* str_node = new (ctx.mem) String_Constant(pstate, str.time_wspace());
     // str_node->is_delayed(true);
     return str_node;
   }
@@ -1418,6 +1508,7 @@
     if (!p) {
       String_Constant* str_node = new (ctx.mem) String_Constant(pstate, normalize_wspace(string(str.begin, str.end)));
       str_node->is_delayed(true);
+      str_node->quote_mark('*');
       return str_node;
     }
 
@@ -1426,8 +1517,14 @@
       p = find_first_in_interval< exactly<hash_lbrace> >(i, str.end);
       if (p) {
         if (i < p) {
-          (*schema) << new (ctx.mem) String_Constant(pstate, string(i, p)); // accumulate the preceding segment if it's nonempty
+          String_Constant* part = new (ctx.mem) String_Constant(pstate, normalize_wspace(string(i, p))); // accumulate the preceding segment if it's nonempty
+          part->is_delayed(true);
+          part->quote_mark('*'); // avoid unquote in interpolation
+          (*schema) << part;
         }
+        if (peek < sequence < optional_spaces, exactly<rbrace> > >(p+2)) { position = p+2;
+          css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
+        }
         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
@@ -1442,7 +1539,12 @@
         }
       }
       else { // no interpolants left; add the last segment if nonempty
-        if (i < str.end) (*schema) << new (ctx.mem) String_Constant(pstate, string(i, str.end));
+        if (i < str.end) {
+          String_Constant* part = new (ctx.mem) String_Constant(pstate, normalize_wspace(string(i, str.end)));
+          part->is_delayed(true);
+          part->quote_mark('*'); // avoid unquote in interpolation
+          (*schema) << part;
+        }
         break;
       }
     }
@@ -1456,15 +1558,13 @@
       *kwd_arg << new (ctx.mem) Variable(pstate, Util::normalize_underscores(lexed));
     } else {
       lex< alternatives< identifier_schema, identifier > >();
-      *kwd_arg << new (ctx.mem) String_Quoted(pstate, lexed);
+      *kwd_arg << new (ctx.mem) String_Constant(pstate, lexed);
     }
     lex< exactly<'='> >();
-    *kwd_arg << new (ctx.mem) String_Quoted(pstate, lexed);
+    *kwd_arg << new (ctx.mem) String_Constant(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 if (lex< alternatives< identifier_schema, identifier, number, hexa, hex > >()) {
-      *kwd_arg << new (ctx.mem) String_Quoted(pstate, lexed);
-    }
+    else if (peek < ie_keyword_arg_value >()) { *kwd_arg << parse_list(); }
     return kwd_arg;
   }
 
@@ -1472,11 +1572,21 @@
   {
     String_Schema* schema = new (ctx.mem) String_Schema(pstate);
     size_t num_items = 0;
+    if (peek<exactly<'}'>>()) {
+      css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
+    }
     while (position < stop) {
-      if (lex< interpolant >()) {
+      if (lex< spaces >() && num_items) {
+        (*schema) << new (ctx.mem) String_Constant(pstate, " ");
+      }
+      else if (lex< interpolant >()) {
         Token insides(Token(lexed.begin + 2, lexed.end - 1));
-        Expression* interp_node = Parser::from_token(insides, ctx, pstate).parse_list();
-        interp_node->is_interpolant(true);
+        Expression* interp_node;
+        Parser p = Parser::from_token(insides, ctx, pstate);
+        if (!(interp_node = p.parse_static_expression())) {
+          interp_node = p.parse_list();
+          interp_node->is_interpolant(true);
+        }
         (*schema) << interp_node;
       }
       else if (lex< exactly<'%'> >()) {
@@ -1492,17 +1602,28 @@
         (*schema) << new (ctx.mem) Textual(pstate, Textual::DIMENSION, lexed);
       }
       else if (lex< number >()) {
-        (*schema) << new (ctx.mem) Textual(pstate, Textual::NUMBER, lexed);
+        Expression* factor = new (ctx.mem) Textual(pstate, Textual::NUMBER, lexed);
+        if (peek< class_char< static_ops > >()) {
+          (*schema) << parse_operators(factor);
+        } else {
+          (*schema) << factor;
+        }
       }
       else if (lex< hex >()) {
         (*schema) << new (ctx.mem) Textual(pstate, Textual::HEX, unquote(lexed));
       }
-      else if (lex< quoted_string >()) {
+      else if (lex < exactly < '-' > >()) {
         (*schema) << new (ctx.mem) String_Constant(pstate, lexed);
       }
+      else if (lex< quoted_string >()) {
+        (*schema) << new (ctx.mem) String_Quoted(pstate, lexed);
+      }
       else if (lex< variable >()) {
         (*schema) << new (ctx.mem) Variable(pstate, Util::normalize_underscores(lexed));
       }
+      else if (peek< parenthese_scope >()) {
+        (*schema) << parse_factor();
+      }
       else {
         error("error parsing interpolated value", pstate);
       }
@@ -1565,6 +1686,9 @@
         }
         // we need to skip anything inside strings
         // create a new target in parser/prelexer
+        if (peek < sequence < optional_spaces, exactly<rbrace> > >(p+2)) { position = p+2;
+          css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
+        }
         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
@@ -1609,8 +1733,10 @@
   {
     lex< identifier >();
     string name(lexed);
+
+    ParserState call_pos = pstate;
     Arguments* args = parse_arguments(name == "url");
-    return new (ctx.mem) Function_Call(pstate, name, args);
+    return new (ctx.mem) Function_Call(call_pos, name, args);
   }
 
   Function_Call_Schema* Parser::parse_function_call_schema()
@@ -1976,6 +2102,7 @@
            (q = peek< class_name >(p))                             ||
            (q = peek< sequence< pseudo_prefix, identifier > >(p))  ||
            (q = peek< percentage >(p))                             ||
+           (q = peek< variable >(p))                            ||
            (q = peek< dimension >(p))                              ||
            (q = peek< quoted_string >(p))                          ||
            (q = peek< exactly<'*'> >(p))                           ||
@@ -2085,6 +2212,56 @@
     return result;
   }
 
+
+  Selector_Lookahead Parser::lookahead_for_value(const char* start)
+  {
+    const char* p = start ? start : position;
+    const char* q;
+    bool saw_interpolant = false;
+    bool saw_stuff = false;
+
+    while ((q = peek< identifier >(p))                             ||
+           (q = peek< percentage >(p))                             ||
+           (q = peek< dimension >(p))                              ||
+           (q = peek< quoted_string >(p))                          ||
+           (q = peek< variable >(p))                               ||
+           (q = peek< exactly<'*'> >(p))                           ||
+           (q = peek< exactly<'+'> >(p))                           ||
+           (q = peek< exactly<'~'> >(p))                           ||
+           (q = peek< exactly<'>'> >(p))                           ||
+           (q = peek< exactly<','> >(p))                           ||
+           (q = peek< sequence<parenthese_scope, interpolant>>(p)) ||
+           (saw_stuff && (q = peek< exactly<'-'> >(p)))            ||
+           (q = peek< binomial >(p))                               ||
+           (q = peek< block_comment >(p))                          ||
+           (q = peek< sequence< optional<sign>,
+                                zero_plus<digit>,
+                                exactly<'n'> > >(p))               ||
+           (q = peek< sequence< optional<sign>,
+                                one_plus<digit> > >(p))            ||
+           (q = peek< number >(p))                                 ||
+           (q = peek< sequence< exactly<'&'>,
+                                identifier_alnums > >(p))          ||
+           (q = peek< exactly<'&'> >(p))                           ||
+           (q = peek< exactly<'%'> >(p))                           ||
+           (q = peek< sequence< exactly<'.'>, interpolant > >(p))  ||
+           (q = peek< sequence< exactly<'#'>, interpolant > >(p))  ||
+           (q = peek< sequence< one_plus< exactly<'-'> >, interpolant > >(p))  ||
+           (q = peek< sequence< pseudo_prefix, interpolant > >(p)) ||
+           (q = peek< interpolant >(p))                            ||
+           (q = peek< optional >(p))) {
+      p = q;
+      if (*(p - 1) == '}') saw_interpolant = true;
+      saw_stuff = true;
+    }
+
+    Selector_Lookahead result;
+    result.found            = peek< alternatives< exactly<';'>, exactly<'}'>, exactly<'{'> > >(p) && saw_stuff ? p : 0;
+    result.has_interpolants = saw_interpolant;
+
+    return result;
+  }
+
   void Parser::read_bom()
   {
     size_t skip = 0;
@@ -2197,14 +2374,16 @@
     const char* pos = peek < optional_spaces >();
     bool ellipsis_left = false;
     const char* pos_left(pos);
-    while (*pos_left && pos_left >= source) {
+    while (*pos_left && pos_left > source) {
       if (pos - pos_left > max_len) {
         ellipsis_left = true;
         break;
       }
-      if (*pos_left == '\r') break;
-      if (*pos_left == '\n') break;
-      -- pos_left;
+      const char* prev = pos_left - 1;
+      if (*prev == '\r') break;
+      if (*prev == '\n') break;
+      if (*prev == 10) break;
+      pos_left = prev;
     }
     bool ellipsis_right = false;
     const char* pos_right(pos);
@@ -2215,6 +2394,7 @@
       }
       if (*pos_right == '\r') break;
       if (*pos_right == '\n') break;
+      if (*pos_left == 10) break;
       ++ pos_right;
     }
     string left(pos_left, pos);
diff --git a/libsass/parser.hpp b/libsass/parser.hpp
--- a/libsass/parser.hpp
+++ b/libsass/parser.hpp
@@ -50,13 +50,15 @@
 
     Parser(Context& ctx, const ParserState& pstate)
     : ParserState(pstate), ctx(ctx), block_stack(0), stack(0), last_media_block(0),
-      source(0), position(0), end(0), before_token(pstate), after_token(pstate), pstate("[NULL]"), indentation(0)
+      source(0), position(0), end(0), before_token(pstate), after_token(pstate), pstate(pstate), indentation(0)
     { in_at_root = false; stack.push_back(nothing); }
 
     // 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]"));
+    // special static parsers to convert strings into certain selectors
+    static Selector_List* parse_selector(const char* src, Context& ctx, ParserState pstate = ParserState("[SELECTOR]"));
 
 #ifdef __clang__
 
@@ -165,11 +167,17 @@
     template <prelexer mx>
     const char* lex_css()
     {
+      // copy old token
+      Token prev = lexed;
       // throw away comments
       // update srcmap position
       lex < css_comments >();
-      // now lex a token
-      return lex< mx >();
+      // now lex a new token
+      const char* pos = lex< mx >();
+      // maybe restore prev token
+      if (pos == 0) lexed = prev;
+      // return match
+      return pos;
     }
 
     // all block comments will be skipped and thrown away
@@ -233,10 +241,12 @@
     Function_Call_Schema* parse_function_call_schema();
     String* parse_interpolated_chunk(Token, bool constant = false);
     String* parse_string();
+    String_Constant* parse_static_expression();
     String_Constant* parse_static_value();
     String* parse_ie_property();
     String* parse_ie_keyword_arg();
     String_Schema* parse_value_schema(const char* stop);
+    Expression* parse_operators(Expression* factor);
     String* parse_identifier_schema();
     // String_Schema* parse_url_schema();
     If* parse_if_directive(bool else_if = false);
@@ -264,6 +274,7 @@
 
     void parse_block_comments(Block* block);
 
+    Selector_Lookahead lookahead_for_value(const char* start = 0);
     Selector_Lookahead lookahead_for_selector(const char* start = 0);
     Selector_Lookahead lookahead_for_extension_target(const char* start = 0);
 
diff --git a/libsass/position.hpp b/libsass/position.hpp
--- a/libsass/position.hpp
+++ b/libsass/position.hpp
@@ -89,6 +89,11 @@
     size_t length()    const { return end - begin; }
     string ws_before() const { return string(prefix, begin); }
     string to_string() const { return string(begin, end); }
+    string time_wspace() const {
+      string str(to_string());
+      string whitespaces(" \t\f\v\n\r");
+      return str.erase(str.find_last_not_of(whitespaces)+1);
+    }
 
     operator bool()   { return begin && end && begin >= end; }
     operator string() { return to_string(); }
@@ -106,6 +111,7 @@
     public: // down casts
       Offset off() { return *this; };
       Position pos() { return *this; };
+      ParserState pstate() { return *this; };
 
     public:
       string path;
diff --git a/libsass/prelexer.cpp b/libsass/prelexer.cpp
--- a/libsass/prelexer.cpp
+++ b/libsass/prelexer.cpp
@@ -34,7 +34,12 @@
     {
       return sequence<
                zero_plus < space >,
-               delimited_by<slash_star, star_slash, false> >(src);
+               delimited_by<
+                 slash_star,
+                 star_slash,
+                 false
+               >
+             >(src);
     }
     /* not use anymore - remove?
     const char* block_comment_prefix(const char* src) {
@@ -143,7 +148,12 @@
         exactly <'\''>,
         zero_plus <
           alternatives <
-            // skip all escaped chars first
+            // skip escapes
+            sequence <
+              exactly < '\\' >,
+              exactly < '\r' >,
+              exactly < '\n' >
+            >,
             escape_seq,
             // skip interpolants
             interpolant,
@@ -162,7 +172,12 @@
         exactly <'"'>,
         zero_plus <
           alternatives <
-            // skip all escaped chars first
+            // skip escapes
+            sequence <
+              exactly < '\\' >,
+              exactly < '\r' >,
+              exactly < '\n' >
+            >,
             escape_seq,
             // skip interpolants
             interpolant,
@@ -426,11 +441,16 @@
     const char* uri_value(const char* src)
     {
       return
-      zero_plus <
-        alternatives <
-          alnum,
-          exactly <'/'>,
-          class_char < uri_chars >
+      sequence <
+        negate <
+          exactly < '$' >
+        >,
+        zero_plus <
+          alternatives <
+            alnum,
+            exactly <'/'>,
+            class_char < uri_chars >
+          >
         >
       >(src);
     }
@@ -601,7 +621,7 @@
       >(src);
     }
     const char* ie_expression(const char* src) {
-      return sequence < word<expression_kwd>, delimited_by< '(', ')', true> >(src);
+      return sequence < word<expression_kwd>, exactly<'('>, skip_over_scopes< exactly<'('>, exactly<')'> > >(src);
     }
     const char* ie_property(const char* src) {
       return alternatives < ie_expression, ie_progid >(src);
@@ -612,13 +632,38 @@
     //                    zero_plus< sequence< optional_css_whitespace, exactly<','>, optional_css_whitespace, alternatives< ie_keyword_arg, value_schema, quoted_string, interpolant, number, identifier, delimited_by<'(', ')', true> > > > >(src);
     // }
 
+    const char* ie_keyword_arg_property(const char* src) {
+      return alternatives <
+          variable,
+          identifier_schema,
+          identifier
+        >(src);
+    }
+    const char* ie_keyword_arg_value(const char* src) {
+      return alternatives <
+          variable,
+          identifier_schema,
+          identifier,
+          quoted_string,
+          number,
+          hexa,
+          sequence <
+            exactly < '(' >,
+            skip_over_scopes <
+              exactly < '(' >,
+              exactly < ')' >
+            >
+          >
+        >(src);
+    }
+
     const char* ie_keyword_arg(const char* src) {
-      return sequence<
-        alternatives< variable, identifier_schema, identifier >,
+      return sequence <
+        ie_keyword_arg_property,
         optional_css_whitespace,
         exactly<'='>,
         optional_css_whitespace,
-        alternatives< variable, identifier_schema, identifier, quoted_string, number, hexa >
+        ie_keyword_arg_value
       >(src);
     }
 
@@ -705,7 +750,10 @@
     }
 
     const char* static_value(const char* src) {
-      return sequence< static_component,
+      return sequence< sequence<
+                         static_component,
+                         zero_plus< identifier >
+                       >,
                        zero_plus < sequence<
                                    alternatives<
                                      sequence< optional_spaces, alternatives<
@@ -717,8 +765,20 @@
                                    >,
                                    static_component
                        > >,
+                       optional_css_whitespace,
                        alternatives< exactly<';'>, exactly<'}'> >
                       >(src);
     }
+
+    const char* parenthese_scope(const char* src) {
+      return sequence <
+        exactly < '(' >,
+        skip_over_scopes <
+          exactly < '(' >,
+          exactly < ')' >
+        >
+      >(src);
+    }
+
   }
 }
diff --git a/libsass/prelexer.hpp b/libsass/prelexer.hpp
--- a/libsass/prelexer.hpp
+++ b/libsass/prelexer.hpp
@@ -58,7 +58,7 @@
     // 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) {
+    const char* skip_over_scopes(const char* src, const char* end) {
 
       size_t level = 0;
       bool in_squote = false;
@@ -85,8 +85,9 @@
         }
 
         // find another opener inside?
-        else if (start(src)) {
+        else if (const char* pos = start(src)) {
           ++ level; // increase counter
+          src = pos - 1; // advance position
         }
 
         // look for the closer (maybe final, maybe not)
@@ -96,6 +97,8 @@
           // return position at end of stop
           // delimiter may be multiple chars
           else return final;
+          // advance position
+          src = final - 1;
         }
 
         // next
@@ -105,6 +108,19 @@
       return 0;
     }
 
+    // skip to a skip delimited by parentheses
+    // uses smart `skip_over_scopes` internally
+    const char* parenthese_scope(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) {
+      return skip_over_scopes<start, stop>(src, 0);
+    }
+
     // Match a sequence of characters delimited by the supplied chars.
     template <prelexer start, prelexer stop>
     const char* recursive_scopes(const char* src) {
@@ -296,6 +312,8 @@
     const char* ie_expression(const char* src);
     const char* ie_property(const char* src);
     const char* ie_keyword_arg(const char* src);
+    const char* ie_keyword_arg_value(const char* src);
+    const char* ie_keyword_arg_property(const char* src);
 
     // match urls
     const char* url(const char* src);
diff --git a/libsass/sass_values.cpp b/libsass/sass_values.cpp
--- a/libsass/sass_values.cpp
+++ b/libsass/sass_values.cpp
@@ -38,6 +38,7 @@
 
   struct Sass_String {
     enum Sass_Tag tag;
+    bool          quoted;
     char*         value;
   };
 
@@ -110,6 +111,8 @@
   // Getters and setters for Sass_String
   const char* ADDCALL sass_string_get_value(const union Sass_Value* v) { return v->string.value; }
   void ADDCALL sass_string_set_value(union Sass_Value* v, char* value) { v->string.value = value; }
+  bool ADDCALL sass_string_is_quoted(const union Sass_Value* v) { return v->string.quoted; }
+  void ADDCALL sass_string_set_quoted(union Sass_Value* v, bool quoted) { v->string.quoted = quoted; }
 
   // Getters and setters for Sass_Boolean
   bool ADDCALL sass_boolean_get_value(const union Sass_Value* v) { return v->boolean.value; }
@@ -187,6 +190,18 @@
   {
     Sass_Value* v = (Sass_Value*) calloc(1, sizeof(Sass_Value));
     if (v == 0) return 0;
+    v->string.quoted = false;
+    v->string.tag = SASS_STRING;
+    v->string.value = val ? sass_strdup(val) : 0;
+    if (v->string.value == 0) { free(v); return 0; }
+    return v;
+  }
+
+  union Sass_Value* ADDCALL sass_make_qstring(const char* val)
+  {
+    Sass_Value* v = (Sass_Value*) calloc(1, sizeof(Sass_Value));
+    if (v == 0) return 0;
+    v->string.quoted = true;
     v->string.tag = SASS_STRING;
     v->string.value = val ? sass_strdup(val) : 0;
     if (v->string.value == 0) { free(v); return 0; }
diff --git a/libsass/sass_values.h b/libsass/sass_values.h
--- a/libsass/sass_values.h
+++ b/libsass/sass_values.h
@@ -57,6 +57,8 @@
 // Getters and setters for Sass_String
 ADDAPI const char* ADDCALL sass_string_get_value (const union Sass_Value* v);
 ADDAPI void ADDCALL sass_string_set_value (union Sass_Value* v, char* value);
+ADDAPI bool ADDCALL sass_string_is_quoted(const union Sass_Value* v);
+ADDAPI void ADDCALL sass_string_set_quoted(union Sass_Value* v, bool quoted);
 
 // Getters and setters for Sass_Boolean
 ADDAPI bool ADDCALL sass_boolean_get_value (const union Sass_Value* v);
@@ -101,6 +103,7 @@
 ADDAPI union Sass_Value* ADDCALL sass_make_null    (void);
 ADDAPI union Sass_Value* ADDCALL sass_make_boolean (bool val);
 ADDAPI union Sass_Value* ADDCALL sass_make_string  (const char* val);
+ADDAPI union Sass_Value* ADDCALL sass_make_qstring (const char* val);
 ADDAPI union Sass_Value* ADDCALL sass_make_number  (double val, const char* unit);
 ADDAPI union Sass_Value* ADDCALL sass_make_color   (double r, double g, double b, double a);
 ADDAPI union Sass_Value* ADDCALL sass_make_list    (size_t len, enum Sass_Separator sep);
diff --git a/libsass/to_string.cpp b/libsass/to_string.cpp
--- a/libsass/to_string.cpp
+++ b/libsass/to_string.cpp
@@ -11,15 +11,15 @@
 namespace Sass {
   using namespace std;
 
-  To_String::To_String(Context* ctx)
-  : ctx(ctx) { }
+  To_String::To_String(Context* ctx, bool in_declaration)
+  : ctx(ctx), in_declaration(in_declaration) { }
   To_String::~To_String() { }
 
   inline string To_String::fallback_impl(AST_Node* n)
   {
     Emitter emitter(ctx);
     Inspect i(emitter);
-    i.in_declaration_list = true;
+    i.in_declaration = in_declaration;
     n->perform(&i);
     return i.get_buffer();
   }
diff --git a/libsass/to_string.hpp b/libsass/to_string.hpp
--- a/libsass/to_string.hpp
+++ b/libsass/to_string.hpp
@@ -18,9 +18,10 @@
     string fallback_impl(AST_Node* n);
 
     Context* ctx;
+    bool in_declaration;
 
   public:
-    To_String(Context* ctx = 0);
+    To_String(Context* ctx = 0, bool in_declaration = true);
     virtual ~To_String();
 
     string operator()(Null* n);
diff --git a/libsass/units.cpp b/libsass/units.cpp
--- a/libsass/units.cpp
+++ b/libsass/units.cpp
@@ -1,55 +1,155 @@
+#include <stdexcept>
 #include "units.hpp"
 
-#define PI 3.14159265358979323846
-
 namespace Sass {
 
-  double conversion_factors[10][10] = {
-             /*  in         cm         pc         mm         pt         px                 deg        grad       rad        turn      */
-    /* in   */ { 1,         2.54,      6,         25.4,      72,        96,                1,         1,         1,         1         },
-    /* cm   */ { 1.0/2.54,  1,         6.0/2.54,  10,        72.0/2.54, 96.0/2.54,         1,         1,         1,         1         },
-    /* pc   */ { 1.0/6.0,   2.54/6.0,  1,         25.4/6.0,  72.0/6.0,  96.0/6.0,          1,         1,         1,         1         },
-    /* mm   */ { 1.0/25.4,  1.0/10.0,  6.0/25.4,  1,         72.0/25.4, 96.0/25.4,         1,         1,         1,         1         },
-    /* pt   */ { 1.0/72.0,  2.54/72.0, 6.0/72.0,  25.4/72.0, 1,         96.0/72.0,         1,         1,         1,         1         },
-    /* px   */ { 1.0/96.0,  2.54/96.0, 6.0/96.0,  25.4/96.0, 72.0/96.0, 1,                 1,         1,         1,         1         },
-    /* deg  */ { 1       ,  1        , 1       ,  1        , 1        , 1,                 1,         40.0/36.0, PI/180.0,  1.0/360.0 },
-    /* grad */ { 1       ,  1        , 1       ,  1        , 1        , 1,                 36.0/40.0, 1,         PI/200.0,  1.0/400.0 },
-    /* rad  */ { 1       ,  1        , 1       ,  1        , 1        , 1,                 180.0/PI,  200.0/PI,  1,         PI/2.0    },
-    /* turn */ { 1       ,  1        , 1       ,  1        , 1        , 1,                 360.0/1.0, 400.0/1.0, 2.0*PI,    1         }
+  /* the conversion matrix can be readed the following way */
+  /* if you go down, the factor is for the numerator (multiply) */
+  /* if you go right, the factor is for the denominator (divide) */
+  /* and yes, we actually use both, not sure why, but why not!? */
+
+  const double size_conversion_factors[6][6] =
+  {
+             /*  in         cm         pc         mm         pt         px        */
+    /* in   */ { 1,         2.54,      6,         25.4,      72,        96,       },
+    /* cm   */ { 1.0/2.54,  1,         6.0/2.54,  10,        72.0/2.54, 96.0/2.54 },
+    /* pc   */ { 1.0/6.0,   2.54/6.0,  1,         25.4/6.0,  72.0/6.0,  96.0/6.0  },
+    /* mm   */ { 1.0/25.4,  1.0/10.0,  6.0/25.4,  1,         72.0/25.4, 96.0/25.4 },
+    /* pt   */ { 1.0/72.0,  2.54/72.0, 6.0/72.0,  25.4/72.0, 1,         96.0/72.0 },
+    /* px   */ { 1.0/96.0,  2.54/96.0, 6.0/96.0,  25.4/96.0, 72.0/96.0, 1,        }
   };
 
-  Unit string_to_unit(const string& s)
+  const double angle_conversion_factors[4][4] =
   {
-    if      (s == "in") return IN;
-    else if (s == "cm") return CM;
+             /*  deg        grad       rad        turn      */
+    /* deg  */ { 1,         40.0/36.0, PI/180.0,  1.0/360.0 },
+    /* grad */ { 36.0/40.0, 1,         PI/200.0,  1.0/400.0 },
+    /* rad  */ { 180.0/PI,  200.0/PI,  1,         0.5/PI    },
+    /* turn */ { 360.0,     400.0,     2.0*PI,    1         }
+  };
+
+  const double time_conversion_factors[2][2] =
+  {
+             /*  s          ms        */
+    /* s    */ { 1,         1000.0    },
+    /* ms   */ { 1/1000.0,  1         }
+  };
+  const double frequency_conversion_factors[2][2] =
+  {
+             /*  Hz         kHz       */
+    /* Hz   */ { 1,         1/1000.0  },
+    /* kHz  */ { 1000.0,    1         }
+  };
+  const double resolution_conversion_factors[3][3] =
+  {
+             /*  dpi        dpcm       dppx     */
+    /* dpi  */ { 1,         2.54,      96       },
+    /* dpcm */ { 1/2.54,    1,         96/2.54  },
+    /* dppx */ { 1/96.0,    2.54/96,   1        }
+  };
+
+  SassUnitType get_unit_type(SassUnit unit)
+  {
+    switch (unit & 0xFF00)
+    {
+      case SIZE: return SIZE; break;
+      case ANGLE: return ANGLE; break;
+      case TIME: return TIME; break;
+      case FREQUENCY: return FREQUENCY; break;
+      case RESOLUTION: return RESOLUTION; break;
+      default: return INCOMMENSURABLE; break;
+    }
+  };
+
+  SassUnit string_to_unit(const string& s)
+  {
+    // size units
+    if      (s == "px") return PX;
+    else if (s == "pt") return PT;
     else if (s == "pc") return PC;
     else if (s == "mm") return MM;
-    else if (s == "pt") return PT;
-    else if (s == "px") return PX;
+    else if (s == "cm") return CM;
+    else if (s == "in") return IN;
+    // angle units
     else if (s == "deg") return DEG;
     else if (s == "grad") return GRAD;
     else if (s == "rad") return RAD;
     else if (s == "turn") return TURN;
-    else                return INCOMMENSURABLE;
+    // time units
+    else if (s == "s") return SEC;
+    else if (s == "ms") return MSEC;
+    // frequency units
+    else if (s == "Hz") return HERTZ;
+    else if (s == "kHz") return KHERTZ;
+    // resolutions units
+    else if (s == "dpi") return DPI;
+    else if (s == "dpcm") return DPCM;
+    else if (s == "dppx") return DPPX;
+    // for unknown units
+    else return UNKNOWN;
   }
 
-  double conversion_factor(const string& s1, const string& s2)
+  const char* unit_to_string(SassUnit unit)
   {
-    Unit u1 = string_to_unit(s1);
-    Unit u2 = string_to_unit(s2);
-    double factor;
-    if (u1 == INCOMMENSURABLE || u2 == INCOMMENSURABLE)
-      factor = 0;
-    else
-      factor = conversion_factors[u1][u2];
-    return factor;
+    switch (unit) {
+      // size units
+      case PX: return "px"; break;
+      case PT: return "pt"; break;
+      case PC: return "pc"; break;
+      case MM: return "mm"; break;
+      case CM: return "cm"; break;
+      case IN: return "in"; break;
+      // angle units
+      case DEG: return "deg"; break;
+      case GRAD: return "grad"; break;
+      case RAD: return "rad"; break;
+      case TURN: return "turn"; break;
+      // time units
+      case SEC: return "s"; break;
+      case MSEC: return "ms"; break;
+      // frequency units
+      case HERTZ: return "Hz"; break;
+      case KHERTZ: return "kHz"; break;
+      // resolutions units
+      case DPI: return "dpi"; break;
+      case DPCM: return "dpcm"; break;
+      case DPPX: return "dppx"; break;
+      // for unknown units
+      default: return ""; break;;
+    }
   }
 
-  /* not used anymore - remove?
-  double convert(double n, const string& from, const string& to)
+  // throws incompatibleUnits exceptions
+  double conversion_factor(const string& s1, const string& s2)
   {
-    double factor = conversion_factor(from, to);
-    return factor ? factor * n : n;
-  } */
+    // assert for same units
+    if (s1 == s2) return 1;
+    // get unit enum from string
+    SassUnit u1 = string_to_unit(s1);
+    SassUnit u2 = string_to_unit(s2);
+    // query unit group types
+    SassUnitType t1 = get_unit_type(u1);
+    SassUnitType t2 = get_unit_type(u2);
+    // get absolute offset
+    // used for array acces
+    size_t i1 = u1 - t1;
+    size_t i2 = u2 - t2;
+    // error if units are not of the same group
+    if (t1 != t2) throw incompatibleUnits(u1, u2);
+    // only process known units
+    if (u1 != UNKNOWN && u2 != UNKNOWN) {
+      switch (t1) {
+        case SIZE: return size_conversion_factors[i1][i2]; break;
+        case ANGLE: return angle_conversion_factors[i1][i2]; break;
+        case TIME: return time_conversion_factors[i1][i2]; break;
+        case FREQUENCY: return frequency_conversion_factors[i1][i2]; break;
+        case RESOLUTION: return resolution_conversion_factors[i1][i2]; break;
+        // ToDo: should we throw error here?
+        case INCOMMENSURABLE: return 0; break;
+      }
+    }
+    // fallback
+    return 1;
+  }
 
 }
diff --git a/libsass/units.hpp b/libsass/units.hpp
--- a/libsass/units.hpp
+++ b/libsass/units.hpp
@@ -1,15 +1,89 @@
 #ifndef SASS_UNITS_H
 #define SASS_UNITS_H
 
+#include <cmath>
 #include <string>
+#include <sstream>
 
 namespace Sass {
   using namespace std;
-  enum Unit { IN, CM, PC, MM, PT, PX, DEG, GRAD, RAD, TURN, INCOMMENSURABLE };
-  extern double conversion_factors[10][10];
-  Unit string_to_unit(const string&);
+
+  const double PI = acos(-1);
+
+  enum SassUnitType {
+    SIZE = 0x000,
+    ANGLE = 0x100,
+    TIME = 0x200,
+    FREQUENCY = 0x300,
+    RESOLUTION = 0x400,
+    INCOMMENSURABLE = 0x500
+  };
+
+  enum SassUnit {
+
+    // size units
+    IN = SIZE,
+    CM,
+    PC,
+    MM,
+    PT,
+    PX,
+
+    // angle units
+    DEG = ANGLE,
+    GRAD,
+    RAD,
+    TURN,
+
+    // time units
+    SEC = TIME,
+    MSEC,
+
+    // frequency units
+    HERTZ = FREQUENCY,
+    KHERTZ,
+
+    // resolutions units
+    DPI = RESOLUTION,
+    DPCM,
+    DPPX,
+
+    // for unknown units
+    UNKNOWN = INCOMMENSURABLE
+
+  };
+
+  extern const double size_conversion_factors[6][6];
+  extern const double angle_conversion_factors[4][4];
+  extern const double time_conversion_factors[2][2];
+  extern const double frequency_conversion_factors[2][2];
+  extern const double resolution_conversion_factors[3][3];
+
+  SassUnit string_to_unit(const string&);
+  const char* unit_to_string(SassUnit unit);
+  SassUnitType get_unit_type(SassUnit unit);
+  // throws incompatibleUnits exceptions
   double conversion_factor(const string&, const string&);
-  // double convert(double, const string&, const string&);
+
+  class incompatibleUnits: public exception
+  {
+    public:
+      const char* msg;
+      incompatibleUnits(SassUnit a, SassUnit b)
+      : exception()
+      {
+        stringstream ss;
+        ss << "Incompatible units: ";
+        ss << "'" << unit_to_string(a) << "' and ";
+        ss << "'" << unit_to_string(b) << "'";
+        msg = ss.str().c_str();
+      };
+      virtual const char* what() const throw()
+      {
+        return msg;
+      }
+  };
+
 }
 
 #endif
diff --git a/libsass/util.cpp b/libsass/util.cpp
--- a/libsass/util.cpp
+++ b/libsass/util.cpp
@@ -44,6 +44,59 @@
     return atof(str);
   }
 
+  string string_eval_escapes(const string& s)
+  {
+
+    string out("");
+    bool esc = false;
+    for (size_t i = 0, L = s.length(); i < L; ++i) {
+      if(s[i] == '\\' && esc == false) {
+        esc = true;
+
+        // 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);
+
+          if (cp == 0) cp = 0xFFFD;
+
+          // assert invalid code points
+          if (cp >= 1) {
+
+            // 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++) out.push_back(u[m]);
+
+            // skip some more chars?
+            i += len - 1; esc = false;
+            if (cp == 10) out += ' ';
+
+          }
+
+        }
+
+      }
+      else {
+        out += s[i];
+        esc = false;
+      }
+    }
+    return out;
+
+  }
+
   // double escape every escape sequences
   // escape unescaped quotes and backslashes
   string string_escape(const string& str)
@@ -177,6 +230,7 @@
   {
     string str = "";
     size_t has = 0;
+    char prev = 0;
     bool clean = false;
     for (auto i : text) {
       if (clean) {
@@ -188,7 +242,8 @@
         else {
           clean = false;
           str += ' ';
-          str += i;
+          if (prev == '*' && i == '/') str += "*/";
+          else str += i;
         }
       } else if (i == '\n') {
         clean = true;
@@ -197,6 +252,7 @@
       } else {
         str += i;
       }
+      prev = i;
     }
     if (has) return str;
     else return text;
@@ -206,21 +262,15 @@
   {
     bool ws = false;
     bool esc = false;
-    char inside_str = 0;
     string text = "";
-    for(auto i : str) {
+    for(const char& i : str) {
       if (!esc && i == '\\') {
         esc = true;
+        ws = false;
         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;
+        ws = false;
         text += i;
       } else if (
         i == ' ' ||
@@ -327,12 +377,12 @@
       }
       // 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]"));
-      }
+      // 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]"));
+      // }
       else {
         skipped = false;
         unq.push_back(s[i]);
@@ -345,7 +395,7 @@
 
   }
 
-  string quote(const string& s, char q)
+  string quote(const string& s, char q, bool keep_linefeed_whitespace)
   {
 
     // autodetect with fallback to given quote
@@ -374,6 +424,10 @@
       if (cp == 10) {
         quoted.push_back('\\');
         quoted.push_back('a');
+        // we hope we can remove this flag once we figure out
+        // why ruby sass has these different output behaviors
+        if (keep_linefeed_whitespace)
+          quoted.push_back(' ');
       } else if (cp < 127) {
         quoted.push_back((char) cp);
       } else {
@@ -475,6 +529,8 @@
           } else {
             hasDeclarations = true;
           }
+        } else if (Declaration* d = dynamic_cast<Declaration*>(stm)) {
+          return isPrintable(d, style);
         } else {
           hasDeclarations = true;
         }
@@ -485,6 +541,28 @@
       }
 
       return false;
+    }
+
+    bool isPrintable(String_Constant* s, Output_Style style)
+    {
+      return ! s->value().empty();
+    }
+
+    bool isPrintable(String_Quoted* s, Output_Style style)
+    {
+      return true;
+    }
+
+    bool isPrintable(Declaration* d, Output_Style style)
+    {
+      Expression* val = d->value();
+      if (String_Quoted* sq = dynamic_cast<String_Quoted*>(val)) return isPrintable(sq, style);
+      if (String_Constant* sc = dynamic_cast<String_Constant*>(val)) return isPrintable(sc, style);
+      return true;
+    }
+
+    bool isPrintable(Expression* e, Output_Style style) {
+      return isPrintable(e, style);
     }
 
     bool isPrintable(Feature_Block* f, Output_Style style) {
diff --git a/libsass/util.hpp b/libsass/util.hpp
--- a/libsass/util.hpp
+++ b/libsass/util.hpp
@@ -1,6 +1,7 @@
 #ifndef SASS_UTIL_H
 #define SASS_UTIL_H
 
+#include <cstdio>
 #include <vector>
 #include <string>
 #include "ast_fwd_decl.hpp"
@@ -12,6 +13,7 @@
   double sass_atof(const char* str);
   string string_escape(const string& str);
   string string_unescape(const string& str);
+  string string_eval_escapes(const string& str);
   string read_css_string(const string& str);
   string evacuate_quotes(const string& str);
   string evacuate_escapes(const string& str);
@@ -19,7 +21,7 @@
   string comment_to_string(const string& text);
   string normalize_wspace(const string& str);
 
-  string quote(const string&, char q = 0);
+  string quote(const string&, char q = 0, bool keep_linefeed_whitespace = false);
   string unquote(const string&, char* q = 0);
   char detect_best_quotemark(const char* s, char qm = '"');
 
@@ -41,6 +43,10 @@
     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 isPrintable(String_Constant* s, Output_Style style = NESTED);
+    bool isPrintable(String_Quoted* s, Output_Style style = NESTED);
+    bool isPrintable(Declaration* d, Output_Style style = NESTED);
+    bool isPrintable(Expression* e, Output_Style style = NESTED);
     bool isAscii(const char chr);
 
   }
diff --git a/tests/Main.hs b/tests/Main.hs
--- a/tests/Main.hs
+++ b/tests/Main.hs
@@ -26,7 +26,15 @@
 sampleOutput = "foo {\n  margin: 42px; }\n"
 
 main :: IO ()
-main = hspec $ do
+main = hspec $
   describe "Libsass" $ do
-    it "should correctly compile simple expression" $ do
-      simpleCompile sampleInput `shouldReturn` sampleOutput
+    it "should correctly compile simple expression" $
+        simpleCompile sampleInput `shouldReturn` sampleOutput
+
+    it "should report correct version" $ do
+        str <- peekCString libsass_version
+        str `shouldBe` "3.2.4-18-g3672"
+
+    it "should support quoted strings" $ withCString "sample" $ \cstr -> do
+        str <- sass_make_qstring cstr
+        sass_string_is_quoted str `shouldReturn` True
