diff --git a/Bindings/Libsass/Base.hs b/Bindings/Libsass/Base.hs
--- a/Bindings/Libsass/Base.hs
+++ b/Bindings/Libsass/Base.hs
@@ -25,11 +25,6 @@
     :: CString
     -> IO CString
 
-foreign import ccall unsafe "sass/base.h" sass_resolve_file
-    :: CString
-    -> Ptr CString
-    -> IO CString
-
 foreign import ccall unsafe "sass/base.h" libsass_version
     :: CString
 
diff --git a/Bindings/Libsass/Context.hs b/Bindings/Libsass/Context.hs
--- a/Bindings/Libsass/Context.hs
+++ b/Bindings/Libsass/Context.hs
@@ -139,14 +139,6 @@
     :: Ptr SassOptions
     -> IO CString
 
-foreign import ccall unsafe "sass/context.h" sass_option_get_plugin_path
-    :: Ptr SassOptions
-    -> IO CString
-
-foreign import ccall unsafe "sass/context.h" sass_option_get_include_path
-    :: Ptr SassOptions
-    -> IO CString
-
 foreign import ccall unsafe "sass/context.h" sass_option_get_source_map_file
     :: Ptr SassOptions
     -> IO CString
@@ -306,6 +298,15 @@
     :: Ptr SassContext
     -> IO (Ptr CString)
 
+foreign import ccall unsafe "sass/context.h" sass_option_get_include_path_size
+    :: Ptr SassOptions
+    -> IO CSize
+
+foreign import ccall unsafe "sass/context.h" sass_option_get_include_path
+    :: Ptr SassOptions
+    -> CSize
+    -> IO CString
+
 foreign import ccall unsafe "sass/context.h" sass_context_get_included_files_size
     :: Ptr SassContext
     -> IO CSize
@@ -363,6 +364,19 @@
     -> CSize
     -> IO SassImportEntry
 
+foreign import ccall unsafe "sass/context.h" sass_compiler_get_callee_stack_size
+    :: Ptr SassCompiler
+    -> IO CSize
+
+foreign import ccall unsafe "sass/context.h" sass_compiler_get_last_callee
+    :: Ptr SassCompiler
+    -> IO SassCalleeEntry
+
+foreign import ccall unsafe "sass/context.h" sass_compiler_get_callee_entry
+    :: Ptr SassCompiler
+    -> CSize
+    -> IO SassCalleeEntry
+
 foreign import ccall unsafe "sass/context.h" sass_option_push_plugin_path
     :: Ptr SassOptions
     -> CString
@@ -372,3 +386,24 @@
     :: Ptr SassOptions
     -> CString
     -> IO ()
+
+foreign import ccall unsafe "sass/context.h" sass_find_file
+    :: CString
+    -> Ptr SassOptions
+    -> IO CString
+
+foreign import ccall unsafe "sass/context.h" sass_find_include
+    :: CString
+    -> Ptr SassOptions
+    -> IO CString
+
+foreign import ccall unsafe "sass/context.h" sass_compiler_find_file
+    :: CString
+    -> Ptr SassCompiler
+    -> IO CString
+
+foreign import ccall unsafe "sass/context.h" sass_compiler_find_include
+    :: CString
+    -> Ptr SassCompiler
+    -> IO CString
+    
diff --git a/Bindings/Libsass/Functions.hs b/Bindings/Libsass/Functions.hs
--- a/Bindings/Libsass/Functions.hs
+++ b/Bindings/Libsass/Functions.hs
@@ -20,6 +20,10 @@
     -> SassImporterEntry
     -> IO ()
 
+foreign import ccall unsafe "sass/functions.h" sass_delete_importer_list
+    :: SassImporterList
+    -> IO ()
+
 foreign import ccall unsafe "sass/functions.h" sass_make_importer
     :: SassImporterFn
     -> CDouble
@@ -76,6 +80,63 @@
     -> CSize
     -> IO SassImportEntry
 
+foreign import ccall unsafe "sass/functions.h" sass_callee_get_name
+    :: SassCalleeEntry
+    -> IO CString
+
+foreign import ccall unsafe "sass/functions.h" sass_callee_get_path
+    :: SassCalleeEntry
+    -> IO CString
+
+foreign import ccall unsafe "sass/functions.h" sass_callee_get_line
+    :: SassCalleeEntry
+    -> IO CSize
+
+foreign import ccall unsafe "sass/functions.h" sass_callee_get_column
+    :: SassCalleeEntry
+    -> IO CSize
+
+foreign import ccall unsafe "sass/functions.h" sass_callee_get_type
+    :: SassCalleeEntry
+    -> IO CInt -- ^ Returns 'SassCalleeType'
+
+foreign import ccall unsafe "sass/functions.h" sass_callee_get_env
+    :: SassCalleeEntry
+    -> IO SassEnvFrame
+
+foreign import ccall unsafe "sass/functions.h" sass_env_get_lexical
+    :: SassEnvFrame
+    -> CString
+    -> IO (Ptr SassValue)
+
+foreign import ccall unsafe "sass/functions.h" sass_env_set_lexical
+    :: SassEnvFrame
+    -> CString
+    -> Ptr SassValue
+    -> IO ()
+
+foreign import ccall unsafe "sass/functions.h" sass_env_get_local
+    :: SassEnvFrame
+    -> CString
+    -> IO (Ptr SassValue)
+
+foreign import ccall unsafe "sass/functions.h" sass_env_set_local
+    :: SassEnvFrame
+    -> CString
+    -> Ptr SassValue
+    -> IO ()
+
+foreign import ccall unsafe "sass/functions.h" sass_env_get_global
+    :: SassEnvFrame
+    -> CString
+    -> IO (Ptr SassValue)
+
+foreign import ccall unsafe "sass/functions.h" sass_env_set_global
+    :: SassEnvFrame
+    -> CString
+    -> Ptr SassValue
+    -> IO ()
+
 foreign import ccall unsafe "sass/functions.h" sass_import_get_imp_path
     :: SassImportEntry
     -> IO CString
@@ -130,6 +191,14 @@
     -> Ptr ()
     -> IO SassFunctionEntry
 
+foreign import ccall unsafe "sass/functions.h" sass_delete_function
+    :: SassFunctionEntry
+    -> IO ()
+
+foreign import ccall unsafe "sass/functions.h" sass_delete_function_list
+    :: SassFunctionList
+    -> IO ()
+
 foreign import ccall unsafe "sass/functions.h" sass_function_get_list_entry
     :: SassFunctionList
     -> CSize
@@ -152,3 +221,4 @@
 foreign import ccall unsafe "sass/functions.h" sass_function_get_cookie
     :: SassFunctionEntry
     -> IO (Ptr ())
+
diff --git a/Bindings/Libsass/Types.hs b/Bindings/Libsass/Types.hs
--- a/Bindings/Libsass/Types.hs
+++ b/Bindings/Libsass/Types.hs
@@ -33,8 +33,6 @@
 
 -- From sass/context.h
 
-data SassCompiler
-data SassOptions
 data SassContext
 data SassFileContext
 data SassDataContext
@@ -56,10 +54,16 @@
 
 -- From sass/functions.h
 
+data SassEnv
+data SassCallee
 data SassImport
+data SassOptions
+data SassCompiler
 data SassImporter
 data SassFunction
 
+type SassEnvFrame = Ptr SassEnv
+type SassCalleeEntry = Ptr SassCallee
 type SassImportEntry = Ptr SassImport
 type SassImportList = Ptr (Ptr SassImport)
 type SassImporterEntry = Ptr SassImporter
@@ -81,6 +85,21 @@
   -> Ptr SassOptions
   -> IO (Ptr SassValue)
 type SassFunctionFn = FunPtr SassFunctionFnType
+
+data SassCalleeType = SassCalleeMixin
+                    | SassCalleeFunction
+                    | SassCalleeCFunction
+                    deriving (Eq, Show)
+
+instance Enum SassCalleeType where
+    fromEnum SassCalleeMixin = 0
+    fromEnum SassCalleeFunction = 1
+    fromEnum SassCalleeCFunction = 2
+
+    toEnum 0 = SassCalleeMixin
+    toEnum 1 = SassCalleeFunction
+    toEnum 2 = SassCalleeCFunction
+    toEnum u = error ("SassCalleeType.toEnum: Cannot match " ++ show u)
 
 -- From sass/values.h
 
diff --git a/Bindings/Libsass/Values.hs b/Bindings/Libsass/Values.hs
--- a/Bindings/Libsass/Values.hs
+++ b/Bindings/Libsass/Values.hs
@@ -35,6 +35,7 @@
 foreign import ccall unsafe "sass/values.h" sass_make_list
     :: CSize
     -> CInt -- ^ 'SassSeparator'
+    -> Bool
     -> IO (Ptr SassValue)
 
 foreign import ccall unsafe "sass/values.h" sass_make_map
@@ -201,6 +202,15 @@
 foreign import ccall unsafe "sass/values.h" sass_list_set_separator
     :: Ptr SassValue
     -> CInt -- ^ 'SassSeparator'
+    -> IO ()
+
+foreign import ccall unsafe "sass/values.h" sass_list_get_is_bracketed
+    :: Ptr SassValue
+    -> IO Bool
+
+foreign import ccall unsafe "sass/values.h" sass_list_set_is_bracketed
+    :: Ptr SassValue
+    -> Bool
     -> IO ()
 
 foreign import ccall unsafe "sass/values.h" sass_list_get_value
diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,10 @@
 # Change Log
 All notable changes to this project will be documented in this file.
 
+## [0.1.7.0] - 2018-03-24
+### Changed
+- Update to Libsass 3.5.2
+
 ## [0.1.6.1] - 2017-08-06
 ### Fixed
 - Build process (`Stack.hs`) works with Cabal 1.X and Cabal 2.X
@@ -74,6 +78,7 @@
 - Bindings to Libsass C API
 - Basic tests
 
+[0.1.7.0]: https://github.com/jakubfijalkowski/hlibsass/compare/v0.1.6.1...v0.1.7.0
 [0.1.6.1]: https://github.com/jakubfijalkowski/hlibsass/compare/v0.1.6.0...v0.1.6.1
 [0.1.6.0]: https://github.com/jakubfijalkowski/hlibsass/compare/v0.1.5.2...v0.1.6.0
 [0.1.5.2]: https://github.com/jakubfijalkowski/hlibsass/compare/v0.1.5.0...v0.1.5.2
diff --git a/Setup.hs b/Setup.hs
--- a/Setup.hs
+++ b/Setup.hs
@@ -16,7 +16,6 @@
 import           Distribution.System
 import           System.Directory                   (getCurrentDirectory)
 
-#ifdef MIN_VERSION_Cabal
 #if MIN_VERSION_Cabal(2, 0, 0)
 import           Distribution.Version               (mkVersion)
 #else
@@ -26,7 +25,6 @@
 mkFlagName :: String -> FlagName
 mkFlagName = FlagName
 #endif
-#endif
 
 main = defaultMainWithHooks hooksFix
     where
@@ -132,7 +130,14 @@
     writeFile "libsass/VERSION" ver
     return emptyHookedBuildInfo
 
+#if MIN_VERSION_Cabal(2, 2, 0)
 getCabalFlag :: String -> ConfigFlags -> Bool
+getCabalFlag name flags = fromMaybe False (lookupFlagAssignment (mkFlagName name') allFlags)
+    where allFlags = configConfigurationsFlags flags
+          name' = map toLower name
+#else
+getCabalFlag :: String -> ConfigFlags -> Bool
 getCabalFlag name flags = fromMaybe False (lookup (mkFlagName name') allFlags)
     where allFlags = configConfigurationsFlags flags
           name' = map toLower name
+#endif
diff --git a/hlibsass.cabal b/hlibsass.cabal
--- a/hlibsass.cabal
+++ b/hlibsass.cabal
@@ -1,5 +1,5 @@
 name:                hlibsass
-version:             0.1.6.1
+version:             0.1.7.0
 license:             MIT
 license-file:        LICENSE
 author:              Jakub Fijałkowski <fiolek94@gmail.com>
diff --git a/libsass/Makefile b/libsass/Makefile
--- a/libsass/Makefile
+++ b/libsass/Makefile
@@ -15,10 +15,14 @@
 CFLAGS   ?= -Wall
 CXXFLAGS ?= -Wall
 LDFLAGS  ?= -Wall
-ifneq "$(COVERAGE)" "yes"
+ifeq "x$(COVERAGE)" "x"
   CFLAGS   += -O2
   CXXFLAGS += -O2
   LDFLAGS  += -O2
+else
+  CFLAGS   += -O1 -fno-omit-frame-pointer
+  CXXFLAGS += -O1 -fno-omit-frame-pointer
+  LDFLAGS  += -O1 -fno-omit-frame-pointer
 endif
 LDFLAGS  += -Wl,-undefined,error
 CAT      ?= $(if $(filter $(OS),Windows_NT),type,cat)
@@ -295,7 +299,7 @@
                 install-headers
 
 $(SASSC_BIN): $(BUILD)
-	$(MAKE) -C $(SASS_SASSC_PATH)
+	$(MAKE) -C $(SASS_SASSC_PATH) build-$(BUILD)-dev
 
 sassc: $(SASSC_BIN)
 	$(SASSC_BIN) -v
@@ -305,16 +309,16 @@
 	$(SASSC_BIN) -v
 
 test: $(SASSC_BIN)
-	$(RUBY_BIN) $(SASS_SPEC_PATH)/sass-spec.rb -V 3.4 -c $(SASSC_BIN) --impl libsass $(LOG_FLAGS) $(SASS_SPEC_PATH)/$(SASS_SPEC_SPEC_DIR)
+	$(RUBY_BIN) $(SASS_SPEC_PATH)/sass-spec.rb -V 3.5 -c $(SASSC_BIN) --impl libsass $(LOG_FLAGS) $(SASS_SPEC_PATH)/$(SASS_SPEC_SPEC_DIR)
 
 test_build: $(SASSC_BIN)
-	$(RUBY_BIN) $(SASS_SPEC_PATH)/sass-spec.rb -V 3.4 -c $(SASSC_BIN) --impl libsass $(LOG_FLAGS) $(SASS_SPEC_PATH)/$(SASS_SPEC_SPEC_DIR)
+	$(RUBY_BIN) $(SASS_SPEC_PATH)/sass-spec.rb -V 3.5 -c $(SASSC_BIN) --impl libsass $(LOG_FLAGS) $(SASS_SPEC_PATH)/$(SASS_SPEC_SPEC_DIR)
 
 test_full: $(SASSC_BIN)
-	$(RUBY_BIN) $(SASS_SPEC_PATH)/sass-spec.rb -V 3.4 -c $(SASSC_BIN) --impl libsass --run-todo $(LOG_FLAGS) $(SASS_SPEC_PATH)/$(SASS_SPEC_SPEC_DIR)
+	$(RUBY_BIN) $(SASS_SPEC_PATH)/sass-spec.rb -V 3.5 -c $(SASSC_BIN) --impl libsass --run-todo $(LOG_FLAGS) $(SASS_SPEC_PATH)/$(SASS_SPEC_SPEC_DIR)
 
 test_probe: $(SASSC_BIN)
-	$(RUBY_BIN) $(SASS_SPEC_PATH)/sass-spec.rb -V 3.4 -c $(SASSC_BIN) --impl libsass --probe-todo $(LOG_FLAGS) $(SASS_SPEC_PATH)/$(SASS_SPEC_SPEC_DIR)
+	$(RUBY_BIN) $(SASS_SPEC_PATH)/sass-spec.rb -V 3.5 -c $(SASSC_BIN) --impl libsass --probe-todo $(LOG_FLAGS) $(SASS_SPEC_PATH)/$(SASS_SPEC_SPEC_DIR)
 
 clean-objects: lib
 	-$(RM) lib/*.a lib/*.so lib/*.dll lib/*.la
diff --git a/libsass/Makefile.conf b/libsass/Makefile.conf
--- a/libsass/Makefile.conf
+++ b/libsass/Makefile.conf
@@ -13,6 +13,7 @@
 	functions.cpp \
 	color_maps.cpp \
 	environment.cpp \
+	ast_fwd_decl.cpp \
 	bind.cpp \
 	file.cpp \
 	util.cpp \
@@ -40,6 +41,8 @@
 	sass_context.cpp \
 	sass_functions.cpp \
 	sass2scss.cpp \
+	backtrace.cpp \
+	operators.cpp \
 	to_c.cpp \
 	to_value.cpp \
 	source_map.cpp \
diff --git a/libsass/VERSION b/libsass/VERSION
--- a/libsass/VERSION
+++ b/libsass/VERSION
@@ -1,1 +1,1 @@
-3.4.3
+3.5.2
diff --git a/libsass/include/sass/base.h b/libsass/include/sass/base.h
--- a/libsass/include/sass/base.h
+++ b/libsass/include/sass/base.h
@@ -75,9 +75,6 @@
 ADDAPI char* ADDCALL sass_string_quote (const char* str, const char quote_mark);
 ADDAPI char* ADDCALL sass_string_unquote (const char* str);
 
-// Resolve a file via the given include paths in the include char* array
-ADDAPI char* ADDCALL sass_resolve_file (const char* path, const char* incs[]);
-
 // Implemented sass language version
 // Hardcoded version 3.4 for time being
 ADDAPI const char* ADDCALL libsass_version(void);
diff --git a/libsass/include/sass/context.h b/libsass/include/sass/context.h
--- a/libsass/include/sass/context.h
+++ b/libsass/include/sass/context.h
@@ -81,8 +81,6 @@
 ADDAPI const char* ADDCALL sass_option_get_linefeed (struct Sass_Options* options);
 ADDAPI const char* ADDCALL sass_option_get_input_path (struct Sass_Options* options);
 ADDAPI const char* ADDCALL sass_option_get_output_path (struct Sass_Options* options);
-ADDAPI const char* ADDCALL sass_option_get_plugin_path (struct Sass_Options* options);
-ADDAPI const char* ADDCALL sass_option_get_include_path (struct Sass_Options* options);
 ADDAPI const char* ADDCALL sass_option_get_source_map_file (struct Sass_Options* options);
 ADDAPI const char* ADDCALL sass_option_get_source_map_root (struct Sass_Options* options);
 ADDAPI Sass_Importer_List ADDCALL sass_option_get_c_headers (struct Sass_Options* options);
@@ -124,6 +122,10 @@
 ADDAPI const char* ADDCALL sass_context_get_source_map_string (struct Sass_Context* ctx);
 ADDAPI char** ADDCALL sass_context_get_included_files (struct Sass_Context* ctx);
 
+// Getters for options include path array
+ADDAPI size_t ADDCALL sass_option_get_include_path_size(struct Sass_Options* options);
+ADDAPI const char* ADDCALL sass_option_get_include_path(struct Sass_Options* options, size_t i);
+
 // Calculate the size of the stored null terminated array
 ADDAPI size_t ADDCALL sass_context_get_included_files_size (struct Sass_Context* ctx);
 
@@ -143,10 +145,23 @@
 ADDAPI size_t ADDCALL sass_compiler_get_import_stack_size(struct Sass_Compiler* compiler);
 ADDAPI Sass_Import_Entry ADDCALL sass_compiler_get_last_import(struct Sass_Compiler* compiler);
 ADDAPI Sass_Import_Entry ADDCALL sass_compiler_get_import_entry(struct Sass_Compiler* compiler, size_t idx);
+ADDAPI size_t ADDCALL sass_compiler_get_callee_stack_size(struct Sass_Compiler* compiler);
+ADDAPI Sass_Callee_Entry ADDCALL sass_compiler_get_last_callee(struct Sass_Compiler* compiler);
+ADDAPI Sass_Callee_Entry ADDCALL sass_compiler_get_callee_entry(struct Sass_Compiler* compiler, size_t idx);
 
 // Push function for paths (no manipulation support for now)
 ADDAPI void ADDCALL sass_option_push_plugin_path (struct Sass_Options* options, const char* path);
 ADDAPI void ADDCALL sass_option_push_include_path (struct Sass_Options* options, const char* path);
+
+// Resolve a file via the given include paths in the sass option struct
+// find_file looks for the exact file name while find_include does a regular sass include
+ADDAPI char* ADDCALL sass_find_file (const char* path, struct Sass_Options* opt);
+ADDAPI char* ADDCALL sass_find_include (const char* path, struct Sass_Options* opt);
+
+// Resolve a file relative to last import or include paths in the sass option struct
+// find_file looks for the exact file name while find_include does a regular sass include
+ADDAPI char* ADDCALL sass_compiler_find_file (const char* path, struct Sass_Compiler* compiler);
+ADDAPI char* ADDCALL sass_compiler_find_include (const char* path, struct Sass_Compiler* compiler);
 
 #ifdef __cplusplus
 } // __cplusplus defined.
diff --git a/libsass/include/sass/functions.h b/libsass/include/sass/functions.h
--- a/libsass/include/sass/functions.h
+++ b/libsass/include/sass/functions.h
@@ -11,12 +11,18 @@
 
 
 // Forward declaration
+struct Sass_Env;
+struct Sass_Callee;
 struct Sass_Import;
 struct Sass_Options;
 struct Sass_Compiler;
 struct Sass_Importer;
 struct Sass_Function;
 
+// Typedef helpers for callee lists
+typedef struct Sass_Env (*Sass_Env_Frame);
+// Typedef helpers for callee lists
+typedef struct Sass_Callee (*Sass_Callee_Entry);
 // Typedef helpers for import lists
 typedef struct Sass_Import (*Sass_Import_Entry);
 typedef struct Sass_Import* (*Sass_Import_List);
@@ -34,11 +40,18 @@
 typedef union Sass_Value* (*Sass_Function_Fn)
   (const union Sass_Value*, Sass_Function_Entry cb, struct Sass_Compiler* compiler);
 
+// Type of function calls
+enum Sass_Callee_Type {
+  SASS_CALLEE_MIXIN,
+  SASS_CALLEE_FUNCTION,
+  SASS_CALLEE_C_FUNCTION,
+};
 
 // Creator for sass custom importer return argument list
 ADDAPI Sass_Importer_List ADDCALL sass_make_importer_list (size_t length);
 ADDAPI Sass_Importer_Entry ADDCALL sass_importer_get_list_entry (Sass_Importer_List list, size_t idx);
 ADDAPI void ADDCALL sass_importer_set_list_entry (Sass_Importer_List list, size_t idx, Sass_Importer_Entry entry);
+ADDAPI void ADDCALL sass_delete_importer_list (Sass_Importer_List list);
 
 
 // Creators for custom importer callback (with some additional pointer)
@@ -66,6 +79,22 @@
 ADDAPI void ADDCALL sass_import_set_list_entry (Sass_Import_List list, size_t idx, Sass_Import_Entry entry);
 ADDAPI Sass_Import_Entry ADDCALL sass_import_get_list_entry (Sass_Import_List list, size_t idx);
 
+// Getters for callee entry
+ADDAPI const char* ADDCALL sass_callee_get_name (Sass_Callee_Entry);
+ADDAPI const char* ADDCALL sass_callee_get_path (Sass_Callee_Entry);
+ADDAPI size_t ADDCALL sass_callee_get_line (Sass_Callee_Entry);
+ADDAPI size_t ADDCALL sass_callee_get_column (Sass_Callee_Entry);
+ADDAPI enum Sass_Callee_Type ADDCALL sass_callee_get_type (Sass_Callee_Entry);
+ADDAPI Sass_Env_Frame ADDCALL sass_callee_get_env (Sass_Callee_Entry);
+
+// Getters and Setters for environments (lexical, local and global)
+ADDAPI union Sass_Value* ADDCALL sass_env_get_lexical (Sass_Env_Frame, const char*);
+ADDAPI void ADDCALL sass_env_set_lexical (Sass_Env_Frame, const char*, union Sass_Value*);
+ADDAPI union Sass_Value* ADDCALL sass_env_get_local (Sass_Env_Frame, const char*);
+ADDAPI void ADDCALL sass_env_set_local (Sass_Env_Frame, const char*, union Sass_Value*);
+ADDAPI union Sass_Value* ADDCALL sass_env_get_global (Sass_Env_Frame, const char*);
+ADDAPI void ADDCALL sass_env_set_global (Sass_Env_Frame, const char*, union Sass_Value*);
+
 // Getters for import entry
 ADDAPI const char* ADDCALL sass_import_get_imp_path (Sass_Import_Entry);
 ADDAPI const char* ADDCALL sass_import_get_abs_path (Sass_Import_Entry);
@@ -90,6 +119,8 @@
 // Creators for sass function list and function descriptors
 ADDAPI Sass_Function_List ADDCALL sass_make_function_list (size_t length);
 ADDAPI Sass_Function_Entry ADDCALL sass_make_function (const char* signature, Sass_Function_Fn cb, void* cookie);
+ADDAPI void ADDCALL sass_delete_function (Sass_Function_Entry entry);
+ADDAPI void ADDCALL sass_delete_function_list (Sass_Function_List list);
 
 // Setters and getters for callbacks on function lists
 ADDAPI Sass_Function_Entry ADDCALL sass_function_get_list_entry(Sass_Function_List list, size_t pos);
diff --git a/libsass/include/sass/values.h b/libsass/include/sass/values.h
--- a/libsass/include/sass/values.h
+++ b/libsass/include/sass/values.h
@@ -50,7 +50,7 @@
 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);
+ADDAPI union Sass_Value* ADDCALL sass_make_list    (size_t len, enum Sass_Separator sep, bool is_bracketed);
 ADDAPI union Sass_Value* ADDCALL sass_make_map     (size_t len);
 ADDAPI union Sass_Value* ADDCALL sass_make_error   (const char* msg);
 ADDAPI union Sass_Value* ADDCALL sass_make_warning (const char* msg);
@@ -116,6 +116,8 @@
 // Getters and setters for Sass_List
 ADDAPI enum Sass_Separator ADDCALL sass_list_get_separator (const union Sass_Value* v);
 ADDAPI void ADDCALL sass_list_set_separator (union Sass_Value* v, enum Sass_Separator value);
+ADDAPI bool ADDCALL sass_list_get_is_bracketed (const union Sass_Value* v);
+ADDAPI void ADDCALL sass_list_set_is_bracketed (union Sass_Value* v, bool value);
 // Getters and setters for Sass_List values
 ADDAPI union Sass_Value* ADDCALL sass_list_get_value (const union Sass_Value* v, size_t i);
 ADDAPI void ADDCALL sass_list_set_value (union Sass_Value* v, size_t i, union Sass_Value* value);
diff --git a/libsass/include/sass/version.h b/libsass/include/sass/version.h
--- a/libsass/include/sass/version.h
+++ b/libsass/include/sass/version.h
@@ -6,7 +6,7 @@
 #endif
 
 #ifndef LIBSASS_LANGUAGE_VERSION
-#define LIBSASS_LANGUAGE_VERSION "3.4"
+#define LIBSASS_LANGUAGE_VERSION "3.5"
 #endif
 
 #endif
diff --git a/libsass/include/sass/version.h.in b/libsass/include/sass/version.h.in
--- a/libsass/include/sass/version.h.in
+++ b/libsass/include/sass/version.h.in
@@ -6,7 +6,7 @@
 #endif
 
 #ifndef LIBSASS_LANGUAGE_VERSION
-#define LIBSASS_LANGUAGE_VERSION "3.4"
+#define LIBSASS_LANGUAGE_VERSION "3.5"
 #endif
 
 #endif
diff --git a/libsass/include/sass2scss.h b/libsass/include/sass2scss.h
--- a/libsass/include/sass2scss.h
+++ b/libsass/include/sass2scss.h
@@ -37,7 +37,7 @@
 #ifndef SASS2SCSS_VERSION
 // Hardcode once the file is copied from
 // https://github.com/mgreter/sass2scss
-#define SASS2SCSS_VERSION "1.1.0"
+#define SASS2SCSS_VERSION "1.1.1"
 #endif
 
 // add namespace for c++
diff --git a/libsass/src/GNUmakefile.am b/libsass/src/GNUmakefile.am
--- a/libsass/src/GNUmakefile.am
+++ b/libsass/src/GNUmakefile.am
@@ -34,7 +34,7 @@
 
 libsass_la_SOURCES = ${CSOURCES} ${SOURCES}
 
-libsass_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined -version-info 0:9:0
+libsass_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined -version-info 1:0:0
 
 if ENABLE_TESTS
 if ENABLE_COVERAGE
diff --git a/libsass/src/ast.cpp b/libsass/src/ast.cpp
--- a/libsass/src/ast.cpp
+++ b/libsass/src/ast.cpp
@@ -2,2450 +2,2225 @@
 #include "ast.hpp"
 #include "context.hpp"
 #include "node.hpp"
-#include "extend.hpp"
-#include "emitter.hpp"
-#include "color_maps.hpp"
-#include "ast_fwd_decl.hpp"
-#include <set>
-#include <iomanip>
-#include <iostream>
-#include <algorithm>
-#include <functional>
-#include <cctype>
-#include <locale>
-
-namespace Sass {
-
-  static Null sass_null(ParserState("null"));
-
-  bool Supports_Operator::needs_parens(Supports_Condition_Obj cond) const {
-    if (Supports_Operator_Obj op = SASS_MEMORY_CAST(Supports_Operator, cond)) {
-      return op->operand() != operand();
-    }
-    return SASS_MEMORY_CAST(Supports_Negation, cond) != NULL;
-  }
-
-  bool Supports_Negation::needs_parens(Supports_Condition_Obj cond) const {
-    return SASS_MEMORY_CAST(Supports_Negation, cond) ||
-           SASS_MEMORY_CAST(Supports_Operator, cond);
-  }
-
-  size_t HashExpression::operator() (Expression_Obj ex) const {
-    return ex ? ex->hash() : 0;
-  }
-
-  size_t HashSimpleSelector::operator() (Simple_Selector_Obj ex) const {
-    return ex ? ex->hash() : 0;
-  }
-
-
-  bool CompareExpression::operator()(const Expression_Obj& lhs, const Expression_Obj& rhs) const {
-    return lhs && rhs && lhs->eq(*rhs);
-  }
-
-  bool CompareSimpleSelector::operator()(Simple_Selector_Obj lhs, Simple_Selector_Obj rhs) const {
-    return &lhs && &rhs && *lhs == *rhs;
-  }
-
-  std::string & str_ltrim(std::string & str)
-  {
-    auto it2 =  std::find_if( str.begin() , str.end() , [](char ch){ return !std::isspace<char>(ch , std::locale::classic() ) ; } );
-    str.erase( str.begin() , it2);
-    return str;
-  }
-
-  std::string & str_rtrim(std::string & str)
-  {
-    auto it1 =  std::find_if( str.rbegin() , str.rend() , [](char ch){ return !std::isspace<char>(ch , std::locale::classic() ) ; } );
-    str.erase( it1.base() , str.end() );
-    return str;
-  }
-
-  void String_Constant::rtrim()
-  {
-    value_ = str_rtrim(value_);
-  }
-  void String_Constant::ltrim()
-  {
-    value_ = str_ltrim(value_);
-  }
-  void String_Constant::trim()
-  {
-    rtrim();
-    ltrim();
-  }
-
-  void String_Schema::rtrim()
-  {
-    if (!empty()) {
-      if (String_Ptr str = SASS_MEMORY_CAST(String, last())) str->rtrim();
-    }
-  }
-  void String_Schema::ltrim()
-  {
-    if (!empty()) {
-      if (String_Ptr str = SASS_MEMORY_CAST(String, first())) str->ltrim();
-    }
-  }
-  void String_Schema::trim()
-  {
-    rtrim();
-    ltrim();
-  }
-
-  void Argument::set_delayed(bool delayed)
-  {
-    if (value_) value_->set_delayed(delayed);
-    is_delayed(delayed);
-  }
-
-  void Arguments::set_delayed(bool delayed)
-  {
-    for (Argument_Obj arg : elements()) {
-      if (arg) arg->set_delayed(delayed);
-    }
-    is_delayed(delayed);
-  }
-
-
-  bool At_Root_Query::exclude(std::string str)
-  {
-    bool with = feature() && unquote(feature()->to_string()).compare("with") == 0;
-    List_Ptr l = static_cast<List_Ptr>(&value());
-    std::string v;
-
-    if (with)
-    {
-      if (!l || l->length() == 0) return str.compare("rule") != 0;
-      for (size_t i = 0, L = l->length(); i < L; ++i)
-      {
-        v = unquote((*l)[i]->to_string());
-        if (v.compare("all") == 0 || v == str) return false;
-      }
-      return true;
-    }
-    else
-    {
-      if (!l || !l->length()) return str.compare("rule") == 0;
-      for (size_t i = 0, L = l->length(); i < L; ++i)
-      {
-        v = unquote((*l)[i]->to_string());
-        if (v.compare("all") == 0 || v == str) return true;
-      }
-      return false;
-    }
-  }
-
-  void AST_Node::update_pstate(const ParserState& pstate)
-  {
-    pstate_.offset += pstate - pstate_ + pstate.offset;
-  }
-
-  void AST_Node::set_pstate_offset(const Offset& offset)
-  {
-    pstate_.offset = offset;
-  }
-
-  inline bool is_ns_eq(const std::string& l, const std::string& r)
-  {
-    if (l.empty() && r.empty()) return true;
-    else if (l.empty() && r == "*") return true;
-    else if (r.empty() && l == "*") return true;
-    else return l == r;
-  }
-
-
-
-  bool Compound_Selector::operator< (const Compound_Selector& rhs) const
-  {
-    size_t L = std::min(length(), rhs.length());
-    for (size_t i = 0; i < L; ++i)
-    {
-      Simple_Selector_Obj l = (*this)[i];
-      Simple_Selector_Obj r = rhs[i];
-      if (!l && !r) return false;
-      else if (!r) return false;
-      else if (!l) return true;
-      else if (*l != *r)
-      { return *l < *r; }
-    }
-    // just compare the length now
-    return length() < rhs.length();
-  }
-
-  bool Compound_Selector::has_parent_ref()
-  {
-    for (Simple_Selector_Obj s : *this) {
-      if (s && s->has_parent_ref()) return true;
-    }
-    return false;
-  }
-
-  bool Compound_Selector::has_real_parent_ref()
-  {
-    for (Simple_Selector_Obj s : *this) {
-      if (s && s->has_real_parent_ref()) return true;
-    }
-    return false;
-  }
-
-  bool Complex_Selector::has_parent_ref()
-  {
-    return (head() && head()->has_parent_ref()) ||
-           (tail() && tail()->has_parent_ref());
-  }
-
-  bool Complex_Selector::has_real_parent_ref()
-  {
-    return (head() && head()->has_real_parent_ref()) ||
-           (tail() && tail()->has_real_parent_ref());
-  }
-
-  bool Complex_Selector::operator< (const Complex_Selector& rhs) const
-  {
-    // const iterators for tails
-    Complex_Selector_Ptr_Const l = this;
-    Complex_Selector_Ptr_Const r = &rhs;
-    Compound_Selector_Ptr l_h = l ? &l->head() : 0;
-    Compound_Selector_Ptr r_h = r ? &r->head() : 0;
-    // process all tails
-    while (true)
-    {
-      // skip empty ancestor first
-      if (l && l->is_empty_ancestor())
-      {
-        l = &l->tail();
-        l_h = l ? &l->head() : 0;
-        continue;
-      }
-      // skip empty ancestor first
-      if (r && r->is_empty_ancestor())
-      {
-        r = &r->tail();
-        r_h = r ? &r->head() : 0;
-        continue;
-      }
-      // check for valid selectors
-      if (!l) return !!r;
-      if (!r) return false;
-      // both are null
-      else if (!l_h && !r_h)
-      {
-        // check combinator after heads
-        if (l->combinator() != r->combinator())
-        { return l->combinator() < r->combinator(); }
-        // advance to next tails
-        l = &l->tail();
-        r = &r->tail();
-        // fetch the next headers
-        l_h = l ? &l->head() : 0;
-        r_h = r ? &r->head() : 0;
-      }
-      // one side is null
-      else if (!r_h) return true;
-      else if (!l_h) return false;
-      // heads ok and equal
-      else if (*l_h == *r_h)
-      {
-        // check combinator after heads
-        if (l->combinator() != r->combinator())
-        { return l->combinator() < r->combinator(); }
-        // advance to next tails
-        l = &l->tail();
-        r = &r->tail();
-        // fetch the next headers
-        l_h = l ? &l->head() : 0;
-        r_h = r ? &r->head() : 0;
-      }
-      // heads are not equal
-      else return *l_h < *r_h;
-    }
-    return true;
-  }
-
-  bool Complex_Selector::operator== (const Complex_Selector& rhs) const
-  {
-    // const iterators for tails
-    Complex_Selector_Ptr_Const l = this;
-    Complex_Selector_Ptr_Const r = &rhs;
-    Compound_Selector_Ptr l_h = l ? &l->head() : 0;
-    Compound_Selector_Ptr r_h = r ? &r->head() : 0;
-    // process all tails
-    while (true)
-    {
-      // skip empty ancestor first
-      if (l && l->is_empty_ancestor())
-      {
-        l = &l->tail();
-        l_h = l ? &l->head() : 0;
-        continue;
-      }
-      // skip empty ancestor first
-      if (r && r->is_empty_ancestor())
-      {
-        r = &r->tail();
-        r_h = r ? &r->head() : 0;
-        continue;
-      }
-      // check the pointers
-      if (!r) return !l;
-      if (!l) return !r;
-      // both are null
-      if (!l_h && !r_h)
-      {
-        // check combinator after heads
-        if (l->combinator() != r->combinator())
-        { return l->combinator() < r->combinator(); }
-        // advance to next tails
-        l = &l->tail();
-        r = &r->tail();
-        // fetch the next heads
-        l_h = l ? &l->head() : 0;
-        r_h = r ? &r->head() : 0;
-      }
-      // equals if other head is empty
-      else if ((!l_h && !r_h) ||
-               (!l_h && r_h->empty()) ||
-               (!r_h && l_h->empty()) ||
-               (*l_h == *r_h))
-      {
-        // check combinator after heads
-        if (l->combinator() != r->combinator())
-        { return l->combinator() == r->combinator(); }
-        // advance to next tails
-        l = &l->tail();
-        r = &r->tail();
-        // fetch the next heads
-        l_h = l ? &l->head() : 0;
-        r_h = r ? &r->head() : 0;
-      }
-      // abort
-      else break;
-    }
-    // unreachable
-    return false;
-  }
-
-  Compound_Selector_Ptr Compound_Selector::unify_with(Compound_Selector_Ptr rhs, Context& ctx)
-  {
-    if (empty()) return rhs;
-    Compound_Selector_Obj unified = SASS_MEMORY_COPY(rhs);
-    for (size_t i = 0, L = length(); i < L; ++i)
-    {
-      if (unified.isNull()) break;
-      unified = at(i)->unify_with(&unified, ctx);
-    }
-    return unified.detach();
-  }
-
-  bool Selector::operator== (const Selector& rhs) const
-  {
-    if (Selector_List_Ptr_Const sl = dynamic_cast<Selector_List_Ptr_Const>(this)) return *sl == rhs;
-    if (Simple_Selector_Ptr_Const sp = dynamic_cast<Simple_Selector_Ptr_Const>(this)) return *sp == rhs;
-    throw std::runtime_error("invalid selector base classes to compare");
-    return false;
-  }
-
-  bool Selector::operator< (const Selector& rhs) const
-  {
-    if (Selector_List_Ptr_Const sl = dynamic_cast<Selector_List_Ptr_Const>(this)) return *sl < rhs;
-    if (Simple_Selector_Ptr_Const sp = dynamic_cast<Simple_Selector_Ptr_Const>(this)) return *sp < rhs;
-    throw std::runtime_error("invalid selector base classes to compare");
-    return false;
-  }
-
-  bool Simple_Selector::operator== (const Selector& rhs) const
-  {
-    if (Simple_Selector_Ptr_Const sp = dynamic_cast<Simple_Selector_Ptr_Const>(&rhs)) return *this == *sp;
-    return false;
-  }
-
-  bool Simple_Selector::operator< (const Selector& rhs) const
-  {
-    if (Simple_Selector_Ptr_Const sp = dynamic_cast<Simple_Selector_Ptr_Const>(&rhs)) return *this < *sp;
-    return false;
-  }
-
-  bool Simple_Selector::operator== (const Simple_Selector& rhs) const
-  {
-    Simple_Type type = simple_type();
-    // dynamic cast is a bottleneck - use concrete type as types are final
-    if (type == PSEUDO_SEL /* Pseudo_Selector_Ptr_Const lp = dynamic_cast<Pseudo_Selector_Ptr_Const>(this) */) {
-      return *static_cast<Pseudo_Selector_Ptr_Const>(this) == rhs;
-    }
-    else if (type == WRAPPED_SEL /* Wrapped_Selector_Ptr_Const lw = dynamic_cast<Wrapped_Selector_Ptr_Const>(this) */) {
-      return *static_cast<Wrapped_Selector_Ptr_Const>(this) == rhs;
-    }
-    else if (type == ATTR_SEL /* Attribute_Selector_Ptr_Const la = dynamic_cast<Attribute_Selector_Ptr_Const>(this) */) {
-      return *static_cast<Attribute_Selector_Ptr_Const>(this) == rhs;
-    }
-    else if (name_ == rhs.name_)
-    { return is_ns_eq(ns_, rhs.ns_); }
-    else return false;
-  }
-
-  bool Simple_Selector::operator< (const Simple_Selector& rhs) const
-  {
-    Simple_Type type = simple_type();
-    // dynamic cast is a bottleneck - use concrete type as types are final
-    if (type == PSEUDO_SEL /* Pseudo_Selector_Ptr_Const lp = dynamic_cast<Pseudo_Selector_Ptr_Const>(this) */) {
-      return *static_cast<Pseudo_Selector_Ptr_Const>(this) < rhs;
-    }
-    else if (type == WRAPPED_SEL /* Wrapped_Selector_Ptr_Const lw = dynamic_cast<Wrapped_Selector_Ptr_Const>(this) */) {
-      return *static_cast<Wrapped_Selector_Ptr_Const>(this) < rhs;
-    }
-    else if (type == ATTR_SEL /* Attribute_Selector_Ptr_Const la = dynamic_cast<Attribute_Selector_Ptr_Const>(this) */) {
-      return *static_cast<Attribute_Selector_Ptr_Const>(this) < rhs;
-    }
-    if (is_ns_eq(ns_, rhs.ns_))
-    { return name_ < rhs.name_; }
-    return ns_ < rhs.ns_;
-  }
-
-  bool Selector_List::operator== (const Selector& rhs) const
-  {
-    // solve the double dispatch problem by using RTTI information via dynamic cast
-    if (Selector_List_Ptr_Const ls = dynamic_cast<Selector_List_Ptr_Const>(&rhs)) { return *this == *ls; }
-    else if (Complex_Selector_Ptr_Const ls = dynamic_cast<Complex_Selector_Ptr_Const>(&rhs)) { return *this == *ls; }
-    else if (Compound_Selector_Ptr_Const ls = dynamic_cast<Compound_Selector_Ptr_Const>(&rhs)) { return *this == *ls; }
-    // no compare method
-    return this == &rhs;
-  }
-
-  // Selector lists can be compared to comma lists
-  bool Selector_List::operator==(const Expression& rhs) const
-  {
-    // solve the double dispatch problem by using RTTI information via dynamic cast
-    if (List_Ptr_Const ls = dynamic_cast<List_Ptr_Const>(&rhs)) { return *this == *ls; }
-    if (Selector_Ptr_Const ls = dynamic_cast<Selector_Ptr_Const>(&rhs)) { return *this == *ls; }
-    // compare invalid (maybe we should error?)
-    return false;
-  }
-
-  bool Selector_List::operator== (const Selector_List& rhs) const
-  {
-    // for array access
-    size_t i = 0, n = 0;
-    size_t iL = length();
-    size_t nL = rhs.length();
-    // create temporary vectors and sort them
-    std::vector<Complex_Selector_Obj> l_lst = this->elements();
-    std::vector<Complex_Selector_Obj> r_lst = rhs.elements();
-    std::sort(l_lst.begin(), l_lst.end(), cmp_complex_selector());
-    std::sort(r_lst.begin(), r_lst.end(), cmp_complex_selector());
-    // process loop
-    while (true)
-    {
-      // first check for valid index
-      if (i == iL) return iL == nL;
-      else if (n == nL) return iL == nL;
-      // the access the vector items
-      Complex_Selector_Obj l = l_lst[i];
-      Complex_Selector_Obj r = r_lst[n];
-      // skip nulls
-      if (!l) ++i;
-      else if (!r) ++n;
-      // do the check
-      else if (*l != *r)
-      { return false; }
-      // advance
-      ++i; ++n;
-    }
-    // no mismatch
-    return true;
-  }
-
-  bool Selector_List::operator< (const Selector& rhs) const
-  {
-    if (Selector_List_Ptr_Const sp = dynamic_cast<Selector_List_Ptr_Const>(&rhs)) return *this < *sp;
-    return false;
-  }
-
-  bool Selector_List::operator< (const Selector_List& rhs) const
-  {
-    if (this->length() != rhs.length()) return false;
-    for (size_t i = 0; i < rhs.length(); i ++) {
-      if (!(*at(i) < *rhs.at(i))) return false;
-    }
-    return true;
-  }
-
-  Compound_Selector_Ptr Simple_Selector::unify_with(Compound_Selector_Ptr rhs, Context& ctx)
-  {
-    for (size_t i = 0, L = rhs->length(); i < L; ++i)
-    { if (to_string(ctx.c_options) == rhs->at(i)->to_string(ctx.c_options)) return rhs; }
-
-    // check for pseudo elements because they are always last
-    size_t i, L;
-    bool found = false;
-    if (typeid(*this) == typeid(Pseudo_Selector) || typeid(*this) == typeid(Wrapped_Selector))
-    {
-      for (i = 0, L = rhs->length(); i < L; ++i)
-      {
-        if ((SASS_MEMORY_CAST(Pseudo_Selector, (*rhs)[i]) || SASS_MEMORY_CAST(Wrapped_Selector, (*rhs)[i])) && (*rhs)[L-1]->is_pseudo_element())
-        { found = true; break; }
-      }
-    }
-    else
-    {
-      for (i = 0, L = rhs->length(); i < L; ++i)
-      {
-        if (SASS_MEMORY_CAST(Pseudo_Selector, (*rhs)[i]) || SASS_MEMORY_CAST(Wrapped_Selector, (*rhs)[i]))
-        { found = true; break; }
-      }
-    }
-    if (!found)
-    {
-      rhs->append(this);
-      return rhs;
-    }
-    rhs->elements().insert(rhs->elements().begin() + i, this);
-    return rhs;
-  }
-
-  Simple_Selector_Ptr Element_Selector::unify_with(Simple_Selector_Ptr rhs, Context& ctx)
-  {
-    // check if ns can be extended
-    // true for no ns or universal
-    if (has_universal_ns())
-    {
-      // but dont extend with universal
-      // true for valid ns and universal
-      if (!rhs->is_universal_ns())
-      {
-        // overwrite the name if star is given as name
-        if (this->name() == "*") { this->name(rhs->name()); }
-        // now overwrite the namespace name and flag
-        this->ns(rhs->ns()); this->has_ns(rhs->has_ns());
-        // return copy
-        return this;
-      }
-    }
-    // namespace may changed, check the name now
-    // overwrite star (but not with another star)
-    if (name() == "*" && rhs->name() != "*")
-    {
-      // simply set the new name
-      this->name(rhs->name());
-      // return copy
-      return this;
-    }
-    // return original
-    return this;
-  }
-
-  Compound_Selector_Ptr Element_Selector::unify_with(Compound_Selector_Ptr rhs, Context& ctx)
-  {
-    // TODO: handle namespaces
-
-    // if the rhs is empty, just return a copy of this
-    if (rhs->length() == 0) {
-      rhs->append(this);
-      return rhs;
-    }
-
-    Simple_Selector_Ptr rhs_0 = &rhs->at(0);
-    // otherwise, this is a tag name
-    if (name() == "*")
-    {
-      if (typeid(*rhs_0) == typeid(Element_Selector))
-      {
-        // if rhs is universal, just return this tagname + rhs's qualifiers
-        Element_Selector_Ptr ts = SASS_MEMORY_CAST_PTR(Element_Selector, rhs_0);
-        rhs->at(0) = this->unify_with(ts, ctx);
-        return rhs;
-      }
-      else if (SASS_MEMORY_CAST_PTR(Class_Selector, rhs_0) || SASS_MEMORY_CAST_PTR(Id_Selector, rhs_0)) {
-        // qualifier is `.class`, so we can prefix with `ns|*.class`
-        if (has_ns() && !rhs_0->has_ns()) {
-          if (ns() != "*") rhs->elements().insert(rhs->begin(), this);
-        }
-        return rhs;
-      }
-
-
-      return rhs;
-    }
-
-    if (typeid(*rhs_0) == typeid(Element_Selector))
-    {
-      // if rhs is universal, just return this tagname + rhs's qualifiers
-      if (rhs_0->name() != "*" && rhs_0->ns() != "*" && rhs_0->name() != name()) return 0;
-      // otherwise create new compound and unify first simple selector
-      rhs->at(0) = this->unify_with(rhs_0, ctx);
-      return rhs;
-
-    }
-    // else it's a tag name and a bunch of qualifiers -- just append them
-    if (name() != "*") rhs->elements().insert(rhs->begin(), this);
-    return rhs;
-  }
-
-  Compound_Selector_Ptr Class_Selector::unify_with(Compound_Selector_Ptr rhs, Context& ctx)
-  {
-    rhs->has_line_break(has_line_break());
-    return Simple_Selector::unify_with(rhs, ctx);
-  }
-
-  Compound_Selector_Ptr Id_Selector::unify_with(Compound_Selector_Ptr rhs, Context& ctx)
-  {
-    for (size_t i = 0, L = rhs->length(); i < L; ++i)
-    {
-      if (Id_Selector_Ptr sel = SASS_MEMORY_CAST(Id_Selector, rhs->at(i))) {
-        if (sel->name() != name()) return 0;
-      }
-    }
-    rhs->has_line_break(has_line_break());
-    return Simple_Selector::unify_with(rhs, ctx);
-  }
-
-  Compound_Selector_Ptr Pseudo_Selector::unify_with(Compound_Selector_Ptr rhs, Context& ctx)
-  {
-    if (is_pseudo_element())
-    {
-      for (size_t i = 0, L = rhs->length(); i < L; ++i)
-      {
-        if (Pseudo_Selector_Ptr sel = SASS_MEMORY_CAST(Pseudo_Selector, rhs->at(i))) {
-          if (sel->is_pseudo_element() && sel->name() != name()) return 0;
-        }
-      }
-    }
-    return Simple_Selector::unify_with(rhs, ctx);
-  }
-
-  bool Attribute_Selector::operator< (const Attribute_Selector& rhs) const
-  {
-    if (is_ns_eq(ns(), rhs.ns())) {
-      if (name() == rhs.name()) {
-        if (matcher() == rhs.matcher()) {
-          bool no_lhs_val = value().isNull();
-          bool no_rhs_val = rhs.value().isNull();
-          if (no_lhs_val && no_rhs_val) {
-            return true;
-          }
-          if (!no_lhs_val && !no_rhs_val) {
-            return *value() < *rhs.value();
-          }
-        } else { return matcher() < rhs.matcher(); }
-      } else { return name() < rhs.name(); }
-    }
-    return false;
-  }
-
-  bool Attribute_Selector::operator< (const Simple_Selector& rhs) const
-  {
-    if (Attribute_Selector_Ptr_Const w = dynamic_cast<Attribute_Selector_Ptr_Const>(&rhs))
-    {
-      return *this < *w;
-    }
-    if (is_ns_eq(ns(), rhs.ns()))
-    { return name() < rhs.name(); }
-    return ns() < rhs.ns();
-  }
-
-  bool Attribute_Selector::operator== (const Attribute_Selector& rhs) const
-  {
-    // get optional value state
-    bool no_lhs_val = value().isNull();
-    bool no_rhs_val = rhs.value().isNull();
-    // both are null, therefore equal
-    if (no_lhs_val && no_rhs_val) {
-      return (name() == rhs.name())
-        && (matcher() == rhs.matcher())
-        && (is_ns_eq(ns(), rhs.ns()));
-    }
-    // both are defined, evaluate
-    if (no_lhs_val == no_rhs_val) {
-      return (name() == rhs.name())
-        && (matcher() == rhs.matcher())
-        && (is_ns_eq(ns(), rhs.ns()))
-        && (*value() == *rhs.value());
-    }
-    // not equal
-    return false;
-
-  }
-
-  bool Attribute_Selector::operator== (const Simple_Selector& rhs) const
-  {
-    if (Attribute_Selector_Ptr_Const w = dynamic_cast<Attribute_Selector_Ptr_Const>(&rhs))
-    {
-      return *this == *w;
-    }
-    if (is_ns_eq(ns(), rhs.ns()))
-    { return name() == rhs.name(); }
-    return ns() == rhs.ns();
-  }
-
-  bool Pseudo_Selector::operator== (const Pseudo_Selector& rhs) const
-  {
-    if (is_ns_eq(ns(), rhs.ns()) && name() == rhs.name())
-    {
-      String_Obj lhs_ex = expression();
-      String_Obj rhs_ex = rhs.expression();
-      if (rhs_ex && lhs_ex) return *lhs_ex == *rhs_ex;
-      else return lhs_ex == rhs_ex;
-    }
-    else return false;
-  }
-
-  bool Pseudo_Selector::operator== (const Simple_Selector& rhs) const
-  {
-    if (Pseudo_Selector_Ptr_Const w = dynamic_cast<Pseudo_Selector_Ptr_Const>(&rhs))
-    {
-      return *this == *w;
-    }
-    if (is_ns_eq(ns(), rhs.ns()))
-    { return name() == rhs.name(); }
-    return ns() == rhs.ns();
-  }
-
-  bool Pseudo_Selector::operator< (const Pseudo_Selector& rhs) const
-  {
-    if (is_ns_eq(ns(), rhs.ns()) && name() == rhs.name())
-    {
-      String_Obj lhs_ex = expression();
-      String_Obj rhs_ex = rhs.expression();
-      if (rhs_ex && lhs_ex) return *lhs_ex < *rhs_ex;
-      else return lhs_ex < rhs_ex;
-    }
-    if (is_ns_eq(ns(), rhs.ns()))
-    { return name() < rhs.name(); }
-    return ns() < rhs.ns();
-  }
-
-  bool Pseudo_Selector::operator< (const Simple_Selector& rhs) const
-  {
-    if (Pseudo_Selector_Ptr_Const w = dynamic_cast<Pseudo_Selector_Ptr_Const>(&rhs))
-    {
-      return *this < *w;
-    }
-    if (is_ns_eq(ns(), rhs.ns()))
-    { return name() < rhs.name(); }
-    return ns() < rhs.ns();
-  }
-
-  bool Wrapped_Selector::operator== (const Wrapped_Selector& rhs) const
-  {
-    if (is_ns_eq(ns(), rhs.ns()) && name() == rhs.name())
-    { return *(selector()) == *(rhs.selector()); }
-    else return false;
-  }
-
-  bool Wrapped_Selector::operator== (const Simple_Selector& rhs) const
-  {
-    if (Wrapped_Selector_Ptr_Const w = dynamic_cast<Wrapped_Selector_Ptr_Const>(&rhs))
-    {
-      return *this == *w;
-    }
-    if (is_ns_eq(ns(), rhs.ns()))
-    { return name() == rhs.name(); }
-    return ns() == rhs.ns();
-  }
-
-  bool Wrapped_Selector::operator< (const Wrapped_Selector& rhs) const
-  {
-    if (is_ns_eq(ns(), rhs.ns()) && name() == rhs.name())
-    { return *(selector()) < *(rhs.selector()); }
-    if (is_ns_eq(ns(), rhs.ns()))
-    { return name() < rhs.name(); }
-    return ns() < rhs.ns();
-  }
-
-  bool Wrapped_Selector::operator< (const Simple_Selector& rhs) const
-  {
-    if (Wrapped_Selector_Ptr_Const w = dynamic_cast<Wrapped_Selector_Ptr_Const>(&rhs))
-    {
-      return *this < *w;
-    }
-    if (is_ns_eq(ns(), rhs.ns()))
-    { return name() < rhs.name(); }
-    return ns() < rhs.ns();
-  }
-
-  bool Wrapped_Selector::is_superselector_of(Wrapped_Selector_Obj sub)
-  {
-    if (this->name() != sub->name()) return false;
-    if (this->name() == ":current") return false;
-    if (Selector_List_Obj rhs_list = SASS_MEMORY_CAST(Selector_List, sub->selector())) {
-      if (Selector_List_Obj lhs_list = SASS_MEMORY_CAST(Selector_List, selector())) {
-        return lhs_list->is_superselector_of(rhs_list);
-      }
-      error("is_superselector expected a Selector_List", sub->pstate());
-    } else {
-      error("is_superselector expected a Selector_List", sub->pstate());
-    }
-    return false;
-  }
-
-  bool Compound_Selector::is_superselector_of(Selector_List_Obj rhs, std::string wrapped)
-  {
-    for (Complex_Selector_Obj item : rhs->elements()) {
-      if (is_superselector_of(&item, wrapped)) return true;
-    }
-    return false;
-  }
-
-  bool Compound_Selector::is_superselector_of(Complex_Selector_Obj rhs, std::string wrapped)
-  {
-    if (rhs->head()) return is_superselector_of(&rhs->head(), wrapped);
-    return false;
-  }
-
-  bool Compound_Selector::is_superselector_of(Compound_Selector_Obj rhs, std::string wrapping)
-  {
-    Compound_Selector_Ptr lhs = this;
-    Simple_Selector_Ptr lbase = lhs->base();
-    Simple_Selector_Ptr rbase = rhs->base();
-
-    // Check if pseudo-elements are the same between the selectors
-
-    std::set<std::string> lpsuedoset, rpsuedoset;
-    for (size_t i = 0, L = length(); i < L; ++i)
-    {
-      if ((*this)[i]->is_pseudo_element()) {
-        std::string pseudo((*this)[i]->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);
-      }
-    }
-    for (size_t i = 0, L = rhs->length(); i < L; ++i)
-    {
-      if ((*rhs)[i]->is_pseudo_element()) {
-        std::string pseudo((*rhs)[i]->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);
-      }
-    }
-    if (lpsuedoset != rpsuedoset) {
-      return false;
-    }
-
-    std::set<std::string> lset, rset;
-
-    if (lbase && rbase)
-    {
-      if (lbase->to_string() == rbase->to_string()) {
-        for (size_t i = 1, L = length(); i < L; ++i)
-        { lset.insert((*this)[i]->to_string()); }
-        for (size_t i = 1, L = rhs->length(); i < L; ++i)
-        { rset.insert((*rhs)[i]->to_string()); }
-        return includes(rset.begin(), rset.end(), lset.begin(), lset.end());
-      }
-      return false;
-    }
-
-    for (size_t i = 0, iL = length(); i < iL; ++i)
-    {
-      Selector_Obj lhs = &(*this)[i];
-      // very special case for wrapped matches selector
-      if (Wrapped_Selector_Obj wrapped = SASS_MEMORY_CAST(Wrapped_Selector, lhs)) {
-        if (wrapped->name() == ":not") {
-          if (Selector_List_Obj not_list = SASS_MEMORY_CAST(Selector_List, wrapped->selector())) {
-            if (not_list->is_superselector_of(rhs, wrapped->name())) return false;
-          } else {
-            throw std::runtime_error("wrapped not selector is not a list");
-          }
-        }
-        if (wrapped->name() == ":matches" || wrapped->name() == ":-moz-any") {
-          lhs = wrapped->selector();
-          if (Selector_List_Obj list = SASS_MEMORY_CAST(Selector_List, wrapped->selector())) {
-            if (Compound_Selector_Obj comp = SASS_MEMORY_CAST(Compound_Selector, rhs)) {
-              if (!wrapping.empty() && wrapping != wrapped->name()) return false;
-              if (wrapping.empty() || wrapping != wrapped->name()) {;
-                if (list->is_superselector_of(comp, wrapped->name())) return true;
-              }
-            }
-          }
-        }
-        Simple_Selector_Ptr rhs_sel = rhs->elements().size() > i ? &(*rhs)[i] : 0;
-        if (Wrapped_Selector_Ptr wrapped_r = dynamic_cast<Wrapped_Selector_Ptr>(rhs_sel)) {
-          if (wrapped->name() == wrapped_r->name()) {
-          if (wrapped->is_superselector_of(wrapped_r)) {
-             continue;
-             rset.insert(lhs->to_string());
-
-          }}
-        }
-      }
-      // match from here on as strings
-      lset.insert(lhs->to_string());
-    }
-
-    for (size_t n = 0, nL = rhs->length(); n < nL; ++n)
-    {
-      Selector_Obj r = &(*rhs)[n];
-      if (Wrapped_Selector_Obj wrapped = SASS_MEMORY_CAST(Wrapped_Selector, r)) {
-        if (wrapped->name() == ":not") {
-          if (Selector_List_Obj ls = SASS_MEMORY_CAST(Selector_List, wrapped->selector())) {
-            ls->remove_parent_selectors();
-            if (is_superselector_of(ls, wrapped->name())) return false;
-          }
-        }
-        if (wrapped->name() == ":matches" || wrapped->name() == ":-moz-any") {
-          if (!wrapping.empty()) {
-            if (wrapping != wrapped->name()) return false;
-          }
-          if (Selector_List_Obj ls = SASS_MEMORY_CAST(Selector_List, wrapped->selector())) {
-            ls->remove_parent_selectors();
-            return (is_superselector_of(ls, wrapped->name()));
-          }
-        }
-      }
-      rset.insert(r->to_string());
-    }
-
-    //for (auto l : lset) { cerr << "l: " << l << endl; }
-    //for (auto r : rset) { cerr << "r: " << r << endl; }
-
-    if (lset.empty()) return true;
-    // return true if rset contains all the elements of lset
-    return includes(rset.begin(), rset.end(), lset.begin(), lset.end());
-
-  }
-
-  // create complex selector (ancestor of) from compound selector
-  Complex_Selector_Obj Compound_Selector::to_complex()
-  {
-    // create an intermediate complex selector
-    return SASS_MEMORY_NEW(Complex_Selector,
-                           pstate(),
-                           Complex_Selector::ANCESTOR_OF,
-                           this,
-                           0);
-  }
-
-  Selector_List_Ptr Complex_Selector::unify_with(Complex_Selector_Ptr other, Context& ctx)
-  {
-
-    // get last tails (on the right side)
-    Complex_Selector_Obj l_last = this->last();
-    Complex_Selector_Obj r_last = other->last();
-
-    // check valid pointers (assertion)
-    SASS_ASSERT(l_last, "lhs is null");
-    SASS_ASSERT(r_last, "rhs is null");
-
-    // Not sure about this check, but closest way I could check
-    // was to see if this is a ruby 'SimpleSequence' equivalent.
-    // It seems to do the job correctly as some specs react to this
-    if (l_last->combinator() != Combinator::ANCESTOR_OF) return 0;
-    if (r_last->combinator() != Combinator::ANCESTOR_OF ) return 0;
-
-    // get the headers for the last tails
-    Compound_Selector_Obj l_last_head = l_last->head();
-    Compound_Selector_Obj r_last_head = r_last->head();
-
-    // check valid head pointers (assertion)
-    SASS_ASSERT(l_last_head, "lhs head is null");
-    SASS_ASSERT(r_last_head, "rhs head is null");
-
-    // get the unification of the last compound selectors
-    Compound_Selector_Obj unified = r_last_head->unify_with(&l_last_head, ctx);
-
-    // abort if we could not unify heads
-    if (unified == 0) return 0;
-
-    // check for universal (star: `*`) selector
-    bool is_universal = l_last_head->is_universal() ||
-                        r_last_head->is_universal();
-
-    if (is_universal)
-    {
-      // move the head
-      l_last->head(0);
-      r_last->head(unified);
-    }
-
-    // create nodes from both selectors
-    Node lhsNode = complexSelectorToNode(this, ctx);
-    Node rhsNode = complexSelectorToNode(other, ctx);
-
-    // overwrite universal base
-    if (!is_universal)
-    {
-      // create some temporaries to convert to node
-      Complex_Selector_Obj fake = unified->to_complex();
-      Node unified_node = complexSelectorToNode(&fake, ctx);
-      // add to permutate the list?
-      rhsNode.plus(unified_node);
-    }
-
-    // do some magic we inherit from node and extend
-    Node node = Extend::subweave(lhsNode, rhsNode, ctx);
-    Selector_List_Ptr result = SASS_MEMORY_NEW(Selector_List, pstate());
-    NodeDequePtr col = node.collection(); // move from collection to list
-    for (NodeDeque::iterator it = col->begin(), end = col->end(); it != end; it++)
-    { result->append(nodeToComplexSelector(Node::naiveTrim(*it, ctx), ctx)); }
-
-    // only return if list has some entries
-    return result->length() ? result : 0;
-
-  }
-
-  bool Compound_Selector::operator== (const Compound_Selector& rhs) const
-  {
-    // for array access
-    size_t i = 0, n = 0;
-    size_t iL = length();
-    size_t nL = rhs.length();
-    // create temporary vectors and sort them
-    std::vector<Simple_Selector_Obj> l_lst = this->elements();
-    std::vector<Simple_Selector_Obj> r_lst = rhs.elements();
-    std::sort(l_lst.begin(), l_lst.end(), cmp_simple_selector());
-    std::sort(r_lst.begin(), r_lst.end(), cmp_simple_selector());
-    // process loop
-    while (true)
-    {
-      // first check for valid index
-      if (i == iL) return iL == nL;
-      else if (n == nL) return iL == nL;
-      // the access the vector items
-      Simple_Selector_Obj l = l_lst[i];
-      Simple_Selector_Obj r = r_lst[n];
-      // skip nulls
-      if (!l) ++i;
-      if (!r) ++n;
-      // do the check now
-      else if (*l != *r)
-      { return false; }
-      // advance now
-      ++i; ++n;
-    }
-    // no mismatch
-    return true;
-  }
-
-  bool Complex_Selector_Pointer_Compare::operator() (const Complex_Selector_Obj& pLeft, const Complex_Selector_Obj& pRight) const {
-    return *pLeft < *pRight;
-  }
-
-  bool Complex_Selector::is_superselector_of(Compound_Selector_Obj rhs, std::string wrapping)
-  {
-    return last()->head() && last()->head()->is_superselector_of(rhs, wrapping);
-  }
-
-  bool Complex_Selector::is_superselector_of(Complex_Selector_Obj rhs, std::string wrapping)
-  {
-    Complex_Selector_Ptr lhs = this;
-    // check for selectors with leading or trailing combinators
-    if (!lhs->head() || !rhs->head())
-    { return false; }
-    Complex_Selector_Obj l_innermost = lhs->innermost();
-    if (l_innermost->combinator() != Complex_Selector::ANCESTOR_OF)
-    { return false; }
-    Complex_Selector_Obj r_innermost = rhs->innermost();
-    if (r_innermost->combinator() != Complex_Selector::ANCESTOR_OF)
-    { return false; }
-    // more complex (i.e., longer) selectors are always more specific
-    size_t l_len = lhs->length(), r_len = rhs->length();
-    if (l_len > r_len)
-    { return false; }
-
-    if (l_len == 1)
-    { return lhs->head()->is_superselector_of(&rhs->last()->head(), wrapping); }
-
-    // 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_Obj lhs_tail = lhs->tail();
-      Complex_Selector_Obj rhs_tail = rhs->tail();
-      if (lhs_tail->combinator() != rhs_tail->combinator()) return false;
-      if (lhs_tail->head() && !rhs_tail->head()) return false;
-      if (!lhs_tail->head() && rhs_tail->head()) return false;
-      if (lhs_tail->head() && rhs_tail->head()) {
-        if (!lhs_tail->head()->is_superselector_of(&rhs_tail->head())) return false;
-      }
-    }
-
-    bool found = false;
-    Complex_Selector_Obj marker = rhs;
-    for (size_t i = 0, L = rhs->length(); i < L; ++i) {
-      if (i == L-1)
-      { return false; }
-      if (lhs->head() && marker->head() && lhs->head()->is_superselector_of(&marker->head(), wrapping))
-      { found = true; break; }
-      marker = marker->tail();
-    }
-    if (!found)
-    { return false; }
-
-    /*
-      Hmm, I hope I have the logic right:
-
-      if lhs has a combinator:
-        if !(marker has a combinator) return false
-        if !(lhs.combinator == '~' ? marker.combinator != '>' : lhs.combinator == marker.combinator) return false
-        return lhs.tail-without-innermost.is_superselector_of(marker.tail-without-innermost)
-      else if marker has a combinator:
-        if !(marker.combinator == ">") return false
-        return lhs.tail.is_superselector_of(marker.tail)
-      else
-        return lhs.tail.is_superselector_of(marker.tail)
-    */
-    if (lhs->combinator() != Complex_Selector::ANCESTOR_OF)
-    {
-      if (marker->combinator() == Complex_Selector::ANCESTOR_OF)
-      { return false; }
-      if (!(lhs->combinator() == Complex_Selector::PRECEDES ? marker->combinator() != Complex_Selector::PARENT_OF : lhs->combinator() == marker->combinator()))
-      { return false; }
-      return lhs->tail()->is_superselector_of(&marker->tail());
-    }
-    else if (marker->combinator() != Complex_Selector::ANCESTOR_OF)
-    {
-      if (marker->combinator() != Complex_Selector::PARENT_OF)
-      { return false; }
-      return lhs->tail()->is_superselector_of(&marker->tail());
-    }
-    else
-    {
-      return lhs->tail()->is_superselector_of(&marker->tail());
-    }
-    // catch-all
-    return false;
-  }
-
-  size_t Complex_Selector::length() const
-  {
-    // TODO: make this iterative
-    if (!tail()) return 1;
-    return 1 + tail()->length();
-  }
-
-  Complex_Selector_Obj Complex_Selector::context(Context& ctx)
-  {
-    if (!tail()) return 0;
-    if (!head()) return tail()->context(ctx);
-    Complex_Selector_Obj cpy = SASS_MEMORY_NEW(Complex_Selector, pstate(), combinator(), head(), tail()->context(ctx));
-    cpy->media_block(media_block());
-    return cpy;
-  }
-
-  // append another complex selector at the end
-  // check if we need to append some headers
-  // then we need to check for the combinator
-  // only then we can safely set the new tail
-  void Complex_Selector::append(Context& ctx, Complex_Selector_Obj ss)
-  {
-
-    Complex_Selector_Obj t = ss->tail();
-    Combinator c = ss->combinator();
-    String_Obj r = ss->reference();
-    Compound_Selector_Obj h = ss->head();
-
-    if (ss->has_line_feed()) has_line_feed(true);
-    if (ss->has_line_break()) has_line_break(true);
-
-    // append old headers
-    if (h && h->length()) {
-      if (last()->combinator() != ANCESTOR_OF && c != ANCESTOR_OF) {
-        error("Invalid parent selector", pstate_);
-      } else if (last()->head_ && last()->head_->length()) {
-        Compound_Selector_Obj rh = last()->head();
-        size_t i = 0, L = h->length();
-        if (SASS_MEMORY_CAST(Element_Selector, h->first())) {
-          if (Class_Selector_Ptr sq = SASS_MEMORY_CAST(Class_Selector, rh->last())) {
-            Class_Selector_Ptr sqs = SASS_MEMORY_COPY(sq);
-            sqs->name(sqs->name() + (*h)[0]->name());
-            sqs->pstate((*h)[0]->pstate());
-            (*rh)[rh->length()-1] = sqs;
-            rh->pstate(h->pstate());
-            for (i = 1; i < L; ++i) rh->append(&(*h)[i]);
-          } else if (Id_Selector_Ptr sq = SASS_MEMORY_CAST(Id_Selector, rh->last())) {
-            Id_Selector_Ptr sqs = SASS_MEMORY_COPY(sq);
-            sqs->name(sqs->name() + (*h)[0]->name());
-            sqs->pstate((*h)[0]->pstate());
-            (*rh)[rh->length()-1] = sqs;
-            rh->pstate(h->pstate());
-            for (i = 1; i < L; ++i) rh->append(&(*h)[i]);
-          } else if (Element_Selector_Ptr ts = SASS_MEMORY_CAST(Element_Selector, rh->last())) {
-            Element_Selector_Ptr tss = SASS_MEMORY_COPY(ts);
-            tss->name(tss->name() + (*h)[0]->name());
-            tss->pstate((*h)[0]->pstate());
-            (*rh)[rh->length()-1] = tss;
-            rh->pstate(h->pstate());
-            for (i = 1; i < L; ++i) rh->append(&(*h)[i]);
-          } else if (Placeholder_Selector_Ptr ps = SASS_MEMORY_CAST(Placeholder_Selector, rh->last())) {
-            Placeholder_Selector_Ptr pss = SASS_MEMORY_COPY(ps);
-            pss->name(pss->name() + (*h)[0]->name());
-            pss->pstate((*h)[0]->pstate());
-            (*rh)[rh->length()-1] = pss;
-            rh->pstate(h->pstate());
-            for (i = 1; i < L; ++i) rh->append(&(*h)[i]);
-          } else {
-            last()->head_->concat(&h);
-          }
-        } else {
-          last()->head_->concat(&h);
-        }
-      } else {
-        last()->head_->concat(&h);
-      }
-    } else {
-      // std::cerr << "has no or empty head\n";
-    }
-
-    if (last()) {
-      if (last()->combinator() != ANCESTOR_OF && c != ANCESTOR_OF) {
-        Complex_Selector_Ptr inter = SASS_MEMORY_NEW(Complex_Selector, pstate());
-        inter->reference(r);
-        inter->combinator(c);
-        inter->tail(t);
-        last()->tail(inter);
-      } else {
-        if (last()->combinator() == ANCESTOR_OF) {
-          last()->combinator(c);
-          last()->reference(r);
-        }
-        last()->tail(t);
-      }
-    }
-
-
-  }
-
-  Selector_List_Ptr Selector_List::resolve_parent_refs(Context& ctx, std::vector<Selector_List_Obj>& pstack, bool implicit_parent)
-  {
-    if (!this->has_parent_ref()) return this;
-    Selector_List_Ptr ss = SASS_MEMORY_NEW(Selector_List, pstate());
-    Selector_List_Ptr ps = &pstack.back();
-    for (size_t pi = 0, pL = ps->length(); pi < pL; ++pi) {
-      for (size_t si = 0, sL = this->length(); si < sL; ++si) {
-        Selector_List_Obj rv = at(si)->resolve_parent_refs(ctx, pstack, implicit_parent);
-        ss->concat(&rv);
-      }
-    }
-    return ss;
-  }
-
-  Selector_List_Ptr Complex_Selector::resolve_parent_refs(Context& ctx, std::vector<Selector_List_Obj>& pstack, bool implicit_parent)
-  {
-    Complex_Selector_Obj tail = this->tail();
-    Compound_Selector_Obj head = this->head();
-    Selector_List_Ptr parents = &pstack.back();
-
-    if (!this->has_real_parent_ref() && !implicit_parent) {
-      Selector_List_Ptr retval = SASS_MEMORY_NEW(Selector_List, pstate());
-      retval->append(this);
-      return retval;
-    }
-
-    // first resolve_parent_refs the tail (which may return an expanded list)
-    Selector_List_Obj tails = tail ? tail->resolve_parent_refs(ctx, pstack, implicit_parent) : 0;
-
-    if (head && head->length() > 0) {
-
-      Selector_List_Obj retval;
-      // we have a parent selector in a simple compound list
-      // mix parent complex selector into the compound list
-      if (SASS_MEMORY_CAST(Parent_Selector, (*head)[0])) {
-        retval = SASS_MEMORY_NEW(Selector_List, pstate());
-
-        // it turns out that real parent references reach
-        // across @at-root rules, which comes unexpected
-        if (parents == NULL && head->has_real_parent_ref()) {
-          int i = pstack.size() - 1;
-          while (!parents && i > -1) {
-            parents = &pstack.at(i--);
-          }
-        }
-
-        if (parents && parents->length()) {
-          if (tails && tails->length() > 0) {
-            for (size_t n = 0, nL = tails->length(); n < nL; ++n) {
-              for (size_t i = 0, iL = parents->length(); i < iL; ++i) {
-                Complex_Selector_Obj t = (*tails)[n];
-                Complex_Selector_Obj parent = (*parents)[i];
-                Complex_Selector_Obj s = SASS_MEMORY_CLONE(parent);
-                Complex_Selector_Obj ss = SASS_MEMORY_CLONE(this);
-                ss->tail(t ? SASS_MEMORY_CLONE(t) : 0);
-                Compound_Selector_Obj h = SASS_MEMORY_COPY(head_);
-                // remove parent selector from sequence
-                if (h->length()) h->erase(h->begin());
-                ss->head(h->length() ? &h : 0);
-                // adjust for parent selector (1 char)
-                if (h->length()) {
-                  ParserState state(h->at(0)->pstate());
-                  state.offset.column += 1;
-                  state.column -= 1;
-                  (*h)[0]->pstate(state);
-                }
-                // keep old parser state
-                s->pstate(pstate());
-                // append new tail
-                s->append(ctx, ss);
-                retval->append(s);
-              }
-            }
-          }
-          // have no tails but parents
-          // loop above is inside out
-          else {
-            for (size_t i = 0, iL = parents->length(); i < iL; ++i) {
-              Complex_Selector_Obj parent = (*parents)[i];
-              Complex_Selector_Obj s = SASS_MEMORY_CLONE(parent);
-              Complex_Selector_Obj ss = SASS_MEMORY_CLONE(this);
-              // this is only if valid if the parent has no trailing op
-              // otherwise we cannot append more simple selectors to head
-              if (parent->last()->combinator() != ANCESTOR_OF) {
-                throw Exception::InvalidParent(&parent, &ss);
-              }
-              ss->tail(tail ? SASS_MEMORY_CLONE(tail) : 0);
-              Compound_Selector_Obj h = SASS_MEMORY_COPY(head_);
-              // remove parent selector from sequence
-              if (h->length()) h->erase(h->begin());
-              ss->head(h->length() ? &h : 0);
-              // \/ IMO ruby sass bug \/
-              ss->has_line_feed(false);
-              // adjust for parent selector (1 char)
-              if (h->length()) {
-                ParserState state(h->at(0)->pstate());
-                state.offset.column += 1;
-                state.column -= 1;
-                (*h)[0]->pstate(state);
-              }
-              // keep old parser state
-              s->pstate(pstate());
-              // append new tail
-              s->append(ctx, &ss);
-              retval->append(s);
-            }
-          }
-        }
-        // have no parent but some tails
-        else {
-          if (tails && tails->length() > 0) {
-            for (size_t n = 0, nL = tails->length(); n < nL; ++n) {
-              Complex_Selector_Obj cpy = SASS_MEMORY_CLONE(this);
-              cpy->tail(SASS_MEMORY_CLONE(tails->at(n)));
-              cpy->head(SASS_MEMORY_NEW(Compound_Selector, head->pstate()));
-              for (size_t i = 1, L = this->head()->length(); i < L; ++i)
-                cpy->head()->append(&(*this->head())[i]);
-              if (!cpy->head()->length()) cpy->head(0);
-              retval->append(cpy->skip_empty_reference());
-            }
-          }
-          // have no parent nor tails
-          else {
-            Complex_Selector_Obj cpy = SASS_MEMORY_CLONE(this);
-            cpy->head(SASS_MEMORY_NEW(Compound_Selector, head->pstate()));
-            for (size_t i = 1, L = this->head()->length(); i < L; ++i)
-              cpy->head()->append(&(*this->head())[i]);
-            if (!cpy->head()->length()) cpy->head(0);
-            retval->append(cpy->skip_empty_reference());
-          }
-        }
-      }
-      // no parent selector in head
-      else {
-        retval = this->tails(ctx, &tails);
-      }
-
-      for (Simple_Selector_Obj ss : head->elements()) {
-        if (Wrapped_Selector_Ptr ws = SASS_MEMORY_CAST(Wrapped_Selector, ss)) {
-          if (Selector_List_Ptr sl = SASS_MEMORY_CAST(Selector_List, ws->selector())) {
-            if (parents) ws->selector(sl->resolve_parent_refs(ctx, pstack, implicit_parent));
-          }
-        }
-      }
-
-      return retval.detach();
-
-    }
-    // has no head
-    else {
-      return this->tails(ctx, &tails);
-    }
-
-    // unreachable
-    return 0;
-  }
-
-  Selector_List_Ptr Complex_Selector::tails(Context& ctx, Selector_List_Ptr tails)
-  {
-    Selector_List_Ptr rv = SASS_MEMORY_NEW(Selector_List, pstate_);
-    if (tails && tails->length()) {
-      for (size_t i = 0, iL = tails->length(); i < iL; ++i) {
-        Complex_Selector_Obj pr = SASS_MEMORY_CLONE(this);
-        pr->tail(tails->at(i));
-        rv->append(pr);
-      }
-    }
-    else {
-      rv->append(this);
-    }
-    return rv;
-  }
-
-  // return the last tail that is defined
-  Complex_Selector_Obj Complex_Selector::first()
-  {
-    // declare variables used in loop
-    Complex_Selector_Obj cur = this;
-    Compound_Selector_Obj head;
-    // processing loop
-    while (cur)
-    {
-      // get the head
-      head = cur->head_;
-      // abort (and return) if it is not a parent selector
-      if (!head || head->length() != 1 || !SASS_MEMORY_CAST(Parent_Selector, (*head)[0])) {
-        break;
-      }
-      // advance to next
-      cur = cur->tail_;
-    }
-    // result
-    return &cur;
-  }
-
-  // return the last tail that is defined
-  Complex_Selector_Obj Complex_Selector::last()
-  {
-    // ToDo: implement with a while loop
-    return tail_? tail_->last() : this;
-  }
-
-  Complex_Selector::Combinator Complex_Selector::clear_innermost()
-  {
-    Combinator c;
-    if (!tail() || tail()->tail() == 0)
-    { c = combinator(); combinator(ANCESTOR_OF); tail(0); }
-    else
-    { c = tail()->clear_innermost(); }
-    return c;
-  }
-
-  void Complex_Selector::set_innermost(Complex_Selector_Obj val, Combinator c)
-  {
-    if (!tail())
-    { tail(val); combinator(c); }
-    else
-    { tail()->set_innermost(val, c); }
-  }
-
-  void Complex_Selector::cloneChildren()
-  {
-    if (head()) head(SASS_MEMORY_CLONE(head()));
-    if (tail()) tail(SASS_MEMORY_CLONE(tail()));
-  }
-
-  void Compound_Selector::cloneChildren()
-  {
-    for (size_t i = 0, l = length(); i < l; i++) {
-      at(i) = SASS_MEMORY_CLONE(at(i));
-    }
-  }
-
-  void Selector_List::cloneChildren()
-  {
-    for (size_t i = 0, l = length(); i < l; i++) {
-      at(i) = SASS_MEMORY_CLONE(at(i));
-    }
-  }
-
-  void Wrapped_Selector::cloneChildren()
-  {
-    selector(SASS_MEMORY_CLONE(selector()));
-  }
-
-  // remove parent selector references
-  // basically unwraps parsed selectors
-  void Selector_List::remove_parent_selectors()
-  {
-    // Check every rhs selector against left hand list
-    for(size_t i = 0, L = length(); i < L; ++i) {
-      if (!(*this)[i]->head()) continue;
-      if ((*this)[i]->head()->is_empty_reference()) {
-        // simply move to the next tail if we have "no" combinator
-        if ((*this)[i]->combinator() == Complex_Selector::ANCESTOR_OF) {
-          if ((*this)[i]->tail()) {
-            if ((*this)[i]->has_line_feed()) {
-              (*this)[i]->tail()->has_line_feed(true);
-            }
-            (*this)[i] = (*this)[i]->tail();
-          }
-        }
-        // otherwise remove the first item from head
-        else {
-          (*this)[i]->head()->erase((*this)[i]->head()->begin());
-        }
-      }
-    }
-  }
-
-  bool Selector_List::has_parent_ref()
-  {
-    for (Complex_Selector_Obj s : elements()) {
-      if (s && s->has_parent_ref()) return true;
-    }
-    return false;
-  }
-
-  bool Selector_List::has_real_parent_ref()
-  {
-    for (Complex_Selector_Obj s : elements()) {
-      if (s && s->has_real_parent_ref()) return true;
-    }
-    return false;
-  }
-
-  bool Selector_Schema::has_parent_ref()
-  {
-    if (String_Schema_Obj schema = SASS_MEMORY_CAST(String_Schema, contents())) {
-      return schema->length() > 0 && SASS_MEMORY_CAST(Parent_Selector, schema->at(0)) != NULL;
-    }
-    return false;
-  }
-
-  bool Selector_Schema::has_real_parent_ref()
-  {
-    if (String_Schema_Obj schema = SASS_MEMORY_CAST(String_Schema, contents())) {
-      Parent_Selector_Obj p = SASS_MEMORY_CAST(Parent_Selector, schema->at(0));
-      return schema->length() > 0 && p && p->is_real_parent_ref();
-    }
-    return false;
-  }
-
-  void Selector_List::adjust_after_pushing(Complex_Selector_Obj c)
-  {
-    // if (c->has_reference())   has_reference(true);
-  }
-
-  // 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_Obj sub, std::string wrapping)
-  {
-    // 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], wrapping)) 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_Obj sub, std::string wrapping)
-  {
-    // 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], wrapping)) 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_Obj sub, std::string wrapping)
-  {
-    // Check every lhs selector against right hand
-    for(size_t i = 0, L = length(); i < L; ++i) {
-      if ((*this)[i]->is_superselector_of(sub, wrapping)) 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_Obj sub, std::string wrapping)
-  {
-    // 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;
-  }
-
-  Selector_List_Ptr Selector_List::unify_with(Selector_List_Ptr rhs, Context& ctx) {
-    std::vector<Complex_Selector_Obj> unified_complex_selectors;
-    // Unify all of children with RHS's children, storing the results in `unified_complex_selectors`
-    for (size_t lhs_i = 0, lhs_L = length(); lhs_i < lhs_L; ++lhs_i) {
-      Complex_Selector_Obj seq1 = (*this)[lhs_i];
-      for(size_t rhs_i = 0, rhs_L = rhs->length(); rhs_i < rhs_L; ++rhs_i) {
-        Complex_Selector_Ptr seq2 = &rhs->at(rhs_i);
-
-        Selector_List_Obj result = seq1->unify_with(seq2, ctx);
-        if( result ) {
-          for(size_t i = 0, L = result->length(); i < L; ++i) {
-            unified_complex_selectors.push_back( &(*result)[i] );
-          }
-        }
-      }
-    }
-
-    // Creates the final Selector_List by combining all the complex selectors
-    Selector_List_Ptr final_result = SASS_MEMORY_NEW(Selector_List, pstate());
-    for (auto itr = unified_complex_selectors.begin(); itr != unified_complex_selectors.end(); ++itr) {
-      final_result->append(*itr);
-    }
-    return final_result;
-  }
-
-  void Selector_List::populate_extends(Selector_List_Obj extendee, Context& ctx, Subset_Map& extends)
-  {
-
-    Selector_List_Ptr extender = this;
-    for (auto complex_sel : extendee->elements()) {
-      Complex_Selector_Obj c = complex_sel;
-
-
-      // Ignore any parent selectors, until we find the first non Selectorerence head
-      Compound_Selector_Obj compound_sel = c->head();
-      Complex_Selector_Obj pIter = complex_sel;
-      while (pIter) {
-        Compound_Selector_Obj pHead = pIter->head();
-        if (pHead && SASS_MEMORY_CAST(Parent_Selector, pHead->elements()[0]) == NULL) {
-          compound_sel = pHead;
-          break;
-        }
-
-        pIter = pIter->tail();
-      }
-
-      if (!pIter->head() || pIter->tail()) {
-        error("nested selectors may not be extended", c->pstate());
-      }
-
-      compound_sel->is_optional(extendee->is_optional());
-
-      for (size_t i = 0, L = extender->length(); i < L; ++i) {
-        extends.put(compound_sel, std::make_pair(&(*extender)[i], &compound_sel));
-      }
-    }
-  };
-
-  std::vector<std::string> Compound_Selector::to_str_vec()
-  {
-    std::vector<std::string> result(length());
-    for (size_t i = 0, L = length(); i < L; ++i)
-    { result.push_back((*this)[i]->to_string()); }
-    return result;
-  }
-
-  void Compound_Selector::append(Simple_Selector_Ptr element)
-  {
-    Vectorized<Simple_Selector_Obj>::append(element);
-    pstate_.offset += element->pstate().offset;
-  }
-
-  Compound_Selector_Ptr Compound_Selector::minus(Compound_Selector_Ptr rhs, Context& ctx)
-  {
-    Compound_Selector_Ptr result = SASS_MEMORY_NEW(Compound_Selector, pstate());
-    // result->has_parent_reference(has_parent_reference());
-
-    // not very efficient because it needs to preserve order
-    for (size_t i = 0, L = length(); i < L; ++i)
-    {
-      bool found = false;
-      std::string thisSelector((*this)[i]->to_string(ctx.c_options));
-      for (size_t j = 0, M = rhs->length(); j < M; ++j)
-      {
-        if (thisSelector == (*rhs)[j]->to_string(ctx.c_options))
-        {
-          found = true;
-          break;
-        }
-      }
-      if (!found) result->append(&(*this)[i]);
-    }
-
-    return result;
-  }
-
-  void Compound_Selector::mergeSources(SourcesSet& sources, Context& ctx)
-  {
-    for (SourcesSet::iterator iterator = sources.begin(), endIterator = sources.end(); iterator != endIterator; ++iterator) {
-      this->sources_.insert(SASS_MEMORY_CLONE(*iterator));
-    }
-  }
-
-  Argument_Obj Arguments::get_rest_argument()
-  {
-    if (this->has_rest_argument()) {
-      for (Argument_Obj arg : this->elements()) {
-        if (arg->is_rest_argument()) {
-          return arg;
-        }
-      }
-    }
-    return NULL;
-  }
-
-  Argument_Obj Arguments::get_keyword_argument()
-  {
-    if (this->has_keyword_argument()) {
-      for (Argument_Obj arg : this->elements()) {
-        if (arg->is_keyword_argument()) {
-          return arg;
-        }
-      }
-    }
-    return NULL;
-  }
-
-  void Arguments::adjust_after_pushing(Argument_Obj a)
-  {
-    if (!a->name().empty()) {
-      if (/* has_rest_argument_ || */ has_keyword_argument_) {
-        error("named arguments must precede variable-length argument", a->pstate());
-      }
-      has_named_arguments_ = true;
-    }
-    else if (a->is_rest_argument()) {
-      if (has_rest_argument_) {
-        error("functions and mixins may only be called with one variable-length argument", a->pstate());
-      }
-      if (has_keyword_argument_) {
-        error("only keyword arguments may follow variable arguments", a->pstate());
-      }
-      has_rest_argument_ = true;
-    }
-    else if (a->is_keyword_argument()) {
-      if (has_keyword_argument_) {
-        error("functions and mixins may only be called with one keyword argument", a->pstate());
-      }
-      has_keyword_argument_ = true;
-    }
-    else {
-      if (has_rest_argument_) {
-        error("ordinal arguments must precede variable-length arguments", a->pstate());
-      }
-      if (has_named_arguments_) {
-        error("ordinal arguments must precede named arguments", a->pstate());
-      }
-    }
-  }
-
-  bool Ruleset::is_invisible() const {
-    if (Selector_List_Ptr sl = SASS_MEMORY_CAST(Selector_List, selector())) {
-      for (size_t i = 0, L = sl->length(); i < L; ++i)
-        if (!(*sl)[i]->has_placeholder()) return false;
-    }
-    return true;
-  }
-
-  bool Media_Block::is_invisible() const {
-    for (size_t i = 0, L = block()->length(); i < L; ++i) {
-      Statement_Obj stm = block()->at(i);
-      if (!stm->is_invisible()) return false;
-    }
-    return true;
-  }
-
-  Number::Number(ParserState pstate, double val, std::string u, bool zero)
-  : Value(pstate),
-    value_(val),
-    zero_(zero),
-    numerator_units_(std::vector<std::string>()),
-    denominator_units_(std::vector<std::string>()),
-    hash_(0)
-  {
-    size_t l = 0, r = 0;
-    if (!u.empty()) {
-      bool nominator = true;
-      while (true) {
-        r = u.find_first_of("*/", l);
-        std::string unit(u.substr(l, r == std::string::npos ? r : r - l));
-        if (!unit.empty()) {
-          if (nominator) numerator_units_.push_back(unit);
-          else denominator_units_.push_back(unit);
-        }
-        if (r == std::string::npos) break;
-        // ToDo: should error for multiple slashes
-        // if (!nominator && u[r] == '/') error(...)
-        if (u[r] == '/')
-          nominator = false;
-        l = r + 1;
-      }
-    }
-    concrete_type(NUMBER);
-  }
-
-  std::string Number::unit() const
-  {
-    std::string 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;
-  }
-
-  bool Number::is_valid_css_unit() const
-  {
-    return numerator_units().size() <= 1 &&
-           denominator_units().size() == 0;
-  }
-
-  bool Number::is_unitless() const
-  { return numerator_units_.empty() && denominator_units_.empty(); }
-
-  void Number::normalize(const std::string& prefered, bool strict)
-  {
-
-    // 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
-    std::map<std::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
-    std::vector<std::string>::iterator nom_it = numerator_units_.begin();
-    std::vector<std::string>::iterator nom_end = numerator_units_.end();
-    std::vector<std::string>::iterator denom_it = denominator_units_.begin();
-    std::vector<std::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 std::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 std::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, strict);
-        // 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.first.empty()) {
-          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, strict); }
-    catch (incompatibleUnits& err)
-    { error(err.what(), pstate()); }
-    catch (...) { throw; }
-
-  }
-
-  // this does not cover all cases (multiple prefered units)
-  double Number::convert_factor(const Number& n) const
-  {
-
-    // 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 class
-    // std::map<std::string, int> exponents;
-    // initialize by summing up occurences in unit vectors
-    // for (size_t i = 0, S = numerator_units_.size(); i < S; ++i) ++ exponents[unit_to_class(numerator_units_[i])];
-    // for (size_t i = 0, S = denominator_units_.size(); i < S; ++i) -- exponents[unit_to_class(denominator_units_[i])];
-
-    std::vector<std::string> l_miss_nums(0);
-    std::vector<std::string> l_miss_dens(0);
-    // create copy since we need these for state keeping
-    std::vector<std::string> r_nums(n.numerator_units_);
-    std::vector<std::string> r_dens(n.denominator_units_);
-
-    std::vector<std::string>::const_iterator l_num_it = numerator_units_.begin();
-    std::vector<std::string>::const_iterator l_num_end = numerator_units_.end();
-
-    bool l_unitless = is_unitless();
-    bool r_unitless = n.is_unitless();
-
-    // overall conversion
-    double factor = 1;
-
-    // process all left numerators
-    while (l_num_it != l_num_end)
-    {
-      // get and increment afterwards
-      const std::string l_num = *(l_num_it ++);
-
-      std::vector<std::string>::iterator r_num_it = r_nums.begin();
-      std::vector<std::string>::iterator r_num_end = r_nums.end();
-
-      bool found = false;
-      // search for compatible numerator
-      while (r_num_it != r_num_end)
-      {
-        // get and increment afterwards
-        const std::string r_num = *(r_num_it);
-        // get possible converstion factor for units
-        double conversion = conversion_factor(l_num, r_num, false);
-        // skip incompatible numerator
-        if (conversion == 0) {
-          ++ r_num_it;
-          continue;
-        }
-        // apply to global factor
-        factor *= conversion;
-        // remove item from vector
-        r_nums.erase(r_num_it);
-        // found numerator
-        found = true;
-        break;
-      }
-      // maybe we did not find any
-      // left numerator is leftover
-      if (!found) l_miss_nums.push_back(l_num);
-    }
-
-    std::vector<std::string>::const_iterator l_den_it = denominator_units_.begin();
-    std::vector<std::string>::const_iterator l_den_end = denominator_units_.end();
-
-    // process all left denominators
-    while (l_den_it != l_den_end)
-    {
-      // get and increment afterwards
-      const std::string l_den = *(l_den_it ++);
-
-      std::vector<std::string>::iterator r_den_it = r_dens.begin();
-      std::vector<std::string>::iterator r_den_end = r_dens.end();
-
-      bool found = false;
-      // search for compatible denominator
-      while (r_den_it != r_den_end)
-      {
-        // get and increment afterwards
-        const std::string r_den = *(r_den_it);
-        // get possible converstion factor for units
-        double conversion = conversion_factor(l_den, r_den, false);
-        // skip incompatible denominator
-        if (conversion == 0) {
-          ++ r_den_it;
-          continue;
-        }
-        // apply to global factor
-        factor *= conversion;
-        // remove item from vector
-        r_dens.erase(r_den_it);
-        // found denominator
-        found = true;
-        break;
-      }
-      // maybe we did not find any
-      // left denominator is leftover
-      if (!found) l_miss_dens.push_back(l_den);
-    }
-
-    // check left-overs (ToDo: might cancel out)
-    if (l_miss_nums.size() > 0 && !r_unitless) {
-      throw Exception::IncompatibleUnits(n, *this);
-    }
-    if (l_miss_dens.size() > 0 && !r_unitless) {
-      throw Exception::IncompatibleUnits(n, *this);
-    }
-    if (r_nums.size() > 0 && !l_unitless) {
-      throw Exception::IncompatibleUnits(n, *this);
-    }
-    if (r_dens.size() > 0 && !l_unitless) {
-      throw Exception::IncompatibleUnits(n, *this);
-    }
-
-    return factor;
-  }
-
-  // this does not cover all cases (multiple prefered units)
-  bool Number::convert(const std::string& prefered, bool strict)
-  {
-    // no conversion if unit is empty
-    if (prefered.empty()) return true;
-
-    // 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
-    std::map<std::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;
-
-    std::vector<std::string>::iterator denom_it = denominator_units_.begin();
-    std::vector<std::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 std::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, strict);
-      // update nominator/denominator exponent
-      ++ exponents[denom]; -- exponents[prefered];
-    }
-
-    std::vector<std::string>::iterator nom_it = numerator_units_.begin();
-    std::vector<std::string>::iterator nom_end = numerator_units_.end();
-
-    // now search for nominator
-    while (nom_it != nom_end)
-    {
-      // get and increment afterwards
-      const std::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, strict);
-      // 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.first.empty()) {
-          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;
-
-    // success?
-    return true;
-
-  }
-
-  // useful for making one number compatible with another
-  std::string Number::find_convertible_unit() const
-  {
-    for (size_t i = 0, S = numerator_units_.size(); i < S; ++i) {
-      std::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) {
-      std::string u(denominator_units_[i]);
-      if (string_to_unit(u) != UNKNOWN) return u;
-    }
-    return std::string();
-  }
-
-  bool Custom_Warning::operator== (const Expression& rhs) const
-  {
-    if (Custom_Warning_Ptr_Const r = dynamic_cast<Custom_Warning_Ptr_Const>(&rhs)) {
-      return message() == r->message();
-    }
-    return false;
-  }
-
-  bool Custom_Error::operator== (const Expression& rhs) const
-  {
-    if (Custom_Error_Ptr_Const r = dynamic_cast<Custom_Error_Ptr_Const>(&rhs)) {
-      return message() == r->message();
-    }
-    return false;
-  }
-
-  bool Number::eq (const Expression& rhs) const
-  {
-    if (Number_Ptr_Const r = dynamic_cast<Number_Ptr_Const>(&rhs)) {
-      size_t lhs_units = numerator_units_.size() + denominator_units_.size();
-      size_t rhs_units = r->numerator_units_.size() + r->denominator_units_.size();
-      if (!lhs_units && !rhs_units) {
-        return std::fabs(value() - r->value()) < NUMBER_EPSILON;
-      }
-      return (numerator_units_ == r->numerator_units_) &&
-             (denominator_units_ == r->denominator_units_) &&
-             std::fabs(value() - r->value()) < NUMBER_EPSILON;
-    }
-    return false;
-  }
-
-  bool Number::operator== (const Expression& rhs) const
-  {
-    if (Number_Ptr_Const r = dynamic_cast<Number_Ptr_Const>(&rhs)) {
-      size_t lhs_units = numerator_units_.size() + denominator_units_.size();
-      size_t rhs_units = r->numerator_units_.size() + r->denominator_units_.size();
-      // unitless and only having one unit seems equivalent (will change in future)
-      if (!lhs_units || !rhs_units) {
-        return std::fabs(value() - r->value()) < NUMBER_EPSILON;
-      }
-      return (numerator_units_ == r->numerator_units_) &&
-             (denominator_units_ == r->denominator_units_) &&
-             std::fabs(value() - r->value()) < NUMBER_EPSILON;
-    }
-    return false;
-  }
-
-  bool Number::operator< (const Number& rhs) const
-  {
-    size_t lhs_units = numerator_units_.size() + denominator_units_.size();
-    size_t rhs_units = rhs.numerator_units_.size() + rhs.denominator_units_.size();
-    // unitless and only having one unit seems equivalent (will change in future)
-    if (!lhs_units || !rhs_units) {
-      return value() < rhs.value();
-    }
-
-    Number tmp_r(&rhs); // copy
-    tmp_r.normalize(find_convertible_unit());
-    std::string l_unit(unit());
-    std::string r_unit(tmp_r.unit());
-    if (unit() != tmp_r.unit()) {
-      error("cannot compare numbers with incompatible units", pstate());
-    }
-    return value() < tmp_r.value();
-  }
-
-  bool String_Quoted::operator== (const Expression& rhs) const
-  {
-    if (String_Quoted_Ptr_Const qstr = dynamic_cast<String_Quoted_Ptr_Const>(&rhs)) {
-      return (value() == qstr->value());
-    } else if (String_Constant_Ptr_Const cstr = dynamic_cast<String_Constant_Ptr_Const>(&rhs)) {
-      return (value() == cstr->value());
-    }
-    return false;
-  }
-
-  bool String_Constant::is_invisible() const {
-    return value_.empty() && quote_mark_ == 0;
-  }
-
-  bool String_Constant::operator== (const Expression& rhs) const
-  {
-    if (String_Quoted_Ptr_Const qstr = dynamic_cast<String_Quoted_Ptr_Const>(&rhs)) {
-      return (value() == qstr->value());
-    } else if (String_Constant_Ptr_Const cstr = dynamic_cast<String_Constant_Ptr_Const>(&rhs)) {
-      return (value() == cstr->value());
-    }
-    return false;
-  }
-
-  bool String_Schema::is_left_interpolant(void) const
-  {
-    return length() && first()->is_left_interpolant();
-  }
-  bool String_Schema::is_right_interpolant(void) const
-  {
-    return length() && last()->is_right_interpolant();
-  }
-
-  bool String_Schema::operator== (const Expression& rhs) const
-  {
-    if (String_Schema_Ptr_Const r = dynamic_cast<String_Schema_Ptr_Const>(&rhs)) {
-      if (length() != r->length()) return false;
-      for (size_t i = 0, L = length(); i < L; ++i) {
-        Expression_Obj rv = (*r)[i];
-        Expression_Obj lv = (*this)[i];
-        if (!lv || !rv) return false;
-        if (!(*lv == *rv)) return false;
-      }
-      return true;
-    }
-    return false;
-  }
-
-  bool Boolean::operator== (const Expression& rhs) const
-  {
-    if (Boolean_Ptr_Const r = dynamic_cast<Boolean_Ptr_Const>(&rhs)) {
-      return (value() == r->value());
-    }
-    return false;
-  }
-
-  bool Color::operator== (const Expression& rhs) const
-  {
-    if (Color_Ptr_Const r = dynamic_cast<Color_Ptr_Const>(&rhs)) {
-      return r_ == r->r() &&
-             g_ == r->g() &&
-             b_ == r->b() &&
-             a_ == r->a();
-    }
-    return false;
-  }
-
-  bool List::operator== (const Expression& rhs) const
-  {
-    if (List_Ptr_Const r = dynamic_cast<List_Ptr_Const>(&rhs)) {
-      if (length() != r->length()) return false;
-      if (separator() != r->separator()) return false;
-      for (size_t i = 0, L = length(); i < L; ++i) {
-        Expression_Obj rv = r->at(i);
-        Expression_Obj lv = this->at(i);
-        if (!lv || !rv) return false;
-        if (!(*lv == *rv)) return false;
-      }
-      return true;
-    }
-    return false;
-  }
-
-  bool Map::operator== (const Expression& rhs) const
-  {
-    if (Map_Ptr_Const r = dynamic_cast<Map_Ptr_Const>(&rhs)) {
-      if (length() != r->length()) return false;
-      for (auto key : keys()) {
-        Expression_Obj lv = at(key);
-        Expression_Obj rv = r->at(key);
-        if (!rv || !lv) return false;
-        if (!(*lv == *rv)) return false;
-      }
-      return true;
-    }
-    return false;
-  }
-
-  bool Null::operator== (const Expression& rhs) const
-  {
-    return rhs.concrete_type() == NULL_VAL;
-  }
-
-  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) {
-      Expression_Obj obj = this->at(i);
-      if (Argument* arg = dynamic_cast<Argument*>(&obj)) {
-        if (!arg->name().empty()) return i;
-      }
-    }
-    return length();
-  }
-
-  Expression_Obj Hashed::at(Expression_Obj k) const
-  {
-    if (elements_.count(k))
-    { return elements_.at(k); }
-    else { return NULL; }
-  }
-
-  bool Binary_Expression::is_left_interpolant(void) const
-  {
-    return is_interpolant() || (left() && left()->is_left_interpolant());
-  }
-  bool Binary_Expression::is_right_interpolant(void) const
-  {
-    return is_interpolant() || (right() && right()->is_right_interpolant());
-  }
-
-  std::string AST_Node::to_string(Sass_Inspect_Options opt) const
-  {
-    Sass_Output_Options out(opt);
-    Emitter emitter(out);
-    Inspect i(emitter);
-    i.in_declaration = true;
-    // ToDo: inspect should be const
-    const_cast<AST_Node_Ptr>(this)->perform(&i);
-    return i.get_buffer();
-  }
-
-  std::string AST_Node::to_string() const
-  {
-    return to_string({ NESTED, 5 });
-  }
-
-  std::string String_Quoted::inspect() const
-  {
-    return quote(value_, '*');
-  }
-
-  std::string String_Constant::inspect() const
-  {
-    return quote(value_, '*');
-  }
-
-  //////////////////////////////////////////////////////////////////////////////////////////
-  // Additional method on Lists to retrieve values directly or from an encompassed Argument.
-  //////////////////////////////////////////////////////////////////////////////////////////
-  Expression_Obj List::value_at_index(size_t i) {
-    Expression_Obj obj = this->at(i);
-    if (is_arglist_) {
-      if (Argument* arg = dynamic_cast<Argument*>(&obj)) {
-        return arg->value();
-      } else {
-        return &obj;
-      }
-    } else {
-      return &obj;
-    }
-  }
-
-  //////////////////////////////////////////////////////////////////////////////////////////
-  // Convert map to (key, value) list.
-  //////////////////////////////////////////////////////////////////////////////////////////
-  List_Obj Map::to_list(Context& ctx, ParserState& pstate) {
-    List_Obj ret = SASS_MEMORY_NEW(List, pstate, length(), SASS_COMMA);
-
-    for (auto key : keys()) {
-      List_Obj l = SASS_MEMORY_NEW(List, pstate, 2);
-      l->append(&key);
-      l->append(at(key));
-      ret->append(&l);
-    }
-
-    return ret;
-  }
-
-  //////////////////////////////////////////////////////////////////////////////////////////
-  // Copy implementations
-  //////////////////////////////////////////////////////////////////////////////////////////
-
-  #ifdef DEBUG_SHARED_PTR
-
-  #define IMPLEMENT_AST_OPERATORS(klass) \
-    klass##_Ptr klass::copy(std::string file, size_t line) const { \
-      klass##_Ptr cpy = new klass(this); \
-      cpy->trace(file, line); \
-      return cpy; \
-    } \
-    klass##_Ptr klass::clone(std::string file, size_t line) const { \
-      klass##_Ptr cpy = copy(file, line); \
-      cpy->cloneChildren(); \
-      return cpy; \
-    } \
-
-  #else
-
-  #define IMPLEMENT_AST_OPERATORS(klass) \
-    klass##_Ptr klass::copy() const { \
-      return new klass(this); \
-    } \
-    klass##_Ptr klass::clone() const { \
-      klass##_Ptr cpy = copy(); \
-      cpy->cloneChildren(); \
-      return cpy; \
-    } \
-
-  #endif
-
-  IMPLEMENT_AST_OPERATORS(Supports_Operator);
-  IMPLEMENT_AST_OPERATORS(Supports_Negation);
-  IMPLEMENT_AST_OPERATORS(Compound_Selector);
-  IMPLEMENT_AST_OPERATORS(Complex_Selector);
-  IMPLEMENT_AST_OPERATORS(Element_Selector);
-  IMPLEMENT_AST_OPERATORS(Class_Selector);
-  IMPLEMENT_AST_OPERATORS(Id_Selector);
-  IMPLEMENT_AST_OPERATORS(Pseudo_Selector);
-  IMPLEMENT_AST_OPERATORS(Wrapped_Selector);
-  IMPLEMENT_AST_OPERATORS(Selector_List);
-  IMPLEMENT_AST_OPERATORS(Ruleset);
-  IMPLEMENT_AST_OPERATORS(Media_Block);
-  IMPLEMENT_AST_OPERATORS(Custom_Warning);
-  IMPLEMENT_AST_OPERATORS(Custom_Error);
-  IMPLEMENT_AST_OPERATORS(List);
-  IMPLEMENT_AST_OPERATORS(Map);
-  IMPLEMENT_AST_OPERATORS(Number);
-  IMPLEMENT_AST_OPERATORS(Binary_Expression);
-  IMPLEMENT_AST_OPERATORS(String_Schema);
-  IMPLEMENT_AST_OPERATORS(String_Constant);
-  IMPLEMENT_AST_OPERATORS(String_Quoted);
-  IMPLEMENT_AST_OPERATORS(Boolean);
-  IMPLEMENT_AST_OPERATORS(Color);
-  IMPLEMENT_AST_OPERATORS(Null);
-  IMPLEMENT_AST_OPERATORS(Parent_Selector);
-  IMPLEMENT_AST_OPERATORS(Import);
-  IMPLEMENT_AST_OPERATORS(Import_Stub);
-  IMPLEMENT_AST_OPERATORS(Function_Call);
-  IMPLEMENT_AST_OPERATORS(Directive);
-  IMPLEMENT_AST_OPERATORS(At_Root_Block);
-  IMPLEMENT_AST_OPERATORS(Supports_Block);
-  IMPLEMENT_AST_OPERATORS(While);
-  IMPLEMENT_AST_OPERATORS(Each);
-  IMPLEMENT_AST_OPERATORS(For);
-  IMPLEMENT_AST_OPERATORS(If);
-  IMPLEMENT_AST_OPERATORS(Mixin_Call);
-  IMPLEMENT_AST_OPERATORS(Extension);
-  IMPLEMENT_AST_OPERATORS(Media_Query);
-  IMPLEMENT_AST_OPERATORS(Media_Query_Expression);
-  IMPLEMENT_AST_OPERATORS(Debug);
-  IMPLEMENT_AST_OPERATORS(Error);
-  IMPLEMENT_AST_OPERATORS(Warning);
-  IMPLEMENT_AST_OPERATORS(Assignment);
-  IMPLEMENT_AST_OPERATORS(Return);
-  IMPLEMENT_AST_OPERATORS(At_Root_Query);
-  IMPLEMENT_AST_OPERATORS(Variable);
-  IMPLEMENT_AST_OPERATORS(Comment);
-  IMPLEMENT_AST_OPERATORS(Attribute_Selector);
-  IMPLEMENT_AST_OPERATORS(Supports_Interpolation);
-  IMPLEMENT_AST_OPERATORS(Supports_Declaration);
-  IMPLEMENT_AST_OPERATORS(Supports_Condition);
-  IMPLEMENT_AST_OPERATORS(Parameters);
-  IMPLEMENT_AST_OPERATORS(Parameter);
-  IMPLEMENT_AST_OPERATORS(Arguments);
-  IMPLEMENT_AST_OPERATORS(Argument);
-  IMPLEMENT_AST_OPERATORS(Unary_Expression);
-  IMPLEMENT_AST_OPERATORS(Function_Call_Schema);
-  IMPLEMENT_AST_OPERATORS(Block);
-  IMPLEMENT_AST_OPERATORS(Content);
-  IMPLEMENT_AST_OPERATORS(Textual);
-  IMPLEMENT_AST_OPERATORS(Trace);
-  IMPLEMENT_AST_OPERATORS(Keyframe_Rule);
-  IMPLEMENT_AST_OPERATORS(Bubble);
-  IMPLEMENT_AST_OPERATORS(Selector_Schema);
-  IMPLEMENT_AST_OPERATORS(Placeholder_Selector);
-  IMPLEMENT_AST_OPERATORS(Definition);
-  IMPLEMENT_AST_OPERATORS(Declaration);
-
+#include "eval.hpp"
+#include "extend.hpp"
+#include "emitter.hpp"
+#include "color_maps.hpp"
+#include "ast_fwd_decl.hpp"
+#include <set>
+#include <iomanip>
+#include <iostream>
+#include <algorithm>
+#include <functional>
+#include <cctype>
+#include <locale>
+
+namespace Sass {
+
+  static Null sass_null(ParserState("null"));
+
+  bool Wrapped_Selector::find ( bool (*f)(AST_Node_Obj) )
+  {
+    // check children first
+    if (selector_) {
+      if (selector_->find(f)) return true;
+    }
+    // execute last
+    return f(this);
+  }
+
+  bool Selector_List::find ( bool (*f)(AST_Node_Obj) )
+  {
+    // check children first
+    for (Complex_Selector_Obj sel : elements()) {
+      if (sel->find(f)) return true;
+    }
+    // execute last
+    return f(this);
+  }
+
+  bool Compound_Selector::find ( bool (*f)(AST_Node_Obj) )
+  {
+    // check children first
+    for (Simple_Selector_Obj sel : elements()) {
+      if (sel->find(f)) return true;
+    }
+    // execute last
+    return f(this);
+  }
+
+  bool Complex_Selector::find ( bool (*f)(AST_Node_Obj) )
+  {
+    // check children first
+    if (head_ && head_->find(f)) return true;
+    if (tail_ && tail_->find(f)) return true;
+    // execute last
+    return f(this);
+  }
+
+  bool Supports_Operator::needs_parens(Supports_Condition_Obj cond) const {
+    if (Supports_Operator_Obj op = Cast<Supports_Operator>(cond)) {
+      return op->operand() != operand();
+    }
+    return Cast<Supports_Negation>(cond) != NULL;
+  }
+
+  bool Supports_Negation::needs_parens(Supports_Condition_Obj cond) const {
+    return Cast<Supports_Negation>(cond) ||
+           Cast<Supports_Operator>(cond);
+  }
+
+  void str_rtrim(std::string& str, const std::string& delimiters = " \f\n\r\t\v")
+  {
+    str.erase( str.find_last_not_of( delimiters ) + 1 );
+  }
+
+  void String_Constant::rtrim()
+  {
+    str_rtrim(value_);
+  }
+
+  void String_Schema::rtrim()
+  {
+    if (!empty()) {
+      if (String_Ptr str = Cast<String>(last())) str->rtrim();
+    }
+  }
+
+  void Argument::set_delayed(bool delayed)
+  {
+    if (value_) value_->set_delayed(delayed);
+    is_delayed(delayed);
+  }
+
+  void Arguments::set_delayed(bool delayed)
+  {
+    for (Argument_Obj arg : elements()) {
+      if (arg) arg->set_delayed(delayed);
+    }
+    is_delayed(delayed);
+  }
+
+
+  bool At_Root_Query::exclude(std::string str)
+  {
+    bool with = feature() && unquote(feature()->to_string()).compare("with") == 0;
+    List_Ptr l = static_cast<List_Ptr>(value().ptr());
+    std::string v;
+
+    if (with)
+    {
+      if (!l || l->length() == 0) return str.compare("rule") != 0;
+      for (size_t i = 0, L = l->length(); i < L; ++i)
+      {
+        v = unquote((*l)[i]->to_string());
+        if (v.compare("all") == 0 || v == str) return false;
+      }
+      return true;
+    }
+    else
+    {
+      if (!l || !l->length()) return str.compare("rule") == 0;
+      for (size_t i = 0, L = l->length(); i < L; ++i)
+      {
+        v = unquote((*l)[i]->to_string());
+        if (v.compare("all") == 0 || v == str) return true;
+      }
+      return false;
+    }
+  }
+
+  void AST_Node::update_pstate(const ParserState& pstate)
+  {
+    pstate_.offset += pstate - pstate_ + pstate.offset;
+  }
+
+  bool Simple_Selector::is_ns_eq(const Simple_Selector& r) const
+  {
+    // https://github.com/sass/sass/issues/2229
+    if ((has_ns_ == r.has_ns_) ||
+        (has_ns_ && ns_.empty()) ||
+        (r.has_ns_ && r.ns_.empty())
+    ) {
+      if (ns_.empty() && r.ns() == "*") return false;
+      else if (r.ns().empty() && ns() == "*") return false;
+      else return ns() == r.ns();
+    }
+    return false;
+  }
+
+  bool Compound_Selector::operator< (const Compound_Selector& rhs) const
+  {
+    size_t L = std::min(length(), rhs.length());
+    for (size_t i = 0; i < L; ++i)
+    {
+      Simple_Selector_Obj l = (*this)[i];
+      Simple_Selector_Obj r = rhs[i];
+      if (!l && !r) return false;
+      else if (!r) return false;
+      else if (!l) return true;
+      else if (*l != *r)
+      { return *l < *r; }
+    }
+    // just compare the length now
+    return length() < rhs.length();
+  }
+
+  bool Compound_Selector::has_parent_ref() const
+  {
+    for (Simple_Selector_Obj s : *this) {
+      if (s && s->has_parent_ref()) return true;
+    }
+    return false;
+  }
+
+  bool Compound_Selector::has_real_parent_ref() const
+  {
+    for (Simple_Selector_Obj s : *this) {
+      if (s && s->has_real_parent_ref()) return true;
+    }
+    return false;
+  }
+
+  bool Complex_Selector::has_parent_ref() const
+  {
+    return (head() && head()->has_parent_ref()) ||
+           (tail() && tail()->has_parent_ref());
+  }
+
+  bool Complex_Selector::has_real_parent_ref() const
+  {
+    return (head() && head()->has_real_parent_ref()) ||
+           (tail() && tail()->has_real_parent_ref());
+  }
+
+  bool Complex_Selector::operator< (const Complex_Selector& rhs) const
+  {
+    // const iterators for tails
+    Complex_Selector_Ptr_Const l = this;
+    Complex_Selector_Ptr_Const r = &rhs;
+    Compound_Selector_Ptr l_h = NULL;
+    Compound_Selector_Ptr r_h = NULL;
+    if (l) l_h = l->head();
+    if (r) r_h = r->head();
+    // process all tails
+    while (true)
+    {
+      #ifdef DEBUG
+      // skip empty ancestor first
+      if (l && l->is_empty_ancestor())
+      {
+        l_h = NULL;
+        l = l->tail();
+        if(l) l_h = l->head();
+        continue;
+      }
+      // skip empty ancestor first
+      if (r && r->is_empty_ancestor())
+      {
+        r_h = NULL;
+        r = r->tail();
+        if (r) r_h = r->head();
+        continue;
+      }
+      #endif
+      // check for valid selectors
+      if (!l) return !!r;
+      if (!r) return false;
+      // both are null
+      else if (!l_h && !r_h)
+      {
+        // check combinator after heads
+        if (l->combinator() != r->combinator())
+        { return l->combinator() < r->combinator(); }
+        // advance to next tails
+        l = l->tail();
+        r = r->tail();
+        // fetch the next headers
+        l_h = NULL; r_h = NULL;
+        if (l) l_h = l->head();
+        if (r) r_h = r->head();
+      }
+      // one side is null
+      else if (!r_h) return true;
+      else if (!l_h) return false;
+      // heads ok and equal
+      else if (*l_h == *r_h)
+      {
+        // check combinator after heads
+        if (l->combinator() != r->combinator())
+        { return l->combinator() < r->combinator(); }
+        // advance to next tails
+        l = l->tail();
+        r = r->tail();
+        // fetch the next headers
+        l_h = NULL; r_h = NULL;
+        if (l) l_h = l->head();
+        if (r) r_h = r->head();
+      }
+      // heads are not equal
+      else return *l_h < *r_h;
+    }
+  }
+
+  bool Complex_Selector::operator== (const Complex_Selector& rhs) const
+  {
+    // const iterators for tails
+    Complex_Selector_Ptr_Const l = this;
+    Complex_Selector_Ptr_Const r = &rhs;
+    Compound_Selector_Ptr l_h = NULL;
+    Compound_Selector_Ptr r_h = NULL;
+    if (l) l_h = l->head();
+    if (r) r_h = r->head();
+    // process all tails
+    while (true)
+    {
+      #ifdef DEBUG
+      // skip empty ancestor first
+      if (l && l->is_empty_ancestor())
+      {
+        l_h = NULL;
+        l = l->tail();
+        if (l) l_h = l->head();
+        continue;
+      }
+      // skip empty ancestor first
+      if (r && r->is_empty_ancestor())
+      {
+        r_h = NULL;
+        r = r->tail();
+        if (r) r_h = r->head();
+        continue;
+      }
+      #endif
+      // check the pointers
+      if (!r) return !l;
+      if (!l) return !r;
+      // both are null
+      if (!l_h && !r_h)
+      {
+        // check combinator after heads
+        if (l->combinator() != r->combinator())
+        { return l->combinator() < r->combinator(); }
+        // advance to next tails
+        l = l->tail();
+        r = r->tail();
+        // fetch the next heads
+        l_h = NULL; r_h = NULL;
+        if (l) l_h = l->head();
+        if (r) r_h = r->head();
+      }
+      // equals if other head is empty
+      else if ((!l_h && !r_h) ||
+               (!l_h && r_h->empty()) ||
+               (!r_h && l_h->empty()) ||
+               (l_h && r_h && *l_h == *r_h))
+      {
+        // check combinator after heads
+        if (l->combinator() != r->combinator())
+        { return l->combinator() == r->combinator(); }
+        // advance to next tails
+        l = l->tail();
+        r = r->tail();
+        // fetch the next heads
+        l_h = NULL; r_h = NULL;
+        if (l) l_h = l->head();
+        if (r) r_h = r->head();
+      }
+      // abort
+      else break;
+    }
+    // unreachable
+    return false;
+  }
+
+  Compound_Selector_Ptr Compound_Selector::unify_with(Compound_Selector_Ptr rhs)
+  {
+    if (empty()) return rhs;
+    Compound_Selector_Obj unified = SASS_MEMORY_COPY(rhs);
+    for (size_t i = 0, L = length(); i < L; ++i)
+    {
+      if (unified.isNull()) break;
+      unified = at(i)->unify_with(unified);
+    }
+    return unified.detach();
+  }
+
+  bool Complex_Selector::operator== (const Selector& rhs) const
+  {
+    if (const Selector_List* sl = Cast<Selector_List>(&rhs)) return *this == *sl;
+    if (const Simple_Selector* sp = Cast<Simple_Selector>(&rhs)) return *this == *sp;
+    if (const Complex_Selector* cs = Cast<Complex_Selector>(&rhs)) return *this == *cs;
+    if (const Compound_Selector* ch = Cast<Compound_Selector>(&rhs)) return *this == *ch;
+    throw std::runtime_error("invalid selector base classes to compare");
+  }
+
+
+  bool Complex_Selector::operator< (const Selector& rhs) const
+  {
+    if (const Selector_List* sl = Cast<Selector_List>(&rhs)) return *this < *sl;
+    if (const Simple_Selector* sp = Cast<Simple_Selector>(&rhs)) return *this < *sp;
+    if (const Complex_Selector* cs = Cast<Complex_Selector>(&rhs)) return *this < *cs;
+    if (const Compound_Selector* ch = Cast<Compound_Selector>(&rhs)) return *this < *ch;
+    throw std::runtime_error("invalid selector base classes to compare");
+  }
+
+  bool Compound_Selector::operator== (const Selector& rhs) const
+  {
+    if (const Selector_List* sl = Cast<Selector_List>(&rhs)) return *this == *sl;
+    if (const Simple_Selector* sp = Cast<Simple_Selector>(&rhs)) return *this == *sp;
+    if (const Complex_Selector* cs = Cast<Complex_Selector>(&rhs)) return *this == *cs;
+    if (const Compound_Selector* ch = Cast<Compound_Selector>(&rhs)) return *this == *ch;
+    throw std::runtime_error("invalid selector base classes to compare");
+  }
+
+  bool Compound_Selector::operator< (const Selector& rhs) const
+  {
+    if (const Selector_List* sl = Cast<Selector_List>(&rhs)) return *this < *sl;
+    if (const Simple_Selector* sp = Cast<Simple_Selector>(&rhs)) return *this < *sp;
+    if (const Complex_Selector* cs = Cast<Complex_Selector>(&rhs)) return *this < *cs;
+    if (const Compound_Selector* ch = Cast<Compound_Selector>(&rhs)) return *this < *ch;
+    throw std::runtime_error("invalid selector base classes to compare");
+  }
+
+  bool Selector_Schema::operator== (const Selector& rhs) const
+  {
+    if (const Selector_List* sl = Cast<Selector_List>(&rhs)) return *this == *sl;
+    if (const Simple_Selector* sp = Cast<Simple_Selector>(&rhs)) return *this == *sp;
+    if (const Complex_Selector* cs = Cast<Complex_Selector>(&rhs)) return *this == *cs;
+    if (const Compound_Selector* ch = Cast<Compound_Selector>(&rhs)) return *this == *ch;
+    throw std::runtime_error("invalid selector base classes to compare");
+  }
+
+  bool Selector_Schema::operator< (const Selector& rhs) const
+  {
+    if (const Selector_List* sl = Cast<Selector_List>(&rhs)) return *this < *sl;
+    if (const Simple_Selector* sp = Cast<Simple_Selector>(&rhs)) return *this < *sp;
+    if (const Complex_Selector* cs = Cast<Complex_Selector>(&rhs)) return *this < *cs;
+    if (const Compound_Selector* ch = Cast<Compound_Selector>(&rhs)) return *this < *ch;
+    throw std::runtime_error("invalid selector base classes to compare");
+  }
+
+  bool Simple_Selector::operator== (const Selector& rhs) const
+  {
+    if (Simple_Selector_Ptr_Const sp = Cast<Simple_Selector>(&rhs)) return *this == *sp;
+    return false;
+  }
+
+  bool Simple_Selector::operator< (const Selector& rhs) const
+  {
+    if (Simple_Selector_Ptr_Const sp = Cast<Simple_Selector>(&rhs)) return *this < *sp;
+    return false;
+  }
+
+  bool Simple_Selector::operator== (const Simple_Selector& rhs) const
+  {
+    // solve the double dispatch problem by using RTTI information via dynamic cast
+    if (const Pseudo_Selector* lhs = Cast<Pseudo_Selector>(this)) {return *lhs == rhs; }
+    else if (const Wrapped_Selector* lhs = Cast<Wrapped_Selector>(this)) {return *lhs == rhs; }
+    else if (const Element_Selector* lhs = Cast<Element_Selector>(this)) {return *lhs == rhs; }
+    else if (const Attribute_Selector* lhs = Cast<Attribute_Selector>(this)) {return *lhs == rhs; }
+    else if (name_ == rhs.name_)
+    { return is_ns_eq(rhs); }
+    else return false;
+  }
+
+  bool Simple_Selector::operator< (const Simple_Selector& rhs) const
+  {
+    // solve the double dispatch problem by using RTTI information via dynamic cast
+    if (const Pseudo_Selector* lhs = Cast<Pseudo_Selector>(this)) {return *lhs < rhs; }
+    else if (const Wrapped_Selector* lhs = Cast<Wrapped_Selector>(this)) {return *lhs < rhs; }
+    else if (const Element_Selector* lhs = Cast<Element_Selector>(this)) {return *lhs < rhs; }
+    else if (const Attribute_Selector* lhs = Cast<Attribute_Selector>(this)) {return *lhs < rhs; }
+    if (is_ns_eq(rhs))
+    { return name_ < rhs.name_; }
+    return ns_ < rhs.ns_;
+  }
+
+  bool Selector_List::operator== (const Selector& rhs) const
+  {
+    // solve the double dispatch problem by using RTTI information via dynamic cast
+    if (Selector_List_Ptr_Const sl = Cast<Selector_List>(&rhs)) { return *this == *sl; }
+    else if (Complex_Selector_Ptr_Const cpx = Cast<Complex_Selector>(&rhs)) { return *this == *cpx; }
+    else if (Compound_Selector_Ptr_Const cpd = Cast<Compound_Selector>(&rhs)) { return *this == *cpd; }
+    // no compare method
+    return this == &rhs;
+  }
+
+  // Selector lists can be compared to comma lists
+  bool Selector_List::operator== (const Expression& rhs) const
+  {
+    // solve the double dispatch problem by using RTTI information via dynamic cast
+    if (List_Ptr_Const ls = Cast<List>(&rhs)) { return *ls == *this; }
+    if (Selector_Ptr_Const ls = Cast<Selector>(&rhs)) { return *this == *ls; }
+    // compare invalid (maybe we should error?)
+    return false;
+  }
+
+  bool Selector_List::operator== (const Selector_List& rhs) const
+  {
+    // for array access
+    size_t i = 0, n = 0;
+    size_t iL = length();
+    size_t nL = rhs.length();
+    // create temporary vectors and sort them
+    std::vector<Complex_Selector_Obj> l_lst = this->elements();
+    std::vector<Complex_Selector_Obj> r_lst = rhs.elements();
+    std::sort(l_lst.begin(), l_lst.end(), OrderNodes());
+    std::sort(r_lst.begin(), r_lst.end(), OrderNodes());
+    // process loop
+    while (true)
+    {
+      // first check for valid index
+      if (i == iL) return iL == nL;
+      else if (n == nL) return iL == nL;
+      // the access the vector items
+      Complex_Selector_Obj l = l_lst[i];
+      Complex_Selector_Obj r = r_lst[n];
+      // skip nulls
+      if (!l) ++i;
+      else if (!r) ++n;
+      // do the check
+      else if (*l != *r)
+      { return false; }
+      // advance
+      ++i; ++n;
+    }
+    // there is no break?!
+  }
+
+  bool Selector_List::operator< (const Selector& rhs) const
+  {
+    if (Selector_List_Ptr_Const sp = Cast<Selector_List>(&rhs)) return *this < *sp;
+    return false;
+  }
+
+  bool Selector_List::operator< (const Selector_List& rhs) const
+  {
+    size_t l = rhs.length();
+    if (length() < l) l = length();
+    for (size_t i = 0; i < l; i ++) {
+      if (*at(i) < *rhs.at(i)) return true;
+    }
+    return false;
+  }
+
+  Compound_Selector_Ptr Simple_Selector::unify_with(Compound_Selector_Ptr rhs)
+  {
+    for (size_t i = 0, L = rhs->length(); i < L; ++i)
+    { if (to_string() == rhs->at(i)->to_string()) return rhs; }
+
+    // check for pseudo elements because they are always last
+    size_t i, L;
+    bool found = false;
+    if (typeid(*this) == typeid(Pseudo_Selector) || typeid(*this) == typeid(Wrapped_Selector) || typeid(*this) == typeid(Attribute_Selector))
+    {
+      for (i = 0, L = rhs->length(); i < L; ++i)
+      {
+        if ((Cast<Pseudo_Selector>((*rhs)[i]) || Cast<Wrapped_Selector>((*rhs)[i]) || Cast<Attribute_Selector>((*rhs)[i])) && (*rhs)[L-1]->is_pseudo_element())
+        { found = true; break; }
+      }
+    }
+    else
+    {
+      for (i = 0, L = rhs->length(); i < L; ++i)
+      {
+        if (Cast<Pseudo_Selector>((*rhs)[i]) || Cast<Wrapped_Selector>((*rhs)[i]) || Cast<Attribute_Selector>((*rhs)[i]))
+        { found = true; break; }
+      }
+    }
+    if (!found)
+    {
+      rhs->append(this);
+    } else {
+      rhs->elements().insert(rhs->elements().begin() + i, this);
+    }
+    return rhs;
+  }
+
+  Simple_Selector_Ptr Element_Selector::unify_with(Simple_Selector_Ptr rhs)
+  {
+    // check if ns can be extended
+    // true for no ns or universal
+    if (has_universal_ns())
+    {
+      // but dont extend with universal
+      // true for valid ns and universal
+      if (!rhs->is_universal_ns())
+      {
+        // overwrite the name if star is given as name
+        if (this->name() == "*") { this->name(rhs->name()); }
+        // now overwrite the namespace name and flag
+        this->ns(rhs->ns()); this->has_ns(rhs->has_ns());
+        // return copy
+        return this;
+      }
+    }
+    // namespace may changed, check the name now
+    // overwrite star (but not with another star)
+    if (name() == "*" && rhs->name() != "*")
+    {
+      // simply set the new name
+      this->name(rhs->name());
+      // return copy
+      return this;
+    }
+    // return original
+    return this;
+  }
+
+  Compound_Selector_Ptr Element_Selector::unify_with(Compound_Selector_Ptr rhs)
+  {
+    // TODO: handle namespaces
+
+    // if the rhs is empty, just return a copy of this
+    if (rhs->length() == 0) {
+      rhs->append(this);
+      return rhs;
+    }
+
+    Simple_Selector_Ptr rhs_0 = rhs->at(0);
+    // otherwise, this is a tag name
+    if (name() == "*")
+    {
+      if (typeid(*rhs_0) == typeid(Element_Selector))
+      {
+        // if rhs is universal, just return this tagname + rhs's qualifiers
+        Element_Selector_Ptr ts = Cast<Element_Selector>(rhs_0);
+        rhs->at(0) = this->unify_with(ts);
+        return rhs;
+      }
+      else if (Cast<Class_Selector>(rhs_0) || Cast<Id_Selector>(rhs_0)) {
+        // qualifier is `.class`, so we can prefix with `ns|*.class`
+        if (has_ns() && !rhs_0->has_ns()) {
+          if (ns() != "*") rhs->elements().insert(rhs->begin(), this);
+        }
+        return rhs;
+      }
+
+
+      return rhs;
+    }
+
+    if (typeid(*rhs_0) == typeid(Element_Selector))
+    {
+      // if rhs is universal, just return this tagname + rhs's qualifiers
+      if (rhs_0->name() != "*" && rhs_0->ns() != "*" && rhs_0->name() != name()) return 0;
+      // otherwise create new compound and unify first simple selector
+      rhs->at(0) = this->unify_with(rhs_0);
+      return rhs;
+
+    }
+    // else it's a tag name and a bunch of qualifiers -- just append them
+    if (name() != "*") rhs->elements().insert(rhs->begin(), this);
+    return rhs;
+  }
+
+  Compound_Selector_Ptr Class_Selector::unify_with(Compound_Selector_Ptr rhs)
+  {
+    rhs->has_line_break(has_line_break());
+    return Simple_Selector::unify_with(rhs);
+  }
+
+  Compound_Selector_Ptr Id_Selector::unify_with(Compound_Selector_Ptr rhs)
+  {
+    for (size_t i = 0, L = rhs->length(); i < L; ++i)
+    {
+      if (Id_Selector_Ptr sel = Cast<Id_Selector>(rhs->at(i))) {
+        if (sel->name() != name()) return 0;
+      }
+    }
+    rhs->has_line_break(has_line_break());
+    return Simple_Selector::unify_with(rhs);
+  }
+
+  Compound_Selector_Ptr Pseudo_Selector::unify_with(Compound_Selector_Ptr rhs)
+  {
+    if (is_pseudo_element())
+    {
+      for (size_t i = 0, L = rhs->length(); i < L; ++i)
+      {
+        if (Pseudo_Selector_Ptr sel = Cast<Pseudo_Selector>(rhs->at(i))) {
+          if (sel->is_pseudo_element() && sel->name() != name()) return 0;
+        }
+      }
+    }
+    return Simple_Selector::unify_with(rhs);
+  }
+
+  bool Attribute_Selector::operator< (const Attribute_Selector& rhs) const
+  {
+    if (is_ns_eq(rhs)) {
+      if (name() == rhs.name()) {
+        if (matcher() == rhs.matcher()) {
+          bool no_lhs_val = value().isNull();
+          bool no_rhs_val = rhs.value().isNull();
+          if (no_lhs_val && no_rhs_val) return false; // equal
+          else if (no_lhs_val) return true; // lhs is null
+          else if (no_rhs_val) return false; // rhs is null
+          return *value() < *rhs.value(); // both are given
+        } else { return matcher() < rhs.matcher(); }
+      } else { return name() < rhs.name(); }
+    } else { return ns() < rhs.ns(); }
+  }
+
+  bool Attribute_Selector::operator< (const Simple_Selector& rhs) const
+  {
+    if (Attribute_Selector_Ptr_Const w = Cast<Attribute_Selector>(&rhs))
+    {
+      return *this < *w;
+    }
+    if (is_ns_eq(rhs))
+    { return name() < rhs.name(); }
+    return ns() < rhs.ns();
+  }
+
+  bool Attribute_Selector::operator== (const Attribute_Selector& rhs) const
+  {
+    // get optional value state
+    bool no_lhs_val = value().isNull();
+    bool no_rhs_val = rhs.value().isNull();
+    // both are null, therefore equal
+    if (no_lhs_val && no_rhs_val) {
+      return (name() == rhs.name())
+        && (matcher() == rhs.matcher())
+        && (is_ns_eq(rhs));
+    }
+    // both are defined, evaluate
+    if (no_lhs_val == no_rhs_val) {
+      return (name() == rhs.name())
+        && (matcher() == rhs.matcher())
+        && (is_ns_eq(rhs))
+        && (*value() == *rhs.value());
+    }
+    // not equal
+    return false;
+
+  }
+
+  bool Attribute_Selector::operator== (const Simple_Selector& rhs) const
+  {
+    if (Attribute_Selector_Ptr_Const w = Cast<Attribute_Selector>(&rhs))
+    {
+      return is_ns_eq(rhs) &&
+             name() == rhs.name() &&
+             *this == *w;
+    }
+    return false;
+  }
+
+  bool Element_Selector::operator< (const Element_Selector& rhs) const
+  {
+    if (is_ns_eq(rhs))
+    { return name() < rhs.name(); }
+    return ns() < rhs.ns();
+  }
+
+  bool Element_Selector::operator< (const Simple_Selector& rhs) const
+  {
+    if (Element_Selector_Ptr_Const w = Cast<Element_Selector>(&rhs))
+    {
+      return *this < *w;
+    }
+    if (is_ns_eq(rhs))
+    { return name() < rhs.name(); }
+    return ns() < rhs.ns();
+  }
+
+  bool Element_Selector::operator== (const Element_Selector& rhs) const
+  {
+    return is_ns_eq(rhs) &&
+           name() == rhs.name();
+  }
+
+  bool Element_Selector::operator== (const Simple_Selector& rhs) const
+  {
+    if (Element_Selector_Ptr_Const w = Cast<Element_Selector>(&rhs))
+    {
+      return is_ns_eq(rhs) &&
+             name() == rhs.name() &&
+             *this == *w;
+    }
+    return false;
+  }
+
+  bool Pseudo_Selector::operator== (const Pseudo_Selector& rhs) const
+  {
+    if (is_ns_eq(rhs) && name() == rhs.name())
+    {
+      String_Obj lhs_ex = expression();
+      String_Obj rhs_ex = rhs.expression();
+      if (rhs_ex && lhs_ex) return *lhs_ex == *rhs_ex;
+      else return lhs_ex.ptr() == rhs_ex.ptr();
+    }
+    else return false;
+  }
+
+  bool Pseudo_Selector::operator== (const Simple_Selector& rhs) const
+  {
+    if (Pseudo_Selector_Ptr_Const w = Cast<Pseudo_Selector>(&rhs))
+    {
+      return *this == *w;
+    }
+    return is_ns_eq(rhs) &&
+           name() == rhs.name();
+  }
+
+  bool Pseudo_Selector::operator< (const Pseudo_Selector& rhs) const
+  {
+    if (is_ns_eq(rhs) && name() == rhs.name())
+    {
+      String_Obj lhs_ex = expression();
+      String_Obj rhs_ex = rhs.expression();
+      if (rhs_ex && lhs_ex) return *lhs_ex < *rhs_ex;
+      else return lhs_ex.ptr() < rhs_ex.ptr();
+    }
+    if (is_ns_eq(rhs))
+    { return name() < rhs.name(); }
+    return ns() < rhs.ns();
+  }
+
+  bool Pseudo_Selector::operator< (const Simple_Selector& rhs) const
+  {
+    if (Pseudo_Selector_Ptr_Const w = Cast<Pseudo_Selector>(&rhs))
+    {
+      return *this < *w;
+    }
+    if (is_ns_eq(rhs))
+    { return name() < rhs.name(); }
+    return ns() < rhs.ns();
+  }
+
+  bool Wrapped_Selector::operator== (const Wrapped_Selector& rhs) const
+  {
+    if (is_ns_eq(rhs) && name() == rhs.name())
+    { return *(selector()) == *(rhs.selector()); }
+    else return false;
+  }
+
+  bool Wrapped_Selector::operator== (const Simple_Selector& rhs) const
+  {
+    if (Wrapped_Selector_Ptr_Const w = Cast<Wrapped_Selector>(&rhs))
+    {
+      return *this == *w;
+    }
+    return is_ns_eq(rhs) &&
+           name() == rhs.name();
+  }
+
+  bool Wrapped_Selector::operator< (const Wrapped_Selector& rhs) const
+  {
+    if (is_ns_eq(rhs) && name() == rhs.name())
+    { return *(selector()) < *(rhs.selector()); }
+    if (is_ns_eq(rhs))
+    { return name() < rhs.name(); }
+    return ns() < rhs.ns();
+  }
+
+  bool Wrapped_Selector::operator< (const Simple_Selector& rhs) const
+  {
+    if (Wrapped_Selector_Ptr_Const w = Cast<Wrapped_Selector>(&rhs))
+    {
+      return *this < *w;
+    }
+    if (is_ns_eq(rhs))
+    { return name() < rhs.name(); }
+    return ns() < rhs.ns();
+  }
+
+  bool Wrapped_Selector::is_superselector_of(Wrapped_Selector_Obj sub)
+  {
+    if (this->name() != sub->name()) return false;
+    if (this->name() == ":current") return false;
+    if (Selector_List_Obj rhs_list = Cast<Selector_List>(sub->selector())) {
+      if (Selector_List_Obj lhs_list = Cast<Selector_List>(selector())) {
+        return lhs_list->is_superselector_of(rhs_list);
+      }
+    }
+    coreError("is_superselector expected a Selector_List", sub->pstate());
+    return false;
+  }
+
+  bool Compound_Selector::is_superselector_of(Selector_List_Obj rhs, std::string wrapped)
+  {
+    for (Complex_Selector_Obj item : rhs->elements()) {
+      if (is_superselector_of(item, wrapped)) return true;
+    }
+    return false;
+  }
+
+  bool Compound_Selector::is_superselector_of(Complex_Selector_Obj rhs, std::string wrapped)
+  {
+    if (rhs->head()) return is_superselector_of(rhs->head(), wrapped);
+    return false;
+  }
+
+  bool Compound_Selector::is_superselector_of(Compound_Selector_Obj rhs, std::string wrapping)
+  {
+    Compound_Selector_Ptr lhs = this;
+    Simple_Selector_Ptr lbase = lhs->base();
+    Simple_Selector_Ptr rbase = rhs->base();
+
+    // Check if pseudo-elements are the same between the selectors
+
+    std::set<std::string> lpsuedoset, rpsuedoset;
+    for (size_t i = 0, L = length(); i < L; ++i)
+    {
+      if ((*this)[i]->is_pseudo_element()) {
+        std::string pseudo((*this)[i]->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);
+      }
+    }
+    for (size_t i = 0, L = rhs->length(); i < L; ++i)
+    {
+      if ((*rhs)[i]->is_pseudo_element()) {
+        std::string pseudo((*rhs)[i]->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);
+      }
+    }
+    if (lpsuedoset != rpsuedoset) {
+      return false;
+    }
+
+    // would like to replace this without stringification
+    // https://github.com/sass/sass/issues/2229
+    // SimpleSelectorSet lset, rset;
+    std::set<std::string> lset, rset;
+
+    if (lbase && rbase)
+    {
+      if (lbase->to_string() == rbase->to_string()) {
+        for (size_t i = 1, L = length(); i < L; ++i)
+        { lset.insert((*this)[i]->to_string()); }
+        for (size_t i = 1, L = rhs->length(); i < L; ++i)
+        { rset.insert((*rhs)[i]->to_string()); }
+        return includes(rset.begin(), rset.end(), lset.begin(), lset.end());
+      }
+      return false;
+    }
+
+    for (size_t i = 0, iL = length(); i < iL; ++i)
+    {
+      Selector_Obj wlhs = (*this)[i];
+      // very special case for wrapped matches selector
+      if (Wrapped_Selector_Obj wrapped = Cast<Wrapped_Selector>(wlhs)) {
+        if (wrapped->name() == ":not") {
+          if (Selector_List_Obj not_list = Cast<Selector_List>(wrapped->selector())) {
+            if (not_list->is_superselector_of(rhs, wrapped->name())) return false;
+          } else {
+            throw std::runtime_error("wrapped not selector is not a list");
+          }
+        }
+        if (wrapped->name() == ":matches" || wrapped->name() == ":-moz-any") {
+          wlhs = wrapped->selector();
+          if (Selector_List_Obj list = Cast<Selector_List>(wrapped->selector())) {
+            if (Compound_Selector_Obj comp = Cast<Compound_Selector>(rhs)) {
+              if (!wrapping.empty() && wrapping != wrapped->name()) return false;
+              if (wrapping.empty() || wrapping != wrapped->name()) {;
+                if (list->is_superselector_of(comp, wrapped->name())) return true;
+              }
+            }
+          }
+        }
+        Simple_Selector_Ptr rhs_sel = NULL;
+        if (rhs->elements().size() > i) rhs_sel = (*rhs)[i];
+        if (Wrapped_Selector_Ptr wrapped_r = Cast<Wrapped_Selector>(rhs_sel)) {
+          if (wrapped->name() == wrapped_r->name()) {
+          if (wrapped->is_superselector_of(wrapped_r)) {
+             continue;
+          }}
+        }
+      }
+      // match from here on as strings
+      lset.insert(wlhs->to_string());
+    }
+
+    for (size_t n = 0, nL = rhs->length(); n < nL; ++n)
+    {
+      Selector_Obj r = (*rhs)[n];
+      if (Wrapped_Selector_Obj wrapped = Cast<Wrapped_Selector>(r)) {
+        if (wrapped->name() == ":not") {
+          if (Selector_List_Obj ls = Cast<Selector_List>(wrapped->selector())) {
+            ls->remove_parent_selectors();
+            if (is_superselector_of(ls, wrapped->name())) return false;
+          }
+        }
+        if (wrapped->name() == ":matches" || wrapped->name() == ":-moz-any") {
+          if (!wrapping.empty()) {
+            if (wrapping != wrapped->name()) return false;
+          }
+          if (Selector_List_Obj ls = Cast<Selector_List>(wrapped->selector())) {
+            ls->remove_parent_selectors();
+            return (is_superselector_of(ls, wrapped->name()));
+          }
+        }
+      }
+      rset.insert(r->to_string());
+    }
+
+    //for (auto l : lset) { cerr << "l: " << l << endl; }
+    //for (auto r : rset) { cerr << "r: " << r << endl; }
+
+    if (lset.empty()) return true;
+    // return true if rset contains all the elements of lset
+    return includes(rset.begin(), rset.end(), lset.begin(), lset.end());
+
+  }
+
+  // create complex selector (ancestor of) from compound selector
+  Complex_Selector_Obj Compound_Selector::to_complex()
+  {
+    // create an intermediate complex selector
+    return SASS_MEMORY_NEW(Complex_Selector,
+                           pstate(),
+                           Complex_Selector::ANCESTOR_OF,
+                           this,
+                           0);
+  }
+
+  Selector_List_Ptr Complex_Selector::unify_with(Complex_Selector_Ptr other)
+  {
+
+    // get last tails (on the right side)
+    Complex_Selector_Obj l_last = this->last();
+    Complex_Selector_Obj r_last = other->last();
+
+    // check valid pointers (assertion)
+    SASS_ASSERT(l_last, "lhs is null");
+    SASS_ASSERT(r_last, "rhs is null");
+
+    // Not sure about this check, but closest way I could check
+    // was to see if this is a ruby 'SimpleSequence' equivalent.
+    // It seems to do the job correctly as some specs react to this
+    if (l_last->combinator() != Combinator::ANCESTOR_OF) return 0;
+    if (r_last->combinator() != Combinator::ANCESTOR_OF ) return 0;
+
+    // get the headers for the last tails
+    Compound_Selector_Obj l_last_head = l_last->head();
+    Compound_Selector_Obj r_last_head = r_last->head();
+
+    // check valid head pointers (assertion)
+    SASS_ASSERT(l_last_head, "lhs head is null");
+    SASS_ASSERT(r_last_head, "rhs head is null");
+
+    // get the unification of the last compound selectors
+    Compound_Selector_Obj unified = r_last_head->unify_with(l_last_head);
+
+    // abort if we could not unify heads
+    if (unified == 0) return 0;
+
+    // check for universal (star: `*`) selector
+    bool is_universal = l_last_head->is_universal() ||
+                        r_last_head->is_universal();
+
+    if (is_universal)
+    {
+      // move the head
+      l_last->head(0);
+      r_last->head(unified);
+    }
+
+    // create nodes from both selectors
+    Node lhsNode = complexSelectorToNode(this);
+    Node rhsNode = complexSelectorToNode(other);
+
+    // overwrite universal base
+    if (!is_universal)
+    {
+      // create some temporaries to convert to node
+      Complex_Selector_Obj fake = unified->to_complex();
+      Node unified_node = complexSelectorToNode(fake);
+      // add to permutate the list?
+      rhsNode.plus(unified_node);
+    }
+
+    // do some magic we inherit from node and extend
+    Node node = subweave(lhsNode, rhsNode);
+    Selector_List_Obj result = SASS_MEMORY_NEW(Selector_List, pstate());
+    NodeDequePtr col = node.collection(); // move from collection to list
+    for (NodeDeque::iterator it = col->begin(), end = col->end(); it != end; it++)
+    { result->append(nodeToComplexSelector(Node::naiveTrim(*it))); }
+
+    // only return if list has some entries
+    return result->length() ? result.detach() : 0;
+
+  }
+
+  bool Compound_Selector::operator== (const Compound_Selector& rhs) const
+  {
+    // for array access
+    size_t i = 0, n = 0;
+    size_t iL = length();
+    size_t nL = rhs.length();
+    // create temporary vectors and sort them
+    std::vector<Simple_Selector_Obj> l_lst = this->elements();
+    std::vector<Simple_Selector_Obj> r_lst = rhs.elements();
+    std::sort(l_lst.begin(), l_lst.end(), OrderNodes());
+    std::sort(r_lst.begin(), r_lst.end(), OrderNodes());
+    // process loop
+    while (true)
+    {
+      // first check for valid index
+      if (i == iL) return iL == nL;
+      else if (n == nL) return iL == nL;
+      // the access the vector items
+      Simple_Selector_Obj l = l_lst[i];
+      Simple_Selector_Obj r = r_lst[n];
+      // skip nulls
+      if (!l) ++i;
+      if (!r) ++n;
+      // do the check now
+      else if (*l != *r)
+      { return false; }
+      // advance now
+      ++i; ++n;
+    }
+    // there is no break?!
+  }
+
+  bool Complex_Selector::is_superselector_of(Compound_Selector_Obj rhs, std::string wrapping)
+  {
+    return last()->head() && last()->head()->is_superselector_of(rhs, wrapping);
+  }
+
+  bool Complex_Selector::is_superselector_of(Complex_Selector_Obj rhs, std::string wrapping)
+  {
+    Complex_Selector_Ptr lhs = this;
+    // check for selectors with leading or trailing combinators
+    if (!lhs->head() || !rhs->head())
+    { return false; }
+    Complex_Selector_Obj l_innermost = lhs->innermost();
+    if (l_innermost->combinator() != Complex_Selector::ANCESTOR_OF)
+    { return false; }
+    Complex_Selector_Obj r_innermost = rhs->innermost();
+    if (r_innermost->combinator() != Complex_Selector::ANCESTOR_OF)
+    { return false; }
+    // more complex (i.e., longer) selectors are always more specific
+    size_t l_len = lhs->length(), r_len = rhs->length();
+    if (l_len > r_len)
+    { return false; }
+
+    if (l_len == 1)
+    { return lhs->head()->is_superselector_of(rhs->last()->head(), wrapping); }
+
+    // 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_Obj lhs_tail = lhs->tail();
+      Complex_Selector_Obj rhs_tail = rhs->tail();
+      if (lhs_tail->combinator() != rhs_tail->combinator()) return false;
+      if (lhs_tail->head() && !rhs_tail->head()) return false;
+      if (!lhs_tail->head() && rhs_tail->head()) return false;
+      if (lhs_tail->head() && rhs_tail->head()) {
+        if (!lhs_tail->head()->is_superselector_of(rhs_tail->head())) return false;
+      }
+    }
+
+    bool found = false;
+    Complex_Selector_Obj marker = rhs;
+    for (size_t i = 0, L = rhs->length(); i < L; ++i) {
+      if (i == L-1)
+      { return false; }
+      if (lhs->head() && marker->head() && lhs->head()->is_superselector_of(marker->head(), wrapping))
+      { found = true; break; }
+      marker = marker->tail();
+    }
+    if (!found)
+    { return false; }
+
+    /*
+      Hmm, I hope I have the logic right:
+
+      if lhs has a combinator:
+        if !(marker has a combinator) return false
+        if !(lhs.combinator == '~' ? marker.combinator != '>' : lhs.combinator == marker.combinator) return false
+        return lhs.tail-without-innermost.is_superselector_of(marker.tail-without-innermost)
+      else if marker has a combinator:
+        if !(marker.combinator == ">") return false
+        return lhs.tail.is_superselector_of(marker.tail)
+      else
+        return lhs.tail.is_superselector_of(marker.tail)
+    */
+    if (lhs->combinator() != Complex_Selector::ANCESTOR_OF)
+    {
+      if (marker->combinator() == Complex_Selector::ANCESTOR_OF)
+      { return false; }
+      if (!(lhs->combinator() == Complex_Selector::PRECEDES ? marker->combinator() != Complex_Selector::PARENT_OF : lhs->combinator() == marker->combinator()))
+      { return false; }
+      return lhs->tail()->is_superselector_of(marker->tail());
+    }
+    else if (marker->combinator() != Complex_Selector::ANCESTOR_OF)
+    {
+      if (marker->combinator() != Complex_Selector::PARENT_OF)
+      { return false; }
+      return lhs->tail()->is_superselector_of(marker->tail());
+    }
+    return lhs->tail()->is_superselector_of(marker->tail());
+  }
+
+  size_t Complex_Selector::length() const
+  {
+    // TODO: make this iterative
+    if (!tail()) return 1;
+    return 1 + tail()->length();
+  }
+
+  // append another complex selector at the end
+  // check if we need to append some headers
+  // then we need to check for the combinator
+  // only then we can safely set the new tail
+  void Complex_Selector::append(Complex_Selector_Obj ss, Backtraces& traces)
+  {
+
+    Complex_Selector_Obj t = ss->tail();
+    Combinator c = ss->combinator();
+    String_Obj r = ss->reference();
+    Compound_Selector_Obj h = ss->head();
+
+    if (ss->has_line_feed()) has_line_feed(true);
+    if (ss->has_line_break()) has_line_break(true);
+
+    // append old headers
+    if (h && h->length()) {
+      if (last()->combinator() != ANCESTOR_OF && c != ANCESTOR_OF) {
+        traces.push_back(Backtrace(pstate()));
+        throw Exception::InvalidParent(this, traces, ss);
+      } else if (last()->head_ && last()->head_->length()) {
+        Compound_Selector_Obj rh = last()->head();
+        size_t i;
+        size_t L = h->length();
+        if (Cast<Element_Selector>(h->first())) {
+          if (Class_Selector_Ptr cs = Cast<Class_Selector>(rh->last())) {
+            Class_Selector_Ptr sqs = SASS_MEMORY_COPY(cs);
+            sqs->name(sqs->name() + (*h)[0]->name());
+            sqs->pstate((*h)[0]->pstate());
+            (*rh)[rh->length()-1] = sqs;
+            rh->pstate(h->pstate());
+            for (i = 1; i < L; ++i) rh->append((*h)[i]);
+          } else if (Id_Selector_Ptr is = Cast<Id_Selector>(rh->last())) {
+            Id_Selector_Ptr sqs = SASS_MEMORY_COPY(is);
+            sqs->name(sqs->name() + (*h)[0]->name());
+            sqs->pstate((*h)[0]->pstate());
+            (*rh)[rh->length()-1] = sqs;
+            rh->pstate(h->pstate());
+            for (i = 1; i < L; ++i) rh->append((*h)[i]);
+          } else if (Element_Selector_Ptr ts = Cast<Element_Selector>(rh->last())) {
+            Element_Selector_Ptr tss = SASS_MEMORY_COPY(ts);
+            tss->name(tss->name() + (*h)[0]->name());
+            tss->pstate((*h)[0]->pstate());
+            (*rh)[rh->length()-1] = tss;
+            rh->pstate(h->pstate());
+            for (i = 1; i < L; ++i) rh->append((*h)[i]);
+          } else if (Placeholder_Selector_Ptr ps = Cast<Placeholder_Selector>(rh->last())) {
+            Placeholder_Selector_Ptr pss = SASS_MEMORY_COPY(ps);
+            pss->name(pss->name() + (*h)[0]->name());
+            pss->pstate((*h)[0]->pstate());
+            (*rh)[rh->length()-1] = pss;
+            rh->pstate(h->pstate());
+            for (i = 1; i < L; ++i) rh->append((*h)[i]);
+          } else {
+            last()->head_->concat(h);
+          }
+        } else {
+          last()->head_->concat(h);
+        }
+      } else if (last()->head_) {
+        last()->head_->concat(h);
+      }
+    } else {
+      // std::cerr << "has no or empty head\n";
+    }
+
+    if (last()) {
+      if (last()->combinator() != ANCESTOR_OF && c != ANCESTOR_OF) {
+        Complex_Selector_Ptr inter = SASS_MEMORY_NEW(Complex_Selector, pstate());
+        inter->reference(r);
+        inter->combinator(c);
+        inter->tail(t);
+        last()->tail(inter);
+      } else {
+        if (last()->combinator() == ANCESTOR_OF) {
+          last()->combinator(c);
+          last()->reference(r);
+        }
+        last()->tail(t);
+      }
+    }
+
+  }
+
+  Selector_List_Obj Selector_List::eval(Eval& eval)
+  {
+    Selector_List_Obj list = schema() ?
+      eval(schema()) : eval(this);
+    list->schema(schema());
+    return list;
+  }
+
+  Selector_List_Ptr Selector_List::resolve_parent_refs(std::vector<Selector_List_Obj>& pstack, Backtraces& traces, bool implicit_parent)
+  {
+    if (!this->has_parent_ref()) return this;
+    Selector_List_Ptr ss = SASS_MEMORY_NEW(Selector_List, pstate());
+    Selector_List_Ptr ps = pstack.back();
+    for (size_t pi = 0, pL = ps->length(); pi < pL; ++pi) {
+      for (size_t si = 0, sL = this->length(); si < sL; ++si) {
+        Selector_List_Obj rv = at(si)->resolve_parent_refs(pstack, traces, implicit_parent);
+        ss->concat(rv);
+      }
+    }
+    return ss;
+  }
+
+  Selector_List_Ptr Complex_Selector::resolve_parent_refs(std::vector<Selector_List_Obj>& pstack, Backtraces& traces, bool implicit_parent)
+  {
+    Complex_Selector_Obj tail = this->tail();
+    Compound_Selector_Obj head = this->head();
+    Selector_List_Ptr parents = pstack.back();
+
+    if (!this->has_real_parent_ref() && !implicit_parent) {
+      Selector_List_Ptr retval = SASS_MEMORY_NEW(Selector_List, pstate());
+      retval->append(this);
+      return retval;
+    }
+
+    // first resolve_parent_refs the tail (which may return an expanded list)
+    Selector_List_Obj tails = tail ? tail->resolve_parent_refs(pstack, traces, implicit_parent) : 0;
+
+    if (head && head->length() > 0) {
+
+      Selector_List_Obj retval;
+      // we have a parent selector in a simple compound list
+      // mix parent complex selector into the compound list
+      if (Cast<Parent_Selector>((*head)[0])) {
+        retval = SASS_MEMORY_NEW(Selector_List, pstate());
+
+        // it turns out that real parent references reach
+        // across @at-root rules, which comes unexpected
+        if (parents == NULL && head->has_real_parent_ref()) {
+          int i = pstack.size() - 1;
+          while (!parents && i > -1) {
+            parents = pstack.at(i--);
+          }
+        }
+
+        if (parents && parents->length()) {
+          if (tails && tails->length() > 0) {
+            for (size_t n = 0, nL = tails->length(); n < nL; ++n) {
+              for (size_t i = 0, iL = parents->length(); i < iL; ++i) {
+                Complex_Selector_Obj t = (*tails)[n];
+                Complex_Selector_Obj parent = (*parents)[i];
+                Complex_Selector_Obj s = SASS_MEMORY_CLONE(parent);
+                Complex_Selector_Obj ss = SASS_MEMORY_CLONE(this);
+                ss->tail(t ? SASS_MEMORY_CLONE(t) : NULL);
+                Compound_Selector_Obj h = SASS_MEMORY_COPY(head_);
+                // remove parent selector from sequence
+                if (h->length()) {
+                  h->erase(h->begin());
+                  ss->head(h);
+                } else {
+                  ss->head(NULL);
+                }
+                // adjust for parent selector (1 char)
+                // if (h->length()) {
+                //   ParserState state(h->at(0)->pstate());
+                //   state.offset.column += 1;
+                //   state.column -= 1;
+                //   (*h)[0]->pstate(state);
+                // }
+                // keep old parser state
+                s->pstate(pstate());
+                // append new tail
+                s->append(ss, traces);
+                retval->append(s);
+              }
+            }
+          }
+          // have no tails but parents
+          // loop above is inside out
+          else {
+            for (size_t i = 0, iL = parents->length(); i < iL; ++i) {
+              Complex_Selector_Obj parent = (*parents)[i];
+              Complex_Selector_Obj s = SASS_MEMORY_CLONE(parent);
+              Complex_Selector_Obj ss = SASS_MEMORY_CLONE(this);
+              // this is only if valid if the parent has no trailing op
+              // otherwise we cannot append more simple selectors to head
+              if (parent->last()->combinator() != ANCESTOR_OF) {
+                traces.push_back(Backtrace(pstate()));
+                throw Exception::InvalidParent(parent, traces, ss);
+              }
+              ss->tail(tail ? SASS_MEMORY_CLONE(tail) : NULL);
+              Compound_Selector_Obj h = SASS_MEMORY_COPY(head_);
+              // remove parent selector from sequence
+              if (h->length()) {
+                h->erase(h->begin());
+                ss->head(h);
+              } else {
+                ss->head(NULL);
+              }
+              // \/ IMO ruby sass bug \/
+              ss->has_line_feed(false);
+              // adjust for parent selector (1 char)
+              // if (h->length()) {
+              //   ParserState state(h->at(0)->pstate());
+              //   state.offset.column += 1;
+              //   state.column -= 1;
+              //   (*h)[0]->pstate(state);
+              // }
+              // keep old parser state
+              s->pstate(pstate());
+              // append new tail
+              s->append(ss, traces);
+              retval->append(s);
+            }
+          }
+        }
+        // have no parent but some tails
+        else {
+          if (tails && tails->length() > 0) {
+            for (size_t n = 0, nL = tails->length(); n < nL; ++n) {
+              Complex_Selector_Obj cpy = SASS_MEMORY_CLONE(this);
+              cpy->tail(SASS_MEMORY_CLONE(tails->at(n)));
+              cpy->head(SASS_MEMORY_NEW(Compound_Selector, head->pstate()));
+              for (size_t i = 1, L = this->head()->length(); i < L; ++i)
+                cpy->head()->append((*this->head())[i]);
+              if (!cpy->head()->length()) cpy->head(0);
+              retval->append(cpy->skip_empty_reference());
+            }
+          }
+          // have no parent nor tails
+          else {
+            Complex_Selector_Obj cpy = SASS_MEMORY_CLONE(this);
+            cpy->head(SASS_MEMORY_NEW(Compound_Selector, head->pstate()));
+            for (size_t i = 1, L = this->head()->length(); i < L; ++i)
+              cpy->head()->append((*this->head())[i]);
+            if (!cpy->head()->length()) cpy->head(0);
+            retval->append(cpy->skip_empty_reference());
+          }
+        }
+      }
+      // no parent selector in head
+      else {
+        retval = this->tails(tails);
+      }
+
+      for (Simple_Selector_Obj ss : head->elements()) {
+        if (Wrapped_Selector_Ptr ws = Cast<Wrapped_Selector>(ss)) {
+          if (Selector_List_Ptr sl = Cast<Selector_List>(ws->selector())) {
+            if (parents) ws->selector(sl->resolve_parent_refs(pstack, traces, implicit_parent));
+          }
+        }
+      }
+
+      return retval.detach();
+
+    }
+    // has no head
+    return this->tails(tails);
+  }
+
+  Selector_List_Ptr Complex_Selector::tails(Selector_List_Ptr tails)
+  {
+    Selector_List_Ptr rv = SASS_MEMORY_NEW(Selector_List, pstate_);
+    if (tails && tails->length()) {
+      for (size_t i = 0, iL = tails->length(); i < iL; ++i) {
+        Complex_Selector_Obj pr = SASS_MEMORY_CLONE(this);
+        pr->tail(tails->at(i));
+        rv->append(pr);
+      }
+    }
+    else {
+      rv->append(this);
+    }
+    return rv;
+  }
+
+  // return the last tail that is defined
+  Complex_Selector_Obj Complex_Selector::first()
+  {
+    // declare variables used in loop
+    Complex_Selector_Obj cur = this;
+    Compound_Selector_Obj head;
+    // processing loop
+    while (cur)
+    {
+      // get the head
+      head = cur->head_;
+      // abort (and return) if it is not a parent selector
+      if (!head || head->length() != 1 || !Cast<Parent_Selector>((*head)[0])) {
+        break;
+      }
+      // advance to next
+      cur = cur->tail_;
+    }
+    // result
+    return cur;
+  }
+
+  // return the last tail that is defined
+  Complex_Selector_Obj Complex_Selector::last()
+  {
+    Complex_Selector_Ptr cur = this;
+    Complex_Selector_Ptr nxt = cur;
+    // loop until last
+    while (nxt) {
+      cur = nxt;
+      nxt = cur->tail();
+    }
+    return cur;
+  }
+
+  Complex_Selector::Combinator Complex_Selector::clear_innermost()
+  {
+    Combinator c;
+    if (!tail() || tail()->tail() == 0)
+    { c = combinator(); combinator(ANCESTOR_OF); tail(0); }
+    else
+    { c = tail()->clear_innermost(); }
+    return c;
+  }
+
+  void Complex_Selector::set_innermost(Complex_Selector_Obj val, Combinator c)
+  {
+    if (!tail())
+    { tail(val); combinator(c); }
+    else
+    { tail()->set_innermost(val, c); }
+  }
+
+  void Complex_Selector::cloneChildren()
+  {
+    if (head()) head(SASS_MEMORY_CLONE(head()));
+    if (tail()) tail(SASS_MEMORY_CLONE(tail()));
+  }
+
+  void Compound_Selector::cloneChildren()
+  {
+    for (size_t i = 0, l = length(); i < l; i++) {
+      at(i) = SASS_MEMORY_CLONE(at(i));
+    }
+  }
+
+  void Selector_List::cloneChildren()
+  {
+    for (size_t i = 0, l = length(); i < l; i++) {
+      at(i) = SASS_MEMORY_CLONE(at(i));
+    }
+  }
+
+  void Wrapped_Selector::cloneChildren()
+  {
+    selector(SASS_MEMORY_CLONE(selector()));
+  }
+
+  // remove parent selector references
+  // basically unwraps parsed selectors
+  void Selector_List::remove_parent_selectors()
+  {
+    // Check every rhs selector against left hand list
+    for(size_t i = 0, L = length(); i < L; ++i) {
+      if (!(*this)[i]->head()) continue;
+      if ((*this)[i]->head()->is_empty_reference()) {
+        // simply move to the next tail if we have "no" combinator
+        if ((*this)[i]->combinator() == Complex_Selector::ANCESTOR_OF) {
+          if ((*this)[i]->tail()) {
+            if ((*this)[i]->has_line_feed()) {
+              (*this)[i]->tail()->has_line_feed(true);
+            }
+            (*this)[i] = (*this)[i]->tail();
+          }
+        }
+        // otherwise remove the first item from head
+        else {
+          (*this)[i]->head()->erase((*this)[i]->head()->begin());
+        }
+      }
+    }
+  }
+
+  size_t Wrapped_Selector::hash()
+  {
+    if (hash_ == 0) {
+      hash_combine(hash_, Simple_Selector::hash());
+      if (selector_) hash_combine(hash_, selector_->hash());
+    }
+    return hash_;
+  }
+  bool Wrapped_Selector::has_parent_ref() const {
+    // if (has_reference()) return true;
+    if (!selector()) return false;
+    return selector()->has_parent_ref();
+  }
+  bool Wrapped_Selector::has_real_parent_ref() const {
+    // if (has_reference()) return true;
+    if (!selector()) return false;
+    return selector()->has_real_parent_ref();
+  }
+  unsigned long Wrapped_Selector::specificity() const
+  {
+    return selector_ ? selector_->specificity() : 0;
+  }
+
+
+  bool Selector_List::has_parent_ref() const
+  {
+    for (Complex_Selector_Obj s : elements()) {
+      if (s && s->has_parent_ref()) return true;
+    }
+    return false;
+  }
+
+  bool Selector_List::has_real_parent_ref() const
+  {
+    for (Complex_Selector_Obj s : elements()) {
+      if (s && s->has_real_parent_ref()) return true;
+    }
+    return false;
+  }
+
+  bool Selector_Schema::has_parent_ref() const
+  {
+    if (String_Schema_Obj schema = Cast<String_Schema>(contents())) {
+      return schema->length() > 0 && Cast<Parent_Selector>(schema->at(0)) != NULL;
+    }
+    return false;
+  }
+
+  bool Selector_Schema::has_real_parent_ref() const
+  {
+    if (String_Schema_Obj schema = Cast<String_Schema>(contents())) {
+      Parent_Selector_Obj p = Cast<Parent_Selector>(schema->at(0));
+      return schema->length() > 0 && p && p->is_real_parent_ref();
+    }
+    return false;
+  }
+
+  void Selector_List::adjust_after_pushing(Complex_Selector_Obj c)
+  {
+    // if (c->has_reference())   has_reference(true);
+  }
+
+  // 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_Obj sub, std::string wrapping)
+  {
+    // 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], wrapping)) 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_Obj sub, std::string wrapping)
+  {
+    // 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], wrapping)) 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_Obj sub, std::string wrapping)
+  {
+    // Check every lhs selector against right hand
+    for(size_t i = 0, L = length(); i < L; ++i) {
+      if ((*this)[i]->is_superselector_of(sub, wrapping)) 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_Obj sub, std::string wrapping)
+  {
+    // 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;
+  }
+
+  Selector_List_Ptr Selector_List::unify_with(Selector_List_Ptr rhs) {
+    std::vector<Complex_Selector_Obj> unified_complex_selectors;
+    // Unify all of children with RHS's children, storing the results in `unified_complex_selectors`
+    for (size_t lhs_i = 0, lhs_L = length(); lhs_i < lhs_L; ++lhs_i) {
+      Complex_Selector_Obj seq1 = (*this)[lhs_i];
+      for(size_t rhs_i = 0, rhs_L = rhs->length(); rhs_i < rhs_L; ++rhs_i) {
+        Complex_Selector_Ptr seq2 = rhs->at(rhs_i);
+
+        Selector_List_Obj result = seq1->unify_with(seq2);
+        if( result ) {
+          for(size_t i = 0, L = result->length(); i < L; ++i) {
+            unified_complex_selectors.push_back( (*result)[i] );
+          }
+        }
+      }
+    }
+
+    // Creates the final Selector_List by combining all the complex selectors
+    Selector_List_Ptr final_result = SASS_MEMORY_NEW(Selector_List, pstate());
+    for (auto itr = unified_complex_selectors.begin(); itr != unified_complex_selectors.end(); ++itr) {
+      final_result->append(*itr);
+    }
+    return final_result;
+  }
+
+  void Selector_List::populate_extends(Selector_List_Obj extendee, Subset_Map& extends)
+  {
+
+    Selector_List_Ptr extender = this;
+    for (auto complex_sel : extendee->elements()) {
+      Complex_Selector_Obj c = complex_sel;
+
+
+      // Ignore any parent selectors, until we find the first non Selectorerence head
+      Compound_Selector_Obj compound_sel = c->head();
+      Complex_Selector_Obj pIter = complex_sel;
+      while (pIter) {
+        Compound_Selector_Obj pHead = pIter->head();
+        if (pHead && Cast<Parent_Selector>(pHead->elements()[0]) == NULL) {
+          compound_sel = pHead;
+          break;
+        }
+
+        pIter = pIter->tail();
+      }
+
+      if (!pIter->head() || pIter->tail()) {
+        coreError("nested selectors may not be extended", c->pstate());
+      }
+
+      compound_sel->is_optional(extendee->is_optional());
+
+      for (size_t i = 0, L = extender->length(); i < L; ++i) {
+        extends.put(compound_sel, std::make_pair((*extender)[i], compound_sel));
+      }
+    }
+  };
+
+  void Compound_Selector::append(Simple_Selector_Ptr element)
+  {
+    Vectorized<Simple_Selector_Obj>::append(element);
+    pstate_.offset += element->pstate().offset;
+  }
+
+  Compound_Selector_Ptr Compound_Selector::minus(Compound_Selector_Ptr rhs)
+  {
+    Compound_Selector_Ptr result = SASS_MEMORY_NEW(Compound_Selector, pstate());
+    // result->has_parent_reference(has_parent_reference());
+
+    // not very efficient because it needs to preserve order
+    for (size_t i = 0, L = length(); i < L; ++i)
+    {
+      bool found = false;
+      std::string thisSelector((*this)[i]->to_string());
+      for (size_t j = 0, M = rhs->length(); j < M; ++j)
+      {
+        if (thisSelector == (*rhs)[j]->to_string())
+        {
+          found = true;
+          break;
+        }
+      }
+      if (!found) result->append((*this)[i]);
+    }
+
+    return result;
+  }
+
+  void Compound_Selector::mergeSources(ComplexSelectorSet& sources)
+  {
+    for (ComplexSelectorSet::iterator iterator = sources.begin(), endIterator = sources.end(); iterator != endIterator; ++iterator) {
+      this->sources_.insert(SASS_MEMORY_CLONE(*iterator));
+    }
+  }
+
+  Argument_Obj Arguments::get_rest_argument()
+  {
+    if (this->has_rest_argument()) {
+      for (Argument_Obj arg : this->elements()) {
+        if (arg->is_rest_argument()) {
+          return arg;
+        }
+      }
+    }
+    return NULL;
+  }
+
+  Argument_Obj Arguments::get_keyword_argument()
+  {
+    if (this->has_keyword_argument()) {
+      for (Argument_Obj arg : this->elements()) {
+        if (arg->is_keyword_argument()) {
+          return arg;
+        }
+      }
+    }
+    return NULL;
+  }
+
+  void Arguments::adjust_after_pushing(Argument_Obj a)
+  {
+    if (!a->name().empty()) {
+      if (has_keyword_argument()) {
+        coreError("named arguments must precede variable-length argument", a->pstate());
+      }
+      has_named_arguments(true);
+    }
+    else if (a->is_rest_argument()) {
+      if (has_rest_argument()) {
+        coreError("functions and mixins may only be called with one variable-length argument", a->pstate());
+      }
+      if (has_keyword_argument_) {
+        coreError("only keyword arguments may follow variable arguments", a->pstate());
+      }
+      has_rest_argument(true);
+    }
+    else if (a->is_keyword_argument()) {
+      if (has_keyword_argument()) {
+        coreError("functions and mixins may only be called with one keyword argument", a->pstate());
+      }
+      has_keyword_argument(true);
+    }
+    else {
+      if (has_rest_argument()) {
+        coreError("ordinal arguments must precede variable-length arguments", a->pstate());
+      }
+      if (has_named_arguments()) {
+        coreError("ordinal arguments must precede named arguments", a->pstate());
+      }
+    }
+  }
+
+  bool Ruleset::is_invisible() const {
+    if (Selector_List_Ptr sl = Cast<Selector_List>(selector())) {
+      for (size_t i = 0, L = sl->length(); i < L; ++i)
+        if (!(*sl)[i]->has_placeholder()) return false;
+    }
+    return true;
+  }
+
+  bool Media_Block::is_invisible() const {
+    for (size_t i = 0, L = block()->length(); i < L; ++i) {
+      Statement_Obj stm = block()->at(i);
+      if (!stm->is_invisible()) return false;
+    }
+    return true;
+  }
+
+  Number::Number(ParserState pstate, double val, std::string u, bool zero)
+  : Value(pstate),
+    Units(),
+    value_(val),
+    zero_(zero),
+    hash_(0)
+  {
+    size_t l = 0;
+    size_t r;
+    if (!u.empty()) {
+      bool nominator = true;
+      while (true) {
+        r = u.find_first_of("*/", l);
+        std::string unit(u.substr(l, r == std::string::npos ? r : r - l));
+        if (!unit.empty()) {
+          if (nominator) numerators.push_back(unit);
+          else denominators.push_back(unit);
+        }
+        if (r == std::string::npos) break;
+        // ToDo: should error for multiple slashes
+        // if (!nominator && u[r] == '/') error(...)
+        if (u[r] == '/')
+          nominator = false;
+        // strange math parsing?
+        // else if (u[r] == '*')
+        //  nominator = true;
+        l = r + 1;
+      }
+    }
+    concrete_type(NUMBER);
+  }
+
+  // cancel out unnecessary units
+  void Number::reduce()
+  {
+    // apply conversion factor
+    value_ *= this->Units::reduce();
+  }
+
+  void Number::normalize()
+  {
+    // apply conversion factor
+    value_ *= this->Units::normalize();
+  }
+
+  bool Custom_Warning::operator== (const Expression& rhs) const
+  {
+    if (Custom_Warning_Ptr_Const r = Cast<Custom_Warning>(&rhs)) {
+      return message() == r->message();
+    }
+    return false;
+  }
+
+  bool Custom_Error::operator== (const Expression& rhs) const
+  {
+    if (Custom_Error_Ptr_Const r = Cast<Custom_Error>(&rhs)) {
+      return message() == r->message();
+    }
+    return false;
+  }
+
+  bool Number::operator== (const Expression& rhs) const
+  {
+    if (auto rhsnr = Cast<Number>(&rhs)) {
+      return *this == *rhsnr;
+    }
+    return false;
+  }
+
+  bool Number::operator== (const Number& rhs) const
+  {
+    Number l(*this), r(rhs); l.reduce(); r.reduce();
+    size_t lhs_units = l.numerators.size() + l.denominators.size();
+    size_t rhs_units = r.numerators.size() + r.denominators.size();
+    // unitless and only having one unit seems equivalent (will change in future)
+    if (!lhs_units || !rhs_units) {
+      return NEAR_EQUAL(l.value(), r.value());
+    }
+    l.normalize(); r.normalize();
+    Units &lhs_unit = l, &rhs_unit = r;
+    return lhs_unit == rhs_unit &&
+      NEAR_EQUAL(l.value(), r.value());
+  }
+
+  bool Number::operator< (const Number& rhs) const
+  {
+    Number l(*this), r(rhs); l.reduce(); r.reduce();
+    size_t lhs_units = l.numerators.size() + l.denominators.size();
+    size_t rhs_units = r.numerators.size() + r.denominators.size();
+    // unitless and only having one unit seems equivalent (will change in future)
+    if (!lhs_units || !rhs_units) {
+      return l.value() < r.value();
+    }
+    l.normalize(); r.normalize();
+    Units &lhs_unit = l, &rhs_unit = r;
+    if (!(lhs_unit == rhs_unit)) {
+      /* ToDo: do we always get usefull backtraces? */
+      throw Exception::IncompatibleUnits(rhs, *this);
+    }
+    return lhs_unit < rhs_unit ||
+           l.value() < r.value();
+  }
+
+  bool String_Quoted::operator== (const Expression& rhs) const
+  {
+    if (String_Quoted_Ptr_Const qstr = Cast<String_Quoted>(&rhs)) {
+      return (value() == qstr->value());
+    } else if (String_Constant_Ptr_Const cstr = Cast<String_Constant>(&rhs)) {
+      return (value() == cstr->value());
+    }
+    return false;
+  }
+
+  bool String_Constant::is_invisible() const {
+    return value_.empty() && quote_mark_ == 0;
+  }
+
+  bool String_Constant::operator== (const Expression& rhs) const
+  {
+    if (String_Quoted_Ptr_Const qstr = Cast<String_Quoted>(&rhs)) {
+      return (value() == qstr->value());
+    } else if (String_Constant_Ptr_Const cstr = Cast<String_Constant>(&rhs)) {
+      return (value() == cstr->value());
+    }
+    return false;
+  }
+
+  bool String_Schema::is_left_interpolant(void) const
+  {
+    return length() && first()->is_left_interpolant();
+  }
+  bool String_Schema::is_right_interpolant(void) const
+  {
+    return length() && last()->is_right_interpolant();
+  }
+
+  bool String_Schema::operator== (const Expression& rhs) const
+  {
+    if (String_Schema_Ptr_Const r = Cast<String_Schema>(&rhs)) {
+      if (length() != r->length()) return false;
+      for (size_t i = 0, L = length(); i < L; ++i) {
+        Expression_Obj rv = (*r)[i];
+        Expression_Obj lv = (*this)[i];
+        if (!lv || !rv) return false;
+        if (!(*lv == *rv)) return false;
+      }
+      return true;
+    }
+    return false;
+  }
+
+  bool Boolean::operator== (const Expression& rhs) const
+  {
+    if (Boolean_Ptr_Const r = Cast<Boolean>(&rhs)) {
+      return (value() == r->value());
+    }
+    return false;
+  }
+
+  bool Color::operator== (const Expression& rhs) const
+  {
+    if (Color_Ptr_Const r = Cast<Color>(&rhs)) {
+      return r_ == r->r() &&
+             g_ == r->g() &&
+             b_ == r->b() &&
+             a_ == r->a();
+    }
+    return false;
+  }
+
+  bool List::operator== (const Expression& rhs) const
+  {
+    if (List_Ptr_Const r = Cast<List>(&rhs)) {
+      if (length() != r->length()) return false;
+      if (separator() != r->separator()) return false;
+      if (is_bracketed() != r->is_bracketed()) return false;
+      for (size_t i = 0, L = length(); i < L; ++i) {
+        Expression_Obj rv = r->at(i);
+        Expression_Obj lv = this->at(i);
+        if (!lv || !rv) return false;
+        if (!(*lv == *rv)) return false;
+      }
+      return true;
+    }
+    return false;
+  }
+
+  bool Map::operator== (const Expression& rhs) const
+  {
+    if (Map_Ptr_Const r = Cast<Map>(&rhs)) {
+      if (length() != r->length()) return false;
+      for (auto key : keys()) {
+        Expression_Obj lv = at(key);
+        Expression_Obj rv = r->at(key);
+        if (!rv || !lv) return false;
+        if (!(*lv == *rv)) return false;
+      }
+      return true;
+    }
+    return false;
+  }
+
+  bool Null::operator== (const Expression& rhs) const
+  {
+    return rhs.concrete_type() == NULL_VAL;
+  }
+
+  bool Function::operator== (const Expression& rhs) const
+  {
+    if (Function_Ptr_Const r = Cast<Function>(&rhs)) {
+      Definition_Ptr_Const d1 = Cast<Definition>(definition());
+      Definition_Ptr_Const d2 = Cast<Definition>(r->definition());
+      return d1 && d2 && d1 == d2 && is_css() == r->is_css();
+    }
+    return false;
+  }
+
+  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) {
+      Expression_Obj obj = this->at(i);
+      if (Argument_Ptr arg = Cast<Argument>(obj)) {
+        if (!arg->name().empty()) return i;
+      }
+    }
+    return length();
+  }
+
+  Expression_Obj Hashed::at(Expression_Obj k) const
+  {
+    if (elements_.count(k))
+    { return elements_.at(k); }
+    else { return NULL; }
+  }
+
+  bool Binary_Expression::is_left_interpolant(void) const
+  {
+    return is_interpolant() || (left() && left()->is_left_interpolant());
+  }
+  bool Binary_Expression::is_right_interpolant(void) const
+  {
+    return is_interpolant() || (right() && right()->is_right_interpolant());
+  }
+
+  const std::string AST_Node::to_string(Sass_Inspect_Options opt) const
+  {
+    Sass_Output_Options out(opt);
+    Emitter emitter(out);
+    Inspect i(emitter);
+    i.in_declaration = true;
+    // ToDo: inspect should be const
+    const_cast<AST_Node_Ptr>(this)->perform(&i);
+    return i.get_buffer();
+  }
+
+  const std::string AST_Node::to_string() const
+  {
+    return to_string({ NESTED, 5 });
+  }
+
+  std::string String_Quoted::inspect() const
+  {
+    return quote(value_, '*');
+  }
+
+  std::string String_Constant::inspect() const
+  {
+    return quote(value_, '*');
+  }
+
+  bool Declaration::is_invisible() const
+  {
+    if (is_custom_property()) return false;
+
+    return !(value_ && value_->concrete_type() != Expression::NULL_VAL);
+  }
+
+  //////////////////////////////////////////////////////////////////////////////////////////
+  // Additional method on Lists to retrieve values directly or from an encompassed Argument.
+  //////////////////////////////////////////////////////////////////////////////////////////
+  Expression_Obj List::value_at_index(size_t i) {
+    Expression_Obj obj = this->at(i);
+    if (is_arglist_) {
+      if (Argument_Ptr arg = Cast<Argument>(obj)) {
+        return arg->value();
+      } else {
+        return obj;
+      }
+    } else {
+      return obj;
+    }
+  }
+
+  //////////////////////////////////////////////////////////////////////////////////////////
+  // Convert map to (key, value) list.
+  //////////////////////////////////////////////////////////////////////////////////////////
+  List_Obj Map::to_list(ParserState& pstate) {
+    List_Obj ret = SASS_MEMORY_NEW(List, pstate, length(), SASS_COMMA);
+
+    for (auto key : keys()) {
+      List_Obj l = SASS_MEMORY_NEW(List, pstate, 2);
+      l->append(key);
+      l->append(at(key));
+      ret->append(l);
+    }
+
+    return ret;
+  }
+
+  //////////////////////////////////////////////////////////////////////////////////////////
+  // Copy implementations
+  //////////////////////////////////////////////////////////////////////////////////////////
+
+  #ifdef DEBUG_SHARED_PTR
+
+  #define IMPLEMENT_AST_OPERATORS(klass) \
+    klass##_Ptr klass::copy(std::string file, size_t line) const { \
+      klass##_Ptr cpy = new klass(this); \
+      cpy->trace(file, line); \
+      return cpy; \
+    } \
+    klass##_Ptr klass::clone(std::string file, size_t line) const { \
+      klass##_Ptr cpy = copy(file, line); \
+      cpy->cloneChildren(); \
+      return cpy; \
+    } \
+
+  #else
+
+  #define IMPLEMENT_AST_OPERATORS(klass) \
+    klass##_Ptr klass::copy() const { \
+      return new klass(this); \
+    } \
+    klass##_Ptr klass::clone() const { \
+      klass##_Ptr cpy = copy(); \
+      cpy->cloneChildren(); \
+      return cpy; \
+    } \
+
+  #endif
+
+  IMPLEMENT_AST_OPERATORS(Supports_Operator);
+  IMPLEMENT_AST_OPERATORS(Supports_Negation);
+  IMPLEMENT_AST_OPERATORS(Compound_Selector);
+  IMPLEMENT_AST_OPERATORS(Complex_Selector);
+  IMPLEMENT_AST_OPERATORS(Element_Selector);
+  IMPLEMENT_AST_OPERATORS(Class_Selector);
+  IMPLEMENT_AST_OPERATORS(Id_Selector);
+  IMPLEMENT_AST_OPERATORS(Pseudo_Selector);
+  IMPLEMENT_AST_OPERATORS(Wrapped_Selector);
+  IMPLEMENT_AST_OPERATORS(Selector_List);
+  IMPLEMENT_AST_OPERATORS(Ruleset);
+  IMPLEMENT_AST_OPERATORS(Media_Block);
+  IMPLEMENT_AST_OPERATORS(Custom_Warning);
+  IMPLEMENT_AST_OPERATORS(Custom_Error);
+  IMPLEMENT_AST_OPERATORS(List);
+  IMPLEMENT_AST_OPERATORS(Map);
+  IMPLEMENT_AST_OPERATORS(Function);
+  IMPLEMENT_AST_OPERATORS(Number);
+  IMPLEMENT_AST_OPERATORS(Binary_Expression);
+  IMPLEMENT_AST_OPERATORS(String_Schema);
+  IMPLEMENT_AST_OPERATORS(String_Constant);
+  IMPLEMENT_AST_OPERATORS(String_Quoted);
+  IMPLEMENT_AST_OPERATORS(Boolean);
+  IMPLEMENT_AST_OPERATORS(Color);
+  IMPLEMENT_AST_OPERATORS(Null);
+  IMPLEMENT_AST_OPERATORS(Parent_Selector);
+  IMPLEMENT_AST_OPERATORS(Import);
+  IMPLEMENT_AST_OPERATORS(Import_Stub);
+  IMPLEMENT_AST_OPERATORS(Function_Call);
+  IMPLEMENT_AST_OPERATORS(Directive);
+  IMPLEMENT_AST_OPERATORS(At_Root_Block);
+  IMPLEMENT_AST_OPERATORS(Supports_Block);
+  IMPLEMENT_AST_OPERATORS(While);
+  IMPLEMENT_AST_OPERATORS(Each);
+  IMPLEMENT_AST_OPERATORS(For);
+  IMPLEMENT_AST_OPERATORS(If);
+  IMPLEMENT_AST_OPERATORS(Mixin_Call);
+  IMPLEMENT_AST_OPERATORS(Extension);
+  IMPLEMENT_AST_OPERATORS(Media_Query);
+  IMPLEMENT_AST_OPERATORS(Media_Query_Expression);
+  IMPLEMENT_AST_OPERATORS(Debug);
+  IMPLEMENT_AST_OPERATORS(Error);
+  IMPLEMENT_AST_OPERATORS(Warning);
+  IMPLEMENT_AST_OPERATORS(Assignment);
+  IMPLEMENT_AST_OPERATORS(Return);
+  IMPLEMENT_AST_OPERATORS(At_Root_Query);
+  IMPLEMENT_AST_OPERATORS(Variable);
+  IMPLEMENT_AST_OPERATORS(Comment);
+  IMPLEMENT_AST_OPERATORS(Attribute_Selector);
+  IMPLEMENT_AST_OPERATORS(Supports_Interpolation);
+  IMPLEMENT_AST_OPERATORS(Supports_Declaration);
+  IMPLEMENT_AST_OPERATORS(Supports_Condition);
+  IMPLEMENT_AST_OPERATORS(Parameters);
+  IMPLEMENT_AST_OPERATORS(Parameter);
+  IMPLEMENT_AST_OPERATORS(Arguments);
+  IMPLEMENT_AST_OPERATORS(Argument);
+  IMPLEMENT_AST_OPERATORS(Unary_Expression);
+  IMPLEMENT_AST_OPERATORS(Function_Call_Schema);
+  IMPLEMENT_AST_OPERATORS(Block);
+  IMPLEMENT_AST_OPERATORS(Content);
+  IMPLEMENT_AST_OPERATORS(Trace);
+  IMPLEMENT_AST_OPERATORS(Keyframe_Rule);
+  IMPLEMENT_AST_OPERATORS(Bubble);
+  IMPLEMENT_AST_OPERATORS(Selector_Schema);
+  IMPLEMENT_AST_OPERATORS(Placeholder_Selector);
+  IMPLEMENT_AST_OPERATORS(Definition);
+  IMPLEMENT_AST_OPERATORS(Declaration);
 }
diff --git a/libsass/src/ast.hpp b/libsass/src/ast.hpp
--- a/libsass/src/ast.hpp
+++ b/libsass/src/ast.hpp
@@ -1,6 +1,7 @@
 #ifndef SASS_AST_H
 #define SASS_AST_H
 
+#include "sass.hpp"
 #include <set>
 #include <deque>
 #include <vector>
@@ -74,6 +75,9 @@
   // Note: most methods follow precision option
   const double NUMBER_EPSILON = 0.00000000000001;
 
+  // macro to test if numbers are equal within a small error margin
+  #define NEAR_EQUAL(lhs, rhs) std::fabs(lhs - rhs) < NUMBER_EPSILON
+
   // ToDo: where does this fit best?
   // We don't share this with C-API?
   class Operand {
@@ -120,12 +124,14 @@
     ATTACH_VIRTUAL_AST_OPERATIONS(AST_Node);
     virtual std::string inspect() const { return to_string({ INSPECT, 5 }); }
     virtual std::string to_sass() const { return to_string({ TO_SASS, 5 }); }
-    virtual std::string to_string(Sass_Inspect_Options opt) const;
-    virtual std::string to_string() const;
+    virtual const std::string to_string(Sass_Inspect_Options opt) const;
+    virtual const std::string to_string() const;
     virtual void cloneChildren() {};
+    // generic find function (not fully implemented yet)
+    // ToDo: add specific implementions to all children
+    virtual bool find ( bool (*f)(AST_Node_Obj) ) { return f(this); };
   public:
     void update_pstate(const ParserState& pstate);
-    void set_pstate_offset(const Offset& offset);
   public:
     Offset off() { return pstate(); }
     Position pos() { return pstate(); }
@@ -133,7 +139,22 @@
   };
   inline AST_Node::~AST_Node() { }
 
+  //////////////////////////////////////////////////////////////////////
+  // define cast template now (need complete type)
+  //////////////////////////////////////////////////////////////////////
 
+  template<class T>
+  T* Cast(AST_Node* ptr) {
+    return ptr && typeid(T) == typeid(*ptr) ?
+           static_cast<T*>(ptr) : NULL;
+  };
+
+  template<class T>
+  const T* Cast(const AST_Node* ptr) {
+    return ptr && typeid(T) == typeid(*ptr) ?
+           static_cast<const T*>(ptr) : NULL;
+  };
+
   //////////////////////////////////////////////////////////////////////
   // Abstract base class for expressions. This side of the AST hierarchy
   // represents elements in value contexts, which exist primarily to be
@@ -151,9 +172,11 @@
       MAP,
       SELECTOR,
       NULL_VAL,
+      FUNCTION_VAL,
       C_WARNING,
       C_ERROR,
       FUNCTION,
+      VARIABLE,
       NUM_TYPES
     };
     enum Simple_Type {
@@ -186,7 +209,7 @@
     { }
     virtual operator bool() { return true; }
     virtual ~Expression() { }
-    virtual std::string type() { return ""; /* TODO: raise an error? */ }
+    virtual std::string type() const { return ""; /* TODO: raise an error? */ }
     virtual bool is_invisible() const { return false; }
     static std::string type_name() { return ""; }
     virtual bool is_false() { return false; }
@@ -343,8 +366,11 @@
     void reset_duplicate_key() { duplicate_key_ = 0; }
     virtual void adjust_after_pushing(std::pair<Expression_Obj, Expression_Obj> p) { }
   public:
-    Hashed(size_t s = 0) : elements_(ExpressionMap(s)), list_(std::vector<Expression_Obj>())
-    { elements_.reserve(s); list_.reserve(s); reset_duplicate_key(); }
+    Hashed(size_t s = 0)
+    : elements_(ExpressionMap(s)),
+      list_(std::vector<Expression_Obj>()),
+      hash_(0), duplicate_key_(NULL)
+    { elements_.reserve(s); list_.reserve(s); }
     virtual ~Hashed();
     size_t length() const                  { return list_.size(); }
     bool empty() const                     { return list_.empty(); }
@@ -454,7 +480,6 @@
   ////////////////////////
   class Block : public Statement, public Vectorized<Statement_Obj> {
     ADD_PROPERTY(bool, is_root)
-    ADD_PROPERTY(bool, is_at_root);
     // needed for properly formatted CSS emission
   protected:
     void adjust_after_pushing(Statement_Obj s)
@@ -464,14 +489,12 @@
     Block(ParserState pstate, size_t s = 0, bool r = false)
     : Statement(pstate),
       Vectorized<Statement_Obj>(s),
-      is_root_(r),
-      is_at_root_(false)
+      is_root_(r)
     { }
     Block(const Block* ptr)
     : Statement(ptr),
       Vectorized<Statement_Obj>(*ptr),
-      is_root_(ptr->is_root_),
-      is_at_root_(ptr->is_at_root_)
+      is_root_(ptr->is_root_)
     { }
     virtual bool has_content()
     {
@@ -509,17 +532,15 @@
   // of style declarations.
   /////////////////////////////////////////////////////////////////////////////
   class Ruleset : public Has_Block {
-    ADD_PROPERTY(Selector_Obj, selector)
-    ADD_PROPERTY(bool, at_root);
+    ADD_PROPERTY(Selector_List_Obj, selector)
     ADD_PROPERTY(bool, is_root);
   public:
-    Ruleset(ParserState pstate, Selector_Obj s = 0, Block_Obj b = 0)
-    : Has_Block(pstate, b), selector_(s), at_root_(false), is_root_(false)
+    Ruleset(ParserState pstate, Selector_List_Obj s = 0, Block_Obj b = 0)
+    : Has_Block(pstate, b), selector_(s), is_root_(false)
     { statement_type(RULESET); }
     Ruleset(const Ruleset* ptr)
     : Has_Block(ptr),
       selector_(ptr->selector_),
-      at_root_(ptr->at_root_),
       is_root_(ptr->is_root_)
     { statement_type(RULESET); }
     bool is_invisible() const;
@@ -551,13 +572,15 @@
   // Trace.
   /////////////////
   class Trace : public Has_Block {
-    ADD_PROPERTY(std::string, name)
+    ADD_CONSTREF(char, type)
+    ADD_CONSTREF(std::string, name)
   public:
-    Trace(ParserState pstate, std::string n, Block_Obj b = 0)
-    : Has_Block(pstate, b), name_(n)
+    Trace(ParserState pstate, std::string n, Block_Obj b = 0, char type = 'm')
+    : Has_Block(pstate, b), type_(type), name_(n)
     { }
     Trace(const Trace* ptr)
     : Has_Block(ptr),
+      type_(ptr->type_),
       name_(ptr->name_)
     { }
     ATTACH_AST_OPERATIONS(Trace)
@@ -573,9 +596,6 @@
     Media_Block(ParserState pstate, List_Obj mqs, Block_Obj b)
     : Has_Block(pstate, b), media_queries_(mqs)
     { statement_type(MEDIA); }
-    Media_Block(ParserState pstate, List_Obj mqs, Block_Obj b, Selector_Obj s)
-    : Has_Block(pstate, b), media_queries_(mqs)
-    { statement_type(MEDIA); }
     Media_Block(const Media_Block* ptr)
     : Has_Block(ptr), media_queries_(ptr->media_queries_)
     { statement_type(MEDIA); }
@@ -590,11 +610,11 @@
   // optional statement block.
   ///////////////////////////////////////////////////////////////////////
   class Directive : public Has_Block {
-    ADD_PROPERTY(std::string, keyword)
-    ADD_PROPERTY(Selector_Obj, selector)
+    ADD_CONSTREF(std::string, keyword)
+    ADD_PROPERTY(Selector_List_Obj, selector)
     ADD_PROPERTY(Expression_Obj, value)
   public:
-    Directive(ParserState pstate, std::string kwd, Selector_Obj sel = 0, Block_Obj b = 0, Expression_Obj val = 0)
+    Directive(ParserState pstate, std::string kwd, Selector_List_Obj sel = 0, Block_Obj b = 0, Expression_Obj val = 0)
     : Has_Block(pstate, b), keyword_(kwd), selector_(sel), value_(val) // set value manually if needed
     { statement_type(DIRECTIVE); }
     Directive(const Directive* ptr)
@@ -626,7 +646,7 @@
   class Keyframe_Rule : public Has_Block {
     // according to css spec, this should be <keyframes-name>
     // <keyframes-name> = <custom-ident> | <string>
-    ADD_PROPERTY(Selector_Obj, name)
+    ADD_PROPERTY(Selector_List_Obj, name)
   public:
     Keyframe_Rule(ParserState pstate, Block_Obj b)
     : Has_Block(pstate, b), name_()
@@ -645,19 +665,22 @@
     ADD_PROPERTY(String_Obj, property)
     ADD_PROPERTY(Expression_Obj, value)
     ADD_PROPERTY(bool, is_important)
+    ADD_PROPERTY(bool, is_custom_property)
     ADD_PROPERTY(bool, is_indented)
   public:
     Declaration(ParserState pstate,
-                String_Obj prop, Expression_Obj val, bool i = false, Block_Obj b = 0)
-    : Has_Block(pstate, b), property_(prop), value_(val), is_important_(i), is_indented_(false)
+                String_Obj prop, Expression_Obj val, bool i = false, bool c = false, Block_Obj b = 0)
+    : Has_Block(pstate, b), property_(prop), value_(val), is_important_(i), is_custom_property_(c), is_indented_(false)
     { statement_type(DECLARATION); }
     Declaration(const Declaration* ptr)
     : Has_Block(ptr),
       property_(ptr->property_),
       value_(ptr->value_),
       is_important_(ptr->is_important_),
+      is_custom_property_(ptr->is_custom_property_),
       is_indented_(ptr->is_indented_)
     { statement_type(DECLARATION); }
+    virtual bool is_invisible() const;
     ATTACH_AST_OPERATIONS(Declaration)
     ATTACH_OPERATIONS()
   };
@@ -666,7 +689,7 @@
   // Assignments -- variable and value.
   /////////////////////////////////////
   class Assignment : public Statement {
-    ADD_PROPERTY(std::string, variable)
+    ADD_CONSTREF(std::string, variable)
     ADD_PROPERTY(Expression_Obj, value)
     ADD_PROPERTY(bool, is_default)
     ADD_PROPERTY(bool, is_global)
@@ -811,7 +834,7 @@
     ADD_PROPERTY(Block_Obj, alternative)
   public:
     If(ParserState pstate, Expression_Obj pred, Block_Obj con, Block_Obj alt = 0)
-    : Has_Block(pstate, &con), predicate_(pred), alternative_(alt)
+    : Has_Block(pstate, con), predicate_(pred), alternative_(alt)
     { statement_type(IF); }
     If(const If* ptr)
     : Has_Block(ptr),
@@ -830,7 +853,7 @@
   // The Sass `@for` control directive.
   /////////////////////////////////////
   class For : public Has_Block {
-    ADD_PROPERTY(std::string, variable)
+    ADD_CONSTREF(std::string, variable)
     ADD_PROPERTY(Expression_Obj, lower_bound)
     ADD_PROPERTY(Expression_Obj, upper_bound)
     ADD_PROPERTY(bool, is_inclusive)
@@ -904,9 +927,9 @@
   // The Sass `@extend` directive.
   ////////////////////////////////
   class Extension : public Statement {
-    ADD_PROPERTY(Selector_Obj, selector)
+    ADD_PROPERTY(Selector_List_Obj, selector)
   public:
-    Extension(ParserState pstate, Selector_Obj s)
+    Extension(ParserState pstate, Selector_List_Obj s)
     : Statement(pstate), selector_(s)
     { statement_type(EXTEND); }
     Extension(const Extension* ptr)
@@ -921,13 +944,12 @@
   // by a type tag.
   /////////////////////////////////////////////////////////////////////////////
   struct Backtrace;
-  typedef Environment<AST_Node_Obj> Env;
   typedef const char* Signature;
-  typedef Expression_Ptr (*Native_Function)(Env&, Env&, Context&, Signature, ParserState, Backtrace*, std::vector<Selector_List_Obj>);
+  typedef Expression_Ptr (*Native_Function)(Env&, Env&, Context&, Signature, ParserState, Backtraces, std::vector<Selector_List_Obj>);
   class Definition : public Has_Block {
   public:
     enum Type { MIXIN, FUNCTION };
-    ADD_PROPERTY(std::string, name)
+    ADD_CONSTREF(std::string, name)
     ADD_PROPERTY(Parameters_Obj, parameters)
     ADD_PROPERTY(Env*, environment)
     ADD_PROPERTY(Type, type)
@@ -1009,7 +1031,7 @@
   // Mixin calls (i.e., `@include ...`).
   //////////////////////////////////////
   class Mixin_Call : public Has_Block {
-    ADD_PROPERTY(std::string, name)
+    ADD_CONSTREF(std::string, name)
     ADD_PROPERTY(Arguments_Obj, arguments)
   public:
     Mixin_Call(ParserState pstate, std::string n, Arguments_Obj args, Block_Obj b = 0)
@@ -1028,11 +1050,15 @@
   // The @content directive for mixin content blocks.
   ///////////////////////////////////////////////////
   class Content : public Statement {
-    ADD_PROPERTY(Media_Block_Obj, media_block)
+    ADD_PROPERTY(Media_Block_Ptr, media_block)
   public:
-    Content(ParserState pstate) : Statement(pstate)
+    Content(ParserState pstate)
+    : Statement(pstate),
+      media_block_(NULL)
     { statement_type(CONTENT); }
-    Content(const Content* ptr) : Statement(ptr)
+    Content(const Content* ptr)
+    : Statement(ptr),
+      media_block_(ptr->media_block_)
     { statement_type(CONTENT); }
     ATTACH_AST_OPERATIONS(Content)
     ATTACH_OPERATIONS()
@@ -1047,14 +1073,16 @@
   private:
     ADD_PROPERTY(enum Sass_Separator, separator)
     ADD_PROPERTY(bool, is_arglist)
+    ADD_PROPERTY(bool, is_bracketed)
     ADD_PROPERTY(bool, from_selector)
   public:
     List(ParserState pstate,
-         size_t size = 0, enum Sass_Separator sep = SASS_SPACE, bool argl = false)
+         size_t size = 0, enum Sass_Separator sep = SASS_SPACE, bool argl = false, bool bracket = false)
     : Value(pstate),
       Vectorized<Expression_Obj>(size),
       separator_(sep),
       is_arglist_(argl),
+      is_bracketed_(bracket),
       from_selector_(false)
     { concrete_type(LIST); }
     List(const List* ptr)
@@ -1062,15 +1090,16 @@
       Vectorized<Expression_Obj>(*ptr),
       separator_(ptr->separator_),
       is_arglist_(ptr->is_arglist_),
+      is_bracketed_(ptr->is_bracketed_),
       from_selector_(ptr->from_selector_)
     { concrete_type(LIST); }
-    std::string type() { return is_arglist_ ? "arglist" : "list"; }
+    std::string type() const { return is_arglist_ ? "arglist" : "list"; }
     static std::string type_name() { return "list"; }
     const char* sep_string(bool compressed = false) const {
       return separator() == SASS_SPACE ?
         " " : (compressed ? "," : ", ");
     }
-    bool is_invisible() const { return empty(); }
+    bool is_invisible() const { return empty() && !is_bracketed(); }
     Expression_Obj value_at_index(size_t i);
 
     virtual size_t size() const;
@@ -1079,6 +1108,7 @@
     {
       if (hash_ == 0) {
         hash_ = std::hash<std::string>()(sep_string());
+        hash_combine(hash_, std::hash<bool>()(is_bracketed()));
         for (size_t i = 0, L = length(); i < L; ++i)
           hash_combine(hash_, (elements()[i])->hash());
       }
@@ -1112,10 +1142,10 @@
     : Value(ptr),
       Hashed(*ptr)
     { concrete_type(MAP); }
-    std::string type() { return "map"; }
+    std::string type() const { return "map"; }
     static std::string type_name() { return "map"; }
     bool is_invisible() const { return empty(); }
-    List_Obj to_list(Context& ctx, ParserState& pstate);
+    List_Obj to_list(ParserState& pstate);
 
     virtual size_t hash()
     {
@@ -1137,25 +1167,46 @@
 
   inline static const std::string sass_op_to_name(enum Sass_OP op) {
     switch (op) {
-      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 "plus"; break;
-      case SUB: return "sub"; break;
-      case MUL: return "times"; break;
-      case DIV: return "div"; break;
-      case MOD: return "mod"; break;
+      case AND: return "and";
+      case OR: return "or";
+      case EQ: return "eq";
+      case NEQ: return "neq";
+      case GT: return "gt";
+      case GTE: return "gte";
+      case LT: return "lt";
+      case LTE: return "lte";
+      case ADD: return "plus";
+      case SUB: return "sub";
+      case MUL: return "times";
+      case DIV: return "div";
+      case MOD: return "mod";
       // this is only used internally!
-      case NUM_OPS: return "[OPS]"; break;
-      default: return "invalid"; break;
+      case NUM_OPS: return "[OPS]";
+      default: return "invalid";
     }
   }
 
+  inline static const std::string sass_op_separator(enum Sass_OP op) {
+    switch (op) {
+      case AND: return "&&";
+      case OR: return "||";
+      case EQ: return "==";
+      case NEQ: return "!=";
+      case GT: return ">";
+      case GTE: return ">=";
+      case LT: return "<";
+      case LTE: return "<=";
+      case ADD: return "+";
+      case SUB: return "-";
+      case MUL: return "*";
+      case DIV: return "/";
+      case MOD: return "%";
+      // this is only used internally!
+      case NUM_OPS: return "[OPS]";
+      default: return "invalid";
+    }
+  }
+
   //////////////////////////////////////////////////////////////////////////
   // Binary expressions. Represents logical, relational, and arithmetic
   // operations. Templatized to avoid large switch statements and repetitive
@@ -1163,9 +1214,9 @@
   //////////////////////////////////////////////////////////////////////////
   class Binary_Expression : public PreValue {
   private:
-    ADD_HASHED(Operand, op)
-    ADD_HASHED(Expression_Obj, left)
-    ADD_HASHED(Expression_Obj, right)
+    HASH_PROPERTY(Operand, op)
+    HASH_PROPERTY(Expression_Obj, left)
+    HASH_PROPERTY(Expression_Obj, right)
     size_t hash_;
   public:
     Binary_Expression(ParserState pstate,
@@ -1180,44 +1231,10 @@
       hash_(ptr->hash_)
     { }
     const std::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;
-        // this is only used internally!
-        case NUM_OPS: return "[OPS]"; break;
-        default: return "invalid"; break;
-      }
+      return sass_op_to_name(optype());
     }
     const std::string separator() {
-      switch (type()) {
-        case AND: return "&&"; break;
-        case OR: return "||"; break;
-        case EQ: return "=="; break;
-        case NEQ: return "!="; break;
-        case GT: return ">"; break;
-        case GTE: return ">="; break;
-        case LT: return "<"; break;
-        case LTE: return "<="; break;
-        case ADD: return "+"; break;
-        case SUB: return "-"; break;
-        case MUL: return "*"; break;
-        case DIV: return "/"; break;
-        case MOD: return "%"; break;
-        // this is only used internally!
-        case NUM_OPS: return "[OPS]"; break;
-        default: return "invalid"; break;
-      }
+      return sass_op_separator(optype());
     }
     bool is_left_interpolant(void) const;
     bool is_right_interpolant(void) const;
@@ -1236,11 +1253,11 @@
     {
       try
       {
-        Binary_Expression_Ptr_Const m = dynamic_cast<Binary_Expression_Ptr_Const>(&rhs);
+        Binary_Expression_Ptr_Const m = Cast<Binary_Expression>(&rhs);
         if (m == 0) return false;
         return type() == m->type() &&
-               left() == m->left() &&
-               right() == m->right();
+               *left() == *m->left() &&
+               *right() == *m->right();
       }
       catch (std::bad_cast&)
       {
@@ -1251,13 +1268,13 @@
     virtual size_t hash()
     {
       if (hash_ == 0) {
-        hash_ = std::hash<size_t>()(type());
+        hash_ = std::hash<size_t>()(optype());
         hash_combine(hash_, left()->hash());
         hash_combine(hash_, right()->hash());
       }
       return hash_;
     }
-    enum Sass_OP type() const { return op_.operand; }
+    enum Sass_OP optype() const { return op_.operand; }
     ATTACH_AST_OPERATIONS(Binary_Expression)
     ATTACH_OPERATIONS()
   };
@@ -1267,37 +1284,38 @@
   ////////////////////////////////////////////////////////////////////////////
   class Unary_Expression : public Expression {
   public:
-    enum Type { PLUS, MINUS, NOT };
+    enum Type { PLUS, MINUS, NOT, SLASH };
   private:
-    ADD_HASHED(Type, type)
-    ADD_HASHED(Expression_Obj, operand)
+    HASH_PROPERTY(Type, optype)
+    HASH_PROPERTY(Expression_Obj, operand)
     size_t hash_;
   public:
     Unary_Expression(ParserState pstate, Type t, Expression_Obj o)
-    : Expression(pstate), type_(t), operand_(o), hash_(0)
+    : Expression(pstate), optype_(t), operand_(o), hash_(0)
     { }
     Unary_Expression(const Unary_Expression* ptr)
     : Expression(ptr),
-      type_(ptr->type_),
+      optype_(ptr->optype_),
       operand_(ptr->operand_),
       hash_(ptr->hash_)
     { }
     const std::string type_name() {
-      switch (type_) {
-        case PLUS: return "plus"; break;
-        case MINUS: return "minus"; break;
-        case NOT: return "not"; break;
-        default: return "invalid"; break;
+      switch (optype_) {
+        case PLUS: return "plus";
+        case MINUS: return "minus";
+        case SLASH: return "slash";
+        case NOT: return "not";
+        default: return "invalid";
       }
     }
     virtual bool operator==(const Expression& rhs) const
     {
       try
       {
-        Unary_Expression_Ptr_Const m = dynamic_cast<Unary_Expression_Ptr_Const>(&rhs);
+        Unary_Expression_Ptr_Const m = Cast<Unary_Expression>(&rhs);
         if (m == 0) return false;
         return type() == m->type() &&
-               operand() == m->operand();
+               *operand() == *m->operand();
       }
       catch (std::bad_cast&)
       {
@@ -1308,7 +1326,7 @@
     virtual size_t hash()
     {
       if (hash_ == 0) {
-        hash_ = std::hash<size_t>()(type_);
+        hash_ = std::hash<size_t>()(optype_);
         hash_combine(hash_, operand()->hash());
       };
       return hash_;
@@ -1321,8 +1339,8 @@
   // Individual argument objects for mixin and function calls.
   ////////////////////////////////////////////////////////////
   class Argument : public Expression {
-    ADD_HASHED(Expression_Obj, value)
-    ADD_HASHED(std::string, name)
+    HASH_PROPERTY(Expression_Obj, value)
+    HASH_CONSTREF(std::string, name)
     ADD_PROPERTY(bool, is_rest_argument)
     ADD_PROPERTY(bool, is_keyword_argument)
     size_t hash_;
@@ -1331,7 +1349,7 @@
     : Expression(pstate), value_(val), name_(n), is_rest_argument_(rest), is_keyword_argument_(keyword), hash_(0)
     {
       if (!name_.empty() && is_rest_argument_) {
-        error("variable-length argument may not be passed by name", pstate_);
+        coreError("variable-length argument may not be passed by name", pstate_);
       }
     }
     Argument(const Argument* ptr)
@@ -1343,7 +1361,7 @@
       hash_(ptr->hash_)
     {
       if (!name_.empty() && is_rest_argument_) {
-        error("variable-length argument may not be passed by name", pstate_);
+        coreError("variable-length argument may not be passed by name", pstate_);
       }
     }
 
@@ -1352,7 +1370,7 @@
     {
       try
       {
-        Argument_Ptr_Const m = dynamic_cast<Argument_Ptr_Const>(&rhs);
+        Argument_Ptr_Const m = Cast<Argument>(&rhs);
         if (!(m && name() == m->name())) return false;
         return *value() == *m->value();
       }
@@ -1412,19 +1430,55 @@
     ATTACH_OPERATIONS()
   };
 
+  ////////////////////////////////////////////////////
+  // Function reference.
+  ////////////////////////////////////////////////////
+  class Function : public Value {
+  public:
+    ADD_PROPERTY(Definition_Obj, definition)
+    ADD_PROPERTY(bool, is_css)
+  public:
+    Function(ParserState pstate, Definition_Obj def, bool css)
+    : Value(pstate), definition_(def), is_css_(css)
+    { concrete_type(FUNCTION_VAL); }
+    Function(const Function* ptr)
+    : Value(ptr), definition_(ptr->definition_), is_css_(ptr->is_css_)
+    { concrete_type(FUNCTION_VAL); }
+
+    std::string type() const { return "function"; }
+    static std::string type_name() { return "function"; }
+    bool is_invisible() const { return true; }
+
+    std::string name() {
+      if (definition_) {
+        return definition_->name();
+      }
+      return "";
+    }
+
+    virtual bool operator== (const Expression& rhs) const;
+
+    ATTACH_AST_OPERATIONS(Function)
+    ATTACH_OPERATIONS()
+  };
+
   //////////////////
   // Function calls.
   //////////////////
   class Function_Call : public PreValue {
-    ADD_HASHED(std::string, name)
-    ADD_HASHED(Arguments_Obj, arguments)
+    HASH_CONSTREF(std::string, name)
+    HASH_PROPERTY(Arguments_Obj, arguments)
+    HASH_PROPERTY(Function_Obj, func)
     ADD_PROPERTY(bool, via_call)
     ADD_PROPERTY(void*, cookie)
     size_t hash_;
   public:
     Function_Call(ParserState pstate, std::string n, Arguments_Obj args, void* cookie)
-    : PreValue(pstate), name_(n), arguments_(args), via_call_(false), cookie_(cookie), hash_(0)
+    : PreValue(pstate), name_(n), arguments_(args), func_(0), via_call_(false), cookie_(cookie), hash_(0)
     { concrete_type(FUNCTION); }
+    Function_Call(ParserState pstate, std::string n, Arguments_Obj args, Function_Obj func)
+    : PreValue(pstate), name_(n), arguments_(args), func_(func), via_call_(false), cookie_(0), hash_(0)
+    { concrete_type(FUNCTION); }
     Function_Call(ParserState pstate, std::string n, Arguments_Obj args)
     : PreValue(pstate), name_(n), arguments_(args), via_call_(false), cookie_(0), hash_(0)
     { concrete_type(FUNCTION); }
@@ -1432,20 +1486,26 @@
     : PreValue(ptr),
       name_(ptr->name_),
       arguments_(ptr->arguments_),
+      func_(ptr->func_),
       via_call_(ptr->via_call_),
       cookie_(ptr->cookie_),
       hash_(ptr->hash_)
     { concrete_type(FUNCTION); }
 
+    bool is_css() {
+      if (func_) return func_->is_css();
+      return false;
+    }
+
     virtual bool operator==(const Expression& rhs) const
     {
       try
       {
-        Function_Call_Ptr_Const m = dynamic_cast<Function_Call_Ptr_Const>(&rhs);
+        Function_Call_Ptr_Const m = Cast<Function_Call>(&rhs);
         if (!(m && name() == m->name())) return false;
         if (!(m && arguments()->length() == m->arguments()->length())) return false;
         for (size_t i =0, L = arguments()->length(); i < L; ++i)
-          if (!((*arguments())[i] == (*m->arguments())[i])) return false;
+          if (!(*(*arguments())[i] == *(*m->arguments())[i])) return false;
         return true;
       }
       catch (std::bad_cast&)
@@ -1491,20 +1551,20 @@
   // Variable references.
   ///////////////////////
   class Variable : public PreValue {
-    ADD_PROPERTY(std::string, name)
+    ADD_CONSTREF(std::string, name)
   public:
     Variable(ParserState pstate, std::string n)
     : PreValue(pstate), name_(n)
-    { }
+    { concrete_type(VARIABLE); }
     Variable(const Variable* ptr)
     : PreValue(ptr), name_(ptr->name_)
-    { }
+    { concrete_type(VARIABLE); }
 
     virtual bool operator==(const Expression& rhs) const
     {
       try
       {
-        Variable_Ptr_Const e = dynamic_cast<Variable_Ptr_Const>(&rhs);
+        Variable_Ptr_Const e = Cast<Variable>(&rhs);
         return e && name() == e->name();
       }
       catch (std::bad_cast&)
@@ -1523,108 +1583,45 @@
     ATTACH_OPERATIONS()
   };
 
-  ////////////////////////////////////////////////////////////////////////////
-  // Textual (i.e., unevaluated) numeric data. Variants are distinguished with
-  // a type tag.
-  ////////////////////////////////////////////////////////////////////////////
-  class Textual : public Expression {
-  public:
-    enum Type { NUMBER, PERCENTAGE, DIMENSION, HEX };
-  private:
-    ADD_HASHED(Type, type)
-    ADD_HASHED(std::string, value)
-    size_t hash_;
-  public:
-    Textual(ParserState pstate, Type t, std::string val)
-    : Expression(pstate, DELAYED), type_(t), value_(val),
-      hash_(0)
-    { }
-    Textual(const Textual* ptr)
-    : Expression(ptr),
-      type_(ptr->type_),
-      value_(ptr->value_),
-      hash_(ptr->hash_)
-    { }
-
-    virtual bool operator==(const Expression& rhs) const
-    {
-      try
-      {
-        Textual_Ptr_Const e = dynamic_cast<Textual_Ptr_Const>(&rhs);
-        return e && value() == e->value() && type() == e->type();
-      }
-      catch (std::bad_cast&)
-      {
-        return false;
-      }
-      catch (...) { throw; }
-    }
-
-    virtual size_t hash()
-    {
-      if (hash_ == 0) {
-        hash_ = std::hash<std::string>()(value_);
-        hash_combine(hash_, std::hash<int>()(type_));
-      }
-      return hash_;
-    }
-
-    ATTACH_AST_OPERATIONS(Textual)
-    ATTACH_OPERATIONS()
-  };
-
   ////////////////////////////////////////////////
   // Numbers, percentages, dimensions, and colors.
   ////////////////////////////////////////////////
-  class Number : public Value {
-    ADD_HASHED(double, value)
+  class Number : public Value, public Units {
+    HASH_PROPERTY(double, value)
     ADD_PROPERTY(bool, zero)
-    std::vector<std::string> numerator_units_;
-    std::vector<std::string> denominator_units_;
     size_t hash_;
   public:
     Number(ParserState pstate, double val, std::string u = "", bool zero = true);
 
     Number(const Number* ptr)
     : Value(ptr),
+      Units(ptr),
       value_(ptr->value_), zero_(ptr->zero_),
-      numerator_units_(ptr->numerator_units_),
-      denominator_units_(ptr->denominator_units_),
       hash_(ptr->hash_)
     { concrete_type(NUMBER); }
 
     bool zero() { return zero_; }
-    bool is_valid_css_unit() const;
-    std::vector<std::string>& numerator_units()   { return numerator_units_; }
-    std::vector<std::string>& denominator_units() { return denominator_units_; }
-    const std::vector<std::string>& numerator_units() const   { return numerator_units_; }
-    const std::vector<std::string>& denominator_units() const { return denominator_units_; }
-    std::string type() { return "number"; }
+    std::string type() const { return "number"; }
     static std::string type_name() { return "number"; }
-    std::string unit() const;
 
-    bool is_unitless() const;
-    double convert_factor(const Number&) const;
-    bool convert(const std::string& unit = "", bool strict = false);
-    void normalize(const std::string& unit = "", bool strict = false);
-    // useful for making one number compatible with another
-    std::string find_convertible_unit() const;
+    void reduce();
+    void normalize();
 
     virtual size_t hash()
     {
       if (hash_ == 0) {
         hash_ = std::hash<double>()(value_);
-        for (const auto numerator : numerator_units())
+        for (const auto numerator : numerators)
           hash_combine(hash_, std::hash<std::string>()(numerator));
-        for (const auto denominator : denominator_units())
+        for (const auto denominator : denominators)
           hash_combine(hash_, std::hash<std::string>()(denominator));
       }
       return hash_;
     }
 
     virtual bool operator< (const Number& rhs) const;
+    virtual bool operator== (const Number& rhs) const;
     virtual bool operator== (const Expression& rhs) const;
-    virtual bool eq(const Expression& rhs) const;
     ATTACH_AST_OPERATIONS(Number)
     ATTACH_OPERATIONS()
   };
@@ -1633,11 +1630,11 @@
   // Colors.
   //////////
   class Color : public Value {
-    ADD_HASHED(double, r)
-    ADD_HASHED(double, g)
-    ADD_HASHED(double, b)
-    ADD_HASHED(double, a)
-    ADD_PROPERTY(std::string, disp)
+    HASH_PROPERTY(double, r)
+    HASH_PROPERTY(double, g)
+    HASH_PROPERTY(double, b)
+    HASH_PROPERTY(double, a)
+    ADD_CONSTREF(std::string, disp)
     size_t hash_;
   public:
     Color(ParserState pstate, double r, double g, double b, double a = 1, const std::string disp = "")
@@ -1653,7 +1650,7 @@
       disp_(ptr->disp_),
       hash_(ptr->hash_)
     { concrete_type(COLOR); }
-    std::string type() { return "color"; }
+    std::string type() const { return "color"; }
     static std::string type_name() { return "color"; }
 
     virtual size_t hash()
@@ -1677,7 +1674,7 @@
   // Errors from Sass_Values.
   //////////////////////////////
   class Custom_Error : public Value {
-    ADD_PROPERTY(std::string, message)
+    ADD_CONSTREF(std::string, message)
   public:
     Custom_Error(ParserState pstate, std::string msg)
     : Value(pstate), message_(msg)
@@ -1694,7 +1691,7 @@
   // Warnings from Sass_Values.
   //////////////////////////////
   class Custom_Warning : public Value {
-    ADD_PROPERTY(std::string, message)
+    ADD_CONSTREF(std::string, message)
   public:
     Custom_Warning(ParserState pstate, std::string msg)
     : Value(pstate), message_(msg)
@@ -1711,7 +1708,7 @@
   // Booleans.
   ////////////
   class Boolean : public Value {
-    ADD_HASHED(bool, value)
+    HASH_PROPERTY(bool, value)
     size_t hash_;
   public:
     Boolean(ParserState pstate, bool val)
@@ -1724,7 +1721,7 @@
       hash_(ptr->hash_)
     { concrete_type(BOOLEAN); }
     virtual operator bool() { return value_; }
-    std::string type() { return "bool"; }
+    std::string type() const { return "bool"; }
     static std::string type_name() { return "bool"; }
     virtual bool is_false() { return !value_; }
 
@@ -1757,8 +1754,6 @@
     static std::string type_name() { return "string"; }
     virtual ~String() = 0;
     virtual void rtrim() = 0;
-    virtual void ltrim() = 0;
-    virtual void trim() = 0;
     virtual bool operator==(const Expression& rhs) const = 0;
     virtual bool operator<(const Expression& rhs) const {
       return this->to_string() < rhs.to_string();
@@ -1773,19 +1768,20 @@
   // evaluation phase.
   ///////////////////////////////////////////////////////////////////////
   class String_Schema : public String, public Vectorized<Expression_Obj> {
-    // ADD_PROPERTY(bool, has_interpolants)
+    ADD_PROPERTY(bool, css)
     size_t hash_;
   public:
-    String_Schema(ParserState pstate, size_t size = 0, bool has_interpolants = false)
-    : String(pstate), Vectorized<Expression_Obj>(size), hash_(0)
+    String_Schema(ParserState pstate, size_t size = 0, bool css = true)
+    : String(pstate), Vectorized<Expression_Obj>(size), css_(css), hash_(0)
     { concrete_type(STRING); }
     String_Schema(const String_Schema* ptr)
     : String(ptr),
       Vectorized<Expression_Obj>(*ptr),
+      css_(ptr->css_),
       hash_(ptr->hash_)
     { concrete_type(STRING); }
 
-    std::string type() { return "string"; }
+    std::string type() const { return "string"; }
     static std::string type_name() { return "string"; }
 
     bool is_left_interpolant(void) const;
@@ -1798,8 +1794,6 @@
       return false;
     }
     virtual void rtrim();
-    virtual void ltrim();
-    virtual void trim();
 
     virtual size_t hash()
     {
@@ -1825,7 +1819,7 @@
   class String_Constant : public String {
     ADD_PROPERTY(char, quote_mark)
     ADD_PROPERTY(bool, can_compress_whitespace)
-    ADD_HASHED(std::string, value)
+    HASH_CONSTREF(std::string, value)
   protected:
     size_t hash_;
   public:
@@ -1836,24 +1830,22 @@
       value_(ptr->value_),
       hash_(ptr->hash_)
     { }
-    String_Constant(ParserState pstate, std::string val)
-    : String(pstate), quote_mark_(0), can_compress_whitespace_(false), value_(read_css_string(val)), hash_(0)
+    String_Constant(ParserState pstate, std::string val, bool css = true)
+    : String(pstate), quote_mark_(0), can_compress_whitespace_(false), value_(read_css_string(val, css)), hash_(0)
     { }
-    String_Constant(ParserState pstate, const char* beg)
-    : String(pstate), quote_mark_(0), can_compress_whitespace_(false), value_(read_css_string(std::string(beg))), hash_(0)
+    String_Constant(ParserState pstate, const char* beg, bool css = true)
+    : String(pstate), quote_mark_(0), can_compress_whitespace_(false), value_(read_css_string(std::string(beg), css)), hash_(0)
     { }
-    String_Constant(ParserState pstate, const char* beg, const char* end)
-    : String(pstate), quote_mark_(0), can_compress_whitespace_(false), value_(read_css_string(std::string(beg, end-beg))), hash_(0)
+    String_Constant(ParserState pstate, const char* beg, const char* end, bool css = true)
+    : String(pstate), quote_mark_(0), can_compress_whitespace_(false), value_(read_css_string(std::string(beg, end-beg), css)), hash_(0)
     { }
-    String_Constant(ParserState pstate, const Token& tok)
-    : String(pstate), quote_mark_(0), can_compress_whitespace_(false), value_(read_css_string(std::string(tok.begin, tok.end))), hash_(0)
+    String_Constant(ParserState pstate, const Token& tok, bool css = true)
+    : String(pstate), quote_mark_(0), can_compress_whitespace_(false), value_(read_css_string(std::string(tok.begin, tok.end), css)), hash_(0)
     { }
-    std::string type() { return "string"; }
+    std::string type() const { return "string"; }
     static std::string type_name() { return "string"; }
     virtual bool is_invisible() const;
     virtual void rtrim();
-    virtual void ltrim();
-    virtual void trim();
 
     virtual size_t hash()
     {
@@ -1881,8 +1873,8 @@
   public:
     String_Quoted(ParserState pstate, std::string val, char q = 0,
       bool keep_utf8_escapes = false, bool skip_unquoting = false,
-      bool strict_unquoting = true)
-    : String_Constant(pstate, val)
+      bool strict_unquoting = true, bool css = true)
+    : String_Constant(pstate, val, css)
     {
       if (skip_unquoting == false) {
         value_ = unquote(value_, &quote_mark_, keep_utf8_escapes, strict_unquoting);
@@ -2103,7 +2095,7 @@
 
       if (s->statement_type() == Statement::DIRECTIVE)
       {
-        if (Directive_Obj dir = SASS_MEMORY_CAST(Directive, s))
+        if (Directive_Obj dir = Cast<Directive>(s))
         {
           std::string keyword(dir->keyword());
           if (keyword.length() > 0) keyword.erase(0, 1);
@@ -2122,7 +2114,7 @@
       {
         return expression()->exclude("supports");
       }
-      if (Directive_Obj dir = SASS_MEMORY_CAST(Directive, s))
+      if (Directive_Obj dir = Cast<Directive>(s))
       {
         if (dir->is_keyframes()) return expression()->exclude("keyframes");
       }
@@ -2139,7 +2131,7 @@
   public:
     Null(ParserState pstate) : Value(pstate) { concrete_type(NULL_VAL); }
     Null(const Null* ptr) : Value(ptr) { concrete_type(NULL_VAL); }
-    std::string type() { return "null"; }
+    std::string type() const { return "null"; }
     static std::string type_name() { return "null"; }
     bool is_invisible() const { return true; }
     operator bool() { return false; }
@@ -2172,7 +2164,7 @@
   // Individual parameter objects for mixins and functions.
   /////////////////////////////////////////////////////////
   class Parameter : public AST_Node {
-    ADD_PROPERTY(std::string, name)
+    ADD_CONSTREF(std::string, name)
     ADD_PROPERTY(Expression_Obj, default_value)
     ADD_PROPERTY(bool, is_rest_parameter)
   public:
@@ -2180,9 +2172,11 @@
               std::string n, Expression_Obj def = 0, bool rest = false)
     : AST_Node(pstate), name_(n), default_value_(def), is_rest_parameter_(rest)
     {
-      if (default_value_ && is_rest_parameter_) {
-        error("variable-length parameter may not have a default value", pstate_);
-      }
+      // tried to come up with a spec test for this, but it does no longer
+      // get  past the parser (it error out earlier). A spec test was added!
+      // if (default_value_ && is_rest_parameter_) {
+      //   error("variable-length parameter may not have a default value", pstate_);
+      // }
     }
     Parameter(const Parameter* ptr)
     : AST_Node(ptr),
@@ -2190,9 +2184,11 @@
       default_value_(ptr->default_value_),
       is_rest_parameter_(ptr->is_rest_parameter_)
     {
-      if (default_value_ && is_rest_parameter_) {
-        error("variable-length parameter may not have a default value", pstate_);
-      }
+      // tried to come up with a spec test for this, but it does no longer
+      // get  past the parser (it error out earlier). A spec test was added!
+      // if (default_value_ && is_rest_parameter_) {
+      //   error("variable-length parameter may not have a default value", pstate_);
+      // }
     }
     ATTACH_AST_OPERATIONS(Parameter)
     ATTACH_OPERATIONS()
@@ -2210,23 +2206,23 @@
     void adjust_after_pushing(Parameter_Obj p)
     {
       if (p->default_value()) {
-        if (has_rest_parameter_) {
-          error("optional parameters may not be combined with variable-length parameters", p->pstate());
+        if (has_rest_parameter()) {
+          coreError("optional parameters may not be combined with variable-length parameters", p->pstate());
         }
-        has_optional_parameters_ = true;
+        has_optional_parameters(true);
       }
       else if (p->is_rest_parameter()) {
-        if (has_rest_parameter_) {
-          error("functions and mixins cannot have more than one variable-length parameter", p->pstate());
+        if (has_rest_parameter()) {
+          coreError("functions and mixins cannot have more than one variable-length parameter", p->pstate());
         }
-        has_rest_parameter_ = true;
+        has_rest_parameter(true);
       }
       else {
-        if (has_rest_parameter_) {
-          error("required parameters must precede variable-length parameters", p->pstate());
+        if (has_rest_parameter()) {
+          coreError("required parameters must precede variable-length parameters", p->pstate());
         }
-        if (has_optional_parameters_) {
-          error("required parameters must precede optional parameters", p->pstate());
+        if (has_optional_parameters()) {
+          coreError("required parameters must precede optional parameters", p->pstate());
         }
       }
     }
@@ -2266,9 +2262,8 @@
   protected:
     size_t hash_;
   public:
-    Selector(ParserState pstate, bool r = false, bool h = false)
+    Selector(ParserState pstate)
     : Expression(pstate),
-      // has_reference_(r),
       has_line_feed_(false),
       has_line_break_(false),
       is_optional_(false),
@@ -2286,21 +2281,19 @@
     { concrete_type(SELECTOR); }
     virtual ~Selector() = 0;
     virtual size_t hash() = 0;
-    virtual unsigned long specificity() {
-      return 0;
-    }
+    virtual unsigned long specificity() const = 0;
     virtual void set_media_block(Media_Block_Ptr mb) {
       media_block(mb);
     }
-    virtual bool has_parent_ref() {
+    virtual bool has_parent_ref() const {
       return false;
     }
-    virtual bool has_real_parent_ref() {
+    virtual bool has_real_parent_ref() const {
       return false;
     }
     // dispatch to correct handlers
-    virtual bool operator<(const Selector& rhs) const;
-    virtual bool operator==(const Selector& rhs) const;
+    virtual bool operator<(const Selector& rhs) const = 0;
+    virtual bool operator==(const Selector& rhs) const = 0;
     ATTACH_VIRTUAL_AST_OPERATIONS(Selector);
   };
   inline Selector::~Selector() { }
@@ -2309,20 +2302,36 @@
   // Interpolated selectors -- the interpolated String will be expanded and
   // re-parsed into a normal selector class.
   /////////////////////////////////////////////////////////////////////////
-  class Selector_Schema : public Selector {
+  class Selector_Schema : public AST_Node {
     ADD_PROPERTY(String_Obj, contents)
-    ADD_PROPERTY(bool, at_root);
+    ADD_PROPERTY(bool, connect_parent);
+    // must not be a reference counted object
+    // otherwise we create circular references
+    ADD_PROPERTY(Media_Block_Ptr, media_block)
+    // store computed hash
+    size_t hash_;
   public:
     Selector_Schema(ParserState pstate, String_Obj c)
-    : Selector(pstate), contents_(c), at_root_(false)
+    : AST_Node(pstate),
+      contents_(c),
+      connect_parent_(true),
+      media_block_(NULL),
+      hash_(0)
     { }
     Selector_Schema(const Selector_Schema* ptr)
-    : Selector(ptr),
+    : AST_Node(ptr),
       contents_(ptr->contents_),
-      at_root_(ptr->at_root_)
+      connect_parent_(ptr->connect_parent_),
+      media_block_(ptr->media_block_),
+      hash_(ptr->hash_)
     { }
-    virtual bool has_parent_ref();
-    virtual bool has_real_parent_ref();
+    virtual bool has_parent_ref() const;
+    virtual bool has_real_parent_ref() const;
+    virtual bool operator<(const Selector& rhs) const;
+    virtual bool operator==(const Selector& rhs) const;
+    // selector schema is not yet a final selector, so we do not
+    // have a specificity for it yet. We need to
+    virtual unsigned long specificity() const { return 0; }
     virtual size_t hash() {
       if (hash_ == 0) {
         hash_combine(hash_, contents_->hash());
@@ -2337,8 +2346,8 @@
   // Abstract base class for simple selectors.
   ////////////////////////////////////////////
   class Simple_Selector : public Selector {
-    ADD_PROPERTY(std::string, ns)
-    ADD_PROPERTY(std::string, name)
+    ADD_CONSTREF(std::string, ns)
+    ADD_CONSTREF(std::string, name)
     ADD_PROPERTY(Simple_Type, simple_type)
     ADD_PROPERTY(bool, has_ns)
   public:
@@ -2360,10 +2369,6 @@
       name_(ptr->name_),
       has_ns_(ptr->has_ns_)
     { simple_type(SIMPLE); }
-    virtual bool unique() const
-    {
-      return false;
-    }
     virtual std::string ns_name() const
     {
       std::string name("");
@@ -2380,6 +2385,8 @@
       }
       return hash_;
     }
+    // namespace compare functions
+    bool is_ns_eq(const Simple_Selector& r) const;
     // namespace query functions
     bool is_universal_ns() const
     {
@@ -2412,11 +2419,10 @@
     }
 
     virtual ~Simple_Selector() = 0;
-    virtual Compound_Selector_Ptr unify_with(Compound_Selector_Ptr, Context&);
-    virtual bool has_parent_ref() { return false; };
-    virtual bool has_real_parent_ref() { return false; };
-    virtual bool is_pseudo_element() { return false; }
-    virtual bool is_pseudo_class() { return false; }
+    virtual Compound_Selector_Ptr unify_with(Compound_Selector_Ptr);
+    virtual bool has_parent_ref() const { return false; };
+    virtual bool has_real_parent_ref() const  { return false; };
+    virtual bool is_pseudo_element() const { return false; }
 
     virtual bool is_superselector_of(Compound_Selector_Obj sub) { return false; }
 
@@ -2448,14 +2454,14 @@
     Parent_Selector(const Parent_Selector* ptr)
     : Simple_Selector(ptr), real_(ptr->real_)
     { /* has_reference(true); */ }
-    bool is_real_parent_ref() { return real(); };
-    virtual bool has_parent_ref() { return true; };
-    virtual bool has_real_parent_ref() { return is_real_parent_ref(); };
-    virtual unsigned long specificity()
+    bool is_real_parent_ref() const { return real(); };
+    virtual bool has_parent_ref() const { return true; };
+    virtual bool has_real_parent_ref() const { return is_real_parent_ref(); };
+    virtual unsigned long specificity() const
     {
       return 0;
     }
-    std::string type() { return "selector"; }
+    std::string type() const { return "selector"; }
     static std::string type_name() { return "selector"; }
     ATTACH_AST_OPERATIONS(Parent_Selector)
     ATTACH_OPERATIONS()
@@ -2472,7 +2478,7 @@
     Placeholder_Selector(const Placeholder_Selector* ptr)
     : Simple_Selector(ptr)
     { }
-    virtual unsigned long specificity()
+    virtual unsigned long specificity() const
     {
       return Constants::Specificity_Base;
     }
@@ -2495,13 +2501,17 @@
     Element_Selector(const Element_Selector* ptr)
     : Simple_Selector(ptr)
     { }
-    virtual unsigned long specificity()
+    virtual unsigned long specificity() const
     {
       if (name() == "*") return 0;
       else               return Constants::Specificity_Element;
     }
-    virtual Simple_Selector_Ptr unify_with(Simple_Selector_Ptr, Context&);
-    virtual Compound_Selector_Ptr unify_with(Compound_Selector_Ptr, Context&);
+    virtual Simple_Selector_Ptr unify_with(Simple_Selector_Ptr);
+    virtual Compound_Selector_Ptr unify_with(Compound_Selector_Ptr);
+    virtual bool operator==(const Simple_Selector& rhs) const;
+    virtual bool operator==(const Element_Selector& rhs) const;
+    virtual bool operator<(const Simple_Selector& rhs) const;
+    virtual bool operator<(const Element_Selector& rhs) const;
     ATTACH_AST_OPERATIONS(Element_Selector)
     ATTACH_OPERATIONS()
   };
@@ -2517,15 +2527,11 @@
     Class_Selector(const Class_Selector* ptr)
     : Simple_Selector(ptr)
     { }
-    virtual bool unique() const
-    {
-      return false;
-    }
-    virtual unsigned long specificity()
+    virtual unsigned long specificity() const
     {
       return Constants::Specificity_Class;
     }
-    virtual Compound_Selector_Ptr unify_with(Compound_Selector_Ptr, Context&);
+    virtual Compound_Selector_Ptr unify_with(Compound_Selector_Ptr);
     ATTACH_AST_OPERATIONS(Class_Selector)
     ATTACH_OPERATIONS()
   };
@@ -2541,15 +2547,11 @@
     Id_Selector(const Id_Selector* ptr)
     : Simple_Selector(ptr)
     { }
-    virtual bool unique() const
-    {
-      return true;
-    }
-    virtual unsigned long specificity()
+    virtual unsigned long specificity() const
     {
       return Constants::Specificity_ID;
     }
-    virtual Compound_Selector_Ptr unify_with(Compound_Selector_Ptr, Context&);
+    virtual Compound_Selector_Ptr unify_with(Compound_Selector_Ptr);
     ATTACH_AST_OPERATIONS(Id_Selector)
     ATTACH_OPERATIONS()
   };
@@ -2558,17 +2560,19 @@
   // Attribute selectors -- e.g., [src*=".jpg"], etc.
   ///////////////////////////////////////////////////
   class Attribute_Selector : public Simple_Selector {
-    ADD_PROPERTY(std::string, matcher)
+    ADD_CONSTREF(std::string, matcher)
     // this cannot be changed to obj atm!!!!!!????!!!!!!!
     ADD_PROPERTY(String_Obj, value) // might be interpolated
+    ADD_PROPERTY(char, modifier);
   public:
-    Attribute_Selector(ParserState pstate, std::string n, std::string m, String_Obj v)
-    : Simple_Selector(pstate, n), matcher_(m), value_(v)
+    Attribute_Selector(ParserState pstate, std::string n, std::string m, String_Obj v, char o = 0)
+    : Simple_Selector(pstate, n), matcher_(m), value_(v), modifier_(o)
     { simple_type(ATTR_SEL); }
     Attribute_Selector(const Attribute_Selector* ptr)
     : Simple_Selector(ptr),
       matcher_(ptr->matcher_),
-      value_(ptr->value_)
+      value_(ptr->value_),
+      modifier_(ptr->modifier_)
     { simple_type(ATTR_SEL); }
     virtual size_t hash()
     {
@@ -2579,7 +2583,7 @@
       }
       return hash_;
     }
-    virtual unsigned long specificity()
+    virtual unsigned long specificity() const
     {
       return Constants::Specificity_Attr;
     }
@@ -2617,14 +2621,6 @@
     : Simple_Selector(ptr), expression_(ptr->expression_)
     { simple_type(PSEUDO_SEL); }
 
-    // A pseudo-class always consists of a "colon" (:) followed by the name
-    // of the pseudo-class and optionally by a value between parentheses.
-    virtual bool is_pseudo_class()
-    {
-      return (name_[0] == ':' && name_[1] != ':')
-             && ! is_pseudo_class_element(name_);
-    }
-
     // A pseudo-element is made of two colons (::) followed by the name.
     // The `::` notation is introduced by the current document in order to
     // establish a discrimination between pseudo-classes and pseudo-elements.
@@ -2633,7 +2629,7 @@
     // in CSS levels 1 and 2 (namely, :first-line, :first-letter, :before and
     // :after). This compatibility is not allowed for the new pseudo-elements
     // introduced in this specification.
-    virtual bool is_pseudo_element()
+    virtual bool is_pseudo_element() const
     {
       return (name_[0] == ':' && name_[1] == ':')
              || is_pseudo_class_element(name_);
@@ -2646,7 +2642,7 @@
       }
       return hash_;
     }
-    virtual unsigned long specificity()
+    virtual unsigned long specificity() const
     {
       if (is_pseudo_element())
         return Constants::Specificity_Element;
@@ -2656,7 +2652,7 @@
     virtual bool operator==(const Pseudo_Selector& rhs) const;
     virtual bool operator<(const Simple_Selector& rhs) const;
     virtual bool operator<(const Pseudo_Selector& rhs) const;
-    virtual Compound_Selector_Ptr unify_with(Compound_Selector_Ptr, Context&);
+    virtual Compound_Selector_Ptr unify_with(Compound_Selector_Ptr);
     ATTACH_AST_OPERATIONS(Pseudo_Selector)
     ATTACH_OPERATIONS()
   };
@@ -2665,9 +2661,9 @@
   // Wrapped selector -- pseudo selector that takes a list of selectors as argument(s) e.g., :not(:first-of-type), :-moz-any(ol p.blah, ul, menu, dir)
   /////////////////////////////////////////////////
   class Wrapped_Selector : public Simple_Selector {
-    ADD_PROPERTY(Selector_Obj, selector)
+    ADD_PROPERTY(Selector_List_Obj, selector)
   public:
-    Wrapped_Selector(ParserState pstate, std::string n, Selector_Obj sel)
+    Wrapped_Selector(ParserState pstate, std::string n, Selector_List_Obj sel)
     : Simple_Selector(pstate, n), selector_(sel)
     { simple_type(WRAPPED_SEL); }
     Wrapped_Selector(const Wrapped_Selector* ptr)
@@ -2676,28 +2672,11 @@
     virtual bool is_superselector_of(Wrapped_Selector_Obj sub);
     // Selectors inside the negation pseudo-class are counted like any
     // other, but the negation itself does not count as a pseudo-class.
-    virtual size_t hash()
-    {
-      if (hash_ == 0) {
-        hash_combine(hash_, Simple_Selector::hash());
-        if (selector_) hash_combine(hash_, selector_->hash());
-      }
-      return hash_;
-    }
-    virtual bool has_parent_ref() {
-      // if (has_reference()) return true;
-      if (!selector()) return false;
-      return selector()->has_parent_ref();
-    }
-    virtual bool has_real_parent_ref() {
-      // if (has_reference()) return true;
-      if (!selector()) return false;
-      return selector()->has_real_parent_ref();
-    }
-    virtual unsigned long specificity()
-    {
-      return selector_ ? selector_->specificity() : 0;
-    }
+    virtual size_t hash();
+    virtual bool has_parent_ref() const;
+    virtual bool has_real_parent_ref() const;
+    virtual unsigned long specificity() const;
+    virtual bool find ( bool (*f)(AST_Node_Obj) );
     virtual bool operator==(const Simple_Selector& rhs) const;
     virtual bool operator==(const Wrapped_Selector& rhs) const;
     virtual bool operator<(const Simple_Selector& rhs) const;
@@ -2707,18 +2686,13 @@
     ATTACH_OPERATIONS()
   };
 
-  struct Complex_Selector_Pointer_Compare {
-    bool operator() (const Complex_Selector_Obj& pLeft, const Complex_Selector_Obj& pRight) const;
-  };
-
   ////////////////////////////////////////////////////////////////////////////
   // Simple selector sequences. Maintains flags indicating whether it contains
   // any parent references or placeholders, to simplify expansion.
   ////////////////////////////////////////////////////////////////////////////
-  typedef std::set<Complex_Selector_Obj, Complex_Selector_Pointer_Compare> SourcesSet;
   class Compound_Selector : public Selector, public Vectorized<Simple_Selector_Obj> {
   private:
-    SourcesSet sources_;
+    ComplexSelectorSet sources_;
     ADD_PROPERTY(bool, extended);
     ADD_PROPERTY(bool, has_parent_reference);
   protected:
@@ -2755,20 +2729,15 @@
     }
 
     Complex_Selector_Obj to_complex();
-    Compound_Selector_Ptr unify_with(Compound_Selector_Ptr rhs, Context& ctx);
+    Compound_Selector_Ptr unify_with(Compound_Selector_Ptr rhs);
     // virtual Placeholder_Selector_Ptr find_placeholder();
-    virtual bool has_parent_ref();
-    virtual bool has_real_parent_ref();
-    Simple_Selector_Ptr base()
-    {
-      // Implement non-const in terms of const. Safe to const_cast since this method is non-const
-      return const_cast<Simple_Selector_Ptr>(static_cast<Compound_Selector_Ptr_Const>(this)->base());
-    }
-    Simple_Selector_Ptr_Const base() const {
+    virtual bool has_parent_ref() const;
+    virtual bool has_real_parent_ref() const;
+    Simple_Selector_Ptr base() const {
       if (length() == 0) return 0;
       // ToDo: why is this needed?
-      if (SASS_MEMORY_CAST(Element_Selector, (*this)[0]))
-        return &(*this)[0];
+      if (Cast<Element_Selector>((*this)[0]))
+        return (*this)[0];
       return 0;
     }
     virtual bool is_superselector_of(Compound_Selector_Obj sub, std::string wrapped = "");
@@ -2782,7 +2751,7 @@
       }
       return Selector::hash_;
     }
-    virtual unsigned long specificity()
+    virtual unsigned long specificity() const
     {
       int sum = 0;
       for (size_t i = 0, L = length(); i < L; ++i)
@@ -2802,19 +2771,21 @@
     bool is_empty_reference()
     {
       return length() == 1 &&
-             SASS_MEMORY_CAST(Parent_Selector, (*this)[0]);
+             Cast<Parent_Selector>((*this)[0]);
     }
-    std::vector<Subset_Map_Key> to_str_vec(); // sometimes need to convert to a flat "by-value" data structure
 
+    virtual bool find ( bool (*f)(AST_Node_Obj) );
+    virtual bool operator<(const Selector& rhs) const;
+    virtual bool operator==(const Selector& rhs) const;
     virtual bool operator<(const Compound_Selector& rhs) const;
     virtual bool operator==(const Compound_Selector& rhs) const;
     inline bool operator!=(const Compound_Selector& rhs) const { return !(*this == rhs); }
 
-    SourcesSet& sources() { return sources_; }
+    ComplexSelectorSet& sources() { return sources_; }
     void clearSources() { sources_.clear(); }
-    void mergeSources(SourcesSet& sources, Context& ctx);
+    void mergeSources(ComplexSelectorSet& sources);
 
-    Compound_Selector_Ptr minus(Compound_Selector_Ptr rhs, Context& ctx);
+    Compound_Selector_Ptr minus(Compound_Selector_Ptr rhs);
     virtual void cloneChildren();
     ATTACH_AST_OPERATIONS(Compound_Selector)
     ATTACH_OPERATIONS()
@@ -2829,10 +2800,10 @@
   public:
     enum Combinator { ANCESTOR_OF, PARENT_OF, PRECEDES, ADJACENT_TO, REFERENCE };
   private:
-    ADD_PROPERTY(Combinator, combinator)
-    ADD_PROPERTY(Compound_Selector_Obj, head)
-    ADD_PROPERTY(Complex_Selector_Obj, tail)
-    ADD_PROPERTY(String_Obj, reference);
+    HASH_CONSTREF(Combinator, combinator)
+    HASH_PROPERTY(Compound_Selector_Obj, head)
+    HASH_PROPERTY(Complex_Selector_Obj, tail)
+    HASH_PROPERTY(String_Obj, reference);
   public:
     bool contains_placeholder() {
       if (head() && head()->contains_placeholder()) return true;
@@ -2855,8 +2826,8 @@
       head_(ptr->head_), tail_(ptr->tail_),
       reference_(ptr->reference_)
     {};
-    virtual bool has_parent_ref();
-    virtual bool has_real_parent_ref();
+    virtual bool has_parent_ref() const;
+    virtual bool has_real_parent_ref() const;
 
     Complex_Selector_Obj skip_empty_reference()
     {
@@ -2878,10 +2849,7 @@
              combinator() == Combinator::ANCESTOR_OF;
     }
 
-    Complex_Selector_Obj context(Context&);
-
-
-    Selector_List_Ptr tails(Context& ctx, Selector_List_Ptr tails);
+    Selector_List_Ptr tails(Selector_List_Ptr tails);
 
     // front returns the first real tail
     // skips over parent and empty ones
@@ -2893,13 +2861,13 @@
     Complex_Selector_Obj innermost() { return last(); };
 
     size_t length() const;
-    Selector_List_Ptr resolve_parent_refs(Context& ctx, std::vector<Selector_List_Obj>& pstack, bool implicit_parent = true);
+    Selector_List_Ptr resolve_parent_refs(std::vector<Selector_List_Obj>& pstack, Backtraces& traces, bool implicit_parent = true);
     virtual bool is_superselector_of(Compound_Selector_Obj sub, std::string wrapping = "");
     virtual bool is_superselector_of(Complex_Selector_Obj sub, std::string wrapping = "");
     virtual bool is_superselector_of(Selector_List_Obj sub, std::string wrapping = "");
-    Selector_List_Ptr unify_with(Complex_Selector_Ptr rhs, Context& ctx);
+    Selector_List_Ptr unify_with(Complex_Selector_Ptr rhs);
     Combinator clear_innermost();
-    void append(Context&, Complex_Selector_Obj);
+    void append(Complex_Selector_Obj, Backtraces& traces);
     void set_innermost(Complex_Selector_Obj, Combinator);
     virtual size_t hash()
     {
@@ -2928,55 +2896,58 @@
       if (tail_ && tail_->has_placeholder()) return true;
       return false;
     }
+    virtual bool find ( bool (*f)(AST_Node_Obj) );
+    virtual bool operator<(const Selector& rhs) const;
+    virtual bool operator==(const Selector& rhs) const;
     virtual bool operator<(const Complex_Selector& rhs) const;
     virtual bool operator==(const Complex_Selector& rhs) const;
     inline bool operator!=(const Complex_Selector& rhs) const { return !(*this == rhs); }
-    SourcesSet sources()
+    const ComplexSelectorSet sources()
     {
       //s = Set.new
       //seq.map {|sseq_or_op| s.merge sseq_or_op.sources if sseq_or_op.is_a?(SimpleSequence)}
       //s
 
-      SourcesSet srcs;
+      ComplexSelectorSet srcs;
 
       Compound_Selector_Obj pHead = head();
       Complex_Selector_Obj  pTail = tail();
 
       if (pHead) {
-        SourcesSet& headSources = pHead->sources();
+        const ComplexSelectorSet& headSources = pHead->sources();
         srcs.insert(headSources.begin(), headSources.end());
       }
 
       if (pTail) {
-        SourcesSet tailSources = pTail->sources();
+        const ComplexSelectorSet& tailSources = pTail->sources();
         srcs.insert(tailSources.begin(), tailSources.end());
       }
 
       return srcs;
     }
-    void addSources(SourcesSet& sources, Context& ctx) {
+    void addSources(ComplexSelectorSet& sources) {
       // members.map! {|m| m.is_a?(SimpleSequence) ? m.with_more_sources(sources) : m}
       Complex_Selector_Ptr pIter = this;
       while (pIter) {
-        Compound_Selector_Ptr pHead = &pIter->head();
+        Compound_Selector_Ptr pHead = pIter->head();
 
         if (pHead) {
-          pHead->mergeSources(sources, ctx);
+          pHead->mergeSources(sources);
         }
 
-        pIter = &pIter->tail();
+        pIter = pIter->tail();
       }
     }
     void clearSources() {
       Complex_Selector_Ptr pIter = this;
       while (pIter) {
-        Compound_Selector_Ptr pHead = &pIter->head();
+        Compound_Selector_Ptr pHead = pIter->head();
 
         if (pHead) {
           pHead->clearSources();
         }
 
-        pIter = &pIter->tail();
+        pIter = pIter->tail();
       }
     }
 
@@ -2985,36 +2956,40 @@
     ATTACH_OPERATIONS()
   };
 
-  typedef std::deque<Complex_Selector_Obj> ComplexSelectorDeque;
-
   ///////////////////////////////////
   // Comma-separated selector groups.
   ///////////////////////////////////
   class Selector_List : public Selector, public Vectorized<Complex_Selector_Obj> {
-    ADD_PROPERTY(std::vector<std::string>, wspace)
+    ADD_PROPERTY(Selector_Schema_Obj, schema)
+    ADD_CONSTREF(std::vector<std::string>, wspace)
   protected:
     void adjust_after_pushing(Complex_Selector_Obj c);
   public:
     Selector_List(ParserState pstate, size_t s = 0)
-    : Selector(pstate), Vectorized<Complex_Selector_Obj>(s), wspace_(0)
+    : Selector(pstate),
+      Vectorized<Complex_Selector_Obj>(s),
+      schema_(NULL),
+      wspace_(0)
     { }
     Selector_List(const Selector_List* ptr)
     : Selector(ptr),
       Vectorized<Complex_Selector_Obj>(*ptr),
+      schema_(ptr->schema_),
       wspace_(ptr->wspace_)
     { }
-    std::string type() { return "list"; }
+    std::string type() const { return "list"; }
     // remove parent selector references
     // basically unwraps parsed selectors
-    virtual bool has_parent_ref();
-    virtual bool has_real_parent_ref();
+    virtual bool has_parent_ref() const;
+    virtual bool has_real_parent_ref() const;
     void remove_parent_selectors();
-    Selector_List_Ptr resolve_parent_refs(Context& ctx, std::vector<Selector_List_Obj>& pstack, bool implicit_parent = true);
+    Selector_List_Ptr resolve_parent_refs(std::vector<Selector_List_Obj>& pstack, Backtraces& traces, bool implicit_parent = true);
     virtual bool is_superselector_of(Compound_Selector_Obj sub, std::string wrapping = "");
     virtual bool is_superselector_of(Complex_Selector_Obj sub, std::string wrapping = "");
     virtual bool is_superselector_of(Selector_List_Obj sub, std::string wrapping = "");
-    Selector_List_Ptr unify_with(Selector_List_Ptr, Context&);
-    void populate_extends(Selector_List_Obj, Context&, Subset_Map&);
+    Selector_List_Ptr unify_with(Selector_List_Ptr);
+    void populate_extends(Selector_List_Obj, Subset_Map&);
+    Selector_List_Obj eval(Eval& eval);
     virtual size_t hash()
     {
       if (Selector::hash_ == 0) {
@@ -3023,10 +2998,10 @@
       }
       return Selector::hash_;
     }
-    virtual unsigned long specificity()
+    virtual unsigned long specificity() const
     {
       unsigned long sum = 0;
-      unsigned long specificity = 0;
+      unsigned long specificity;
       for (size_t i = 0, L = length(); i < L; ++i)
       {
         specificity = (*this)[i]->specificity();
@@ -3046,6 +3021,7 @@
       }
       return false;
     }
+    virtual bool find ( bool (*f)(AST_Node_Obj) );
     virtual bool operator<(const Selector& rhs) const;
     virtual bool operator==(const Selector& rhs) const;
     virtual bool operator<(const Selector_List& rhs) const;
@@ -3056,24 +3032,6 @@
     ATTACH_AST_OPERATIONS(Selector_List)
     ATTACH_OPERATIONS()
   };
-
-  template<typename SelectorType>
-  bool selectors_equal(const SelectorType& one, const SelectorType& two, bool simpleSelectorOrderDependent) {
-    // Test for equality among selectors while differentiating between checks that demand the underlying Simple_Selector
-    // ordering to be the same or not. This works because operator< (which doesn't make a whole lot of sense for selectors, but
-    // is required for proper stl collection ordering) is implemented using string comparision. This gives stable sorting
-    // behavior, and can be used to determine if the selectors would have exactly idential output. operator== matches the
-    // ruby sass implementations for eql, which sometimes perform order independent comparisions (like set comparisons of the
-    // members of a SimpleSequence (Compound_Selector)).
-    //
-    // Due to the reliance on operator== and operater< behavior, this templated method is currently only intended for
-    // use with Compound_Selector and Complex_Selector objects.
-    if (simpleSelectorOrderDependent) {
-      return !(one < two) && !(two < one);
-    } else {
-      return one == two;
-    }
-  }
 
   // compare function for sorting and probably other other uses
   struct cmp_complex_selector { inline bool operator() (const Complex_Selector_Obj l, const Complex_Selector_Obj r) { return (*l < *r); } };
diff --git a/libsass/src/ast_def_macros.hpp b/libsass/src/ast_def_macros.hpp
--- a/libsass/src/ast_def_macros.hpp
+++ b/libsass/src/ast_def_macros.hpp
@@ -19,13 +19,22 @@
       this->orig = var;
       *(this->var) = orig;
     }
+    void reset()
+    {
+      *(this->var) = this->orig;
+    }
     ~LocalOption() {
       *(this->var) = this->orig;
     }
 };
 
 #define LOCAL_FLAG(name,opt) LocalOption<bool> flag_##name(name, opt)
+#define LOCAL_COUNT(name,opt) LocalOption<size_t> cnt_##name(name, opt)
 
+#define NESTING_GUARD(name) \
+  LocalOption<size_t> cnt_##name(name, name + 1); \
+  if (name > MAX_NESTING) throw Exception::NestingLimitError(pstate, traces); \
+
 #define ATTACH_OPERATIONS()\
 virtual void perform(Operation<void>* op) { (*op)(this); }\
 virtual AST_Node_Ptr perform(Operation<AST_Node_Ptr>* op) { return (*op)(this); }\
@@ -44,12 +53,28 @@
   type name(type name##__) { return name##_ = name##__; }\
 private:
 
-#define ADD_HASHED(type, name)\
+#define HASH_PROPERTY(type, name)\
 protected:\
   type name##_;\
 public:\
   type name() const        { return name##_; }\
   type name(type name##__) { hash_ = 0; return name##_ = name##__; }\
+private:
+
+#define ADD_CONSTREF(type, name) \
+protected: \
+  type name##_; \
+public: \
+  const type& name() const { return name##_; } \
+  void name(type name##__) { name##_ = name##__; } \
+private:
+
+#define HASH_CONSTREF(type, name) \
+protected: \
+  type name##_; \
+public: \
+  const type& name() const { return name##_; } \
+  void name(type name##__) { hash_ = 0; name##_ = name##__; } \
 private:
 
 #endif
diff --git a/libsass/src/ast_fwd_decl.cpp b/libsass/src/ast_fwd_decl.cpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/ast_fwd_decl.cpp
@@ -0,0 +1,29 @@
+#include "ast.hpp"
+
+namespace Sass {
+
+  #define IMPLEMENT_BASE_CAST(T) \
+  template<> \
+  T* Cast(AST_Node* ptr) { \
+    return dynamic_cast<T*>(ptr); \
+  }; \
+  \
+  template<> \
+  const T* Cast(const AST_Node* ptr) { \
+    return dynamic_cast<const T*>(ptr); \
+  }; \
+
+  IMPLEMENT_BASE_CAST(AST_Node)
+  IMPLEMENT_BASE_CAST(Expression)
+  IMPLEMENT_BASE_CAST(Statement)
+  IMPLEMENT_BASE_CAST(Has_Block)
+  IMPLEMENT_BASE_CAST(PreValue)
+  IMPLEMENT_BASE_CAST(Value)
+  IMPLEMENT_BASE_CAST(List)
+  IMPLEMENT_BASE_CAST(String)
+  IMPLEMENT_BASE_CAST(String_Constant)
+  IMPLEMENT_BASE_CAST(Supports_Condition)
+  IMPLEMENT_BASE_CAST(Selector)
+  IMPLEMENT_BASE_CAST(Simple_Selector)
+
+}
diff --git a/libsass/src/ast_fwd_decl.hpp b/libsass/src/ast_fwd_decl.hpp
--- a/libsass/src/ast_fwd_decl.hpp
+++ b/libsass/src/ast_fwd_decl.hpp
@@ -1,12 +1,17 @@
 #ifndef SASS_AST_FWD_DECL_H
 #define SASS_AST_FWD_DECL_H
 
+#include <map>
+#include <set>
+#include <deque>
 #include <vector>
+#include <typeinfo>
 #include <iostream>
 #include <algorithm>
 #include <unordered_map>
 #include <unordered_set>
 #include "memory/SharedPtr.hpp"
+#include "sass/functions.h"
 
 /////////////////////////////////////////////
 // Forward declarations for the AST visitors.
@@ -128,6 +133,9 @@
   class Map;
   typedef Map* Map_Ptr;
   typedef Map const* Map_Ptr_Const;
+  class Function;
+  typedef Function* Function_Ptr;
+  typedef Function const* Function_Ptr_Const;
 
   class Mixin_Call;
   typedef Mixin_Call* Mixin_Call_Ptr;
@@ -154,9 +162,6 @@
   class Variable;
   typedef Variable* Variable_Ptr;
   typedef Variable const* Variable_Ptr_Const;
-  class Textual;
-  typedef Textual* Textual_Ptr;
-  typedef Textual const* Textual_Ptr_Const;
   class Number;
   typedef Number* Number_Ptr;
   typedef Number const* Number_Ptr_Const;
@@ -310,6 +315,7 @@
   IMPL_MEM_OBJ(Expression);
   IMPL_MEM_OBJ(List);
   IMPL_MEM_OBJ(Map);
+  IMPL_MEM_OBJ(Function);
   IMPL_MEM_OBJ(Binary_Expression);
   IMPL_MEM_OBJ(Unary_Expression);
   IMPL_MEM_OBJ(Function_Call);
@@ -317,7 +323,6 @@
   IMPL_MEM_OBJ(Custom_Warning);
   IMPL_MEM_OBJ(Custom_Error);
   IMPL_MEM_OBJ(Variable);
-  IMPL_MEM_OBJ(Textual);
   IMPL_MEM_OBJ(Number);
   IMPL_MEM_OBJ(Color);
   IMPL_MEM_OBJ(Boolean);
@@ -353,37 +358,105 @@
   IMPL_MEM_OBJ(Complex_Selector);
   IMPL_MEM_OBJ(Selector_List);
 
+  // ###########################################################################
+  // Implement compare, order and hashing operations for AST Nodes
+  // ###########################################################################
 
-  struct HashExpression {
-    size_t operator() (Expression_Obj ex) const;
+  struct HashNodes {
+    template <class T>
+    size_t operator() (const T& ex) const {
+      return ex.isNull() ? 0 : ex->hash();
+    }
   };
-  struct CompareExpression {
-    bool operator()(const Expression_Obj& lhs, const Expression_Obj& rhs) const;
+  struct OrderNodes {
+    template <class T>
+    bool operator() (const T& lhs, const T& rhs) const {
+      return !lhs.isNull() && !rhs.isNull() && *lhs < *rhs;
+    }
   };
-
-  struct HashSimpleSelector {
-    size_t operator() (Simple_Selector_Obj ex) const;
+  struct CompareNodes {
+    template <class T>
+    bool operator() (const T& lhs, const T& rhs) const {
+      // code around sass logic issue. 1px == 1 is true
+      // but both items are still different keys in maps
+      if (dynamic_cast<Number*>(lhs.ptr()))
+        if (dynamic_cast<Number*>(rhs.ptr()))
+          return lhs->hash() == rhs->hash();
+      return !lhs.isNull() && !rhs.isNull() && *lhs == *rhs;
+    }
   };
 
-  struct CompareSimpleSelector {
-    bool operator()(Simple_Selector_Obj lhs, Simple_Selector_Obj rhs) const;
-  };
+  // ###########################################################################
+  // some often used typedefs
+  // ###########################################################################
 
   typedef std::unordered_map<
     Expression_Obj, // key
     Expression_Obj, // value
-    HashExpression, // hasher
-    CompareExpression // compare
+    HashNodes, // hasher
+    CompareNodes // compare
   > ExpressionMap;
   typedef std::unordered_set<
     Expression_Obj, // value
-    HashExpression, // hasher
-    CompareExpression // compare
+    HashNodes, // hasher
+    CompareNodes // compare
   > ExpressionSet;
 
-  typedef std::string Subset_Map_Key;
-  typedef std::vector<size_t> Subset_Map_Arr;
-  typedef std::pair<Complex_Selector_Obj, Compound_Selector_Obj> Subset_Map_Val;
+  typedef std::string SubSetMapKey;
+  typedef std::vector<std::string> SubSetMapKeys;
+
+  typedef std::pair<Complex_Selector_Obj, Compound_Selector_Obj> SubSetMapPair;
+  typedef std::pair<Compound_Selector_Obj, Complex_Selector_Obj> SubSetMapLookup;
+  typedef std::vector<SubSetMapPair> SubSetMapPairs;
+  typedef std::vector<SubSetMapLookup> SubSetMapLookups;
+
+  typedef std::pair<Complex_Selector_Obj, SubSetMapPairs> SubSetMapResult;
+  typedef std::vector<SubSetMapResult> SubSetMapResults;
+
+  typedef std::deque<Complex_Selector_Obj> ComplexSelectorDeque;
+  typedef std::set<Simple_Selector_Obj, OrderNodes> SimpleSelectorSet;
+  typedef std::set<Complex_Selector_Obj, OrderNodes> ComplexSelectorSet;
+  typedef std::set<Compound_Selector_Obj, OrderNodes> CompoundSelectorSet;
+  typedef std::unordered_set<Simple_Selector_Obj, HashNodes, CompareNodes> SimpleSelectorDict;
+
+  typedef std::vector<Sass_Import_Entry>* ImporterStack;
+
+  // only to switch implementations for testing
+  #define environment_map std::map
+
+  // ###########################################################################
+  // explicit type conversion functions
+  // ###########################################################################
+
+  template<class T>
+  T* Cast(AST_Node* ptr);
+
+  template<class T>
+  const T* Cast(const AST_Node* ptr);
+
+  // sometimes you know the class you want to cast to is final
+  // in this case a simple typeid check is faster and safe to use
+
+  #define DECLARE_BASE_CAST(T) \
+  template<> T* Cast(AST_Node* ptr); \
+  template<> const T* Cast(const AST_Node* ptr); \
+
+  // ###########################################################################
+  // implement specialization for final classes
+  // ###########################################################################
+
+  DECLARE_BASE_CAST(AST_Node)
+  DECLARE_BASE_CAST(Expression)
+  DECLARE_BASE_CAST(Statement)
+  DECLARE_BASE_CAST(Has_Block)
+  DECLARE_BASE_CAST(PreValue)
+  DECLARE_BASE_CAST(Value)
+  DECLARE_BASE_CAST(List)
+  DECLARE_BASE_CAST(String)
+  DECLARE_BASE_CAST(String_Constant)
+  DECLARE_BASE_CAST(Supports_Condition)
+  DECLARE_BASE_CAST(Selector)
+  DECLARE_BASE_CAST(Simple_Selector)
 
 }
 
diff --git a/libsass/src/b64/encode.h b/libsass/src/b64/encode.h
--- a/libsass/src/b64/encode.h
+++ b/libsass/src/b64/encode.h
@@ -24,7 +24,9 @@
 
 		encoder(int buffersize_in = BUFFERSIZE)
 		: _buffersize(buffersize_in)
-		{}
+		{
+			base64_init_encodestate(&_state);
+		}
 
 		int encode(char value_in)
 		{
diff --git a/libsass/src/backtrace.cpp b/libsass/src/backtrace.cpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/backtrace.cpp
@@ -0,0 +1,46 @@
+#include "backtrace.hpp"
+
+namespace Sass {
+
+  const std::string traces_to_string(Backtraces traces, std::string indent) {
+
+    std::stringstream ss;
+    std::string cwd(File::get_cwd());
+
+    bool first = true;
+    size_t i_beg = traces.size() - 1;
+    size_t i_end = std::string::npos;
+    for (size_t i = i_beg; i != i_end; i --) {
+
+      const Backtrace& trace = traces[i];
+
+      // make path relative to the current directory
+      std::string rel_path(File::abs2rel(trace.pstate.path, cwd, cwd));
+
+      // skip functions on error cases (unsure why ruby sass does this)
+      // if (trace.caller.substr(0, 6) == ", in f") continue;
+
+      if (first) {
+        ss << indent;
+        ss << "on line ";
+        ss << trace.pstate.line + 1;
+        ss << " of " << rel_path;
+        // ss << trace.caller;
+        first = false;
+      } else {
+        ss << trace.caller;
+        ss << std::endl;
+        ss << indent;
+        ss << "from line ";
+        ss << trace.pstate.line + 1;
+        ss << " of " << rel_path;
+      }
+
+    }
+
+    ss << std::endl;
+    return ss.str();
+
+  }
+
+};
diff --git a/libsass/src/backtrace.hpp b/libsass/src/backtrace.hpp
--- a/libsass/src/backtrace.hpp
+++ b/libsass/src/backtrace.hpp
@@ -1,75 +1,28 @@
 #ifndef SASS_BACKTRACE_H
 #define SASS_BACKTRACE_H
 
+#include <vector>
 #include <sstream>
-
 #include "file.hpp"
 #include "position.hpp"
 
 namespace Sass {
 
-
   struct Backtrace {
 
-    Backtrace*  parent;
     ParserState pstate;
-    std::string      caller;
+    std::string caller;
 
-    Backtrace(Backtrace* prn, ParserState pstate, std::string c)
-    : parent(prn),
-      pstate(pstate),
+    Backtrace(ParserState pstate, std::string c = "")
+    : pstate(pstate),
       caller(c)
     { }
 
-    std::string to_string(bool warning = false)
-    {
-      size_t i = -1;
-      std::stringstream ss;
-      std::string cwd(Sass::File::get_cwd());
-      Backtrace* this_point = this;
-
-      if (!warning) ss << std::endl << "Backtrace:";
-      // the first tracepoint (which is parent-less) is an empty placeholder
-      while (this_point->parent) {
-
-        // make path relative to the current directory
-        std::string rel_path(Sass::File::abs2rel(this_point->pstate.path, cwd, cwd));
-
-        if (warning) {
-          ss << std::endl
-             << "\t"
-             << (++i == 0 ? "on" : "from")
-             << " line "
-             << this_point->pstate.line + 1
-             << " of "
-             << rel_path;
-        } else {
-          ss << std::endl
-             << "\t"
-             << rel_path
-             << ":"
-             << this_point->pstate.line + 1
-             << this_point->parent->caller;
-        }
-
-        this_point = this_point->parent;
-      }
-
-      return ss.str();
-    }
+  };
 
-    size_t depth()
-    {
-      size_t d = 0;
-      Backtrace* p = parent;
-      while (p) {
-        ++d;
-        p = p->parent;
-      }
-      return d-1;
-    }
+  typedef std::vector<Backtrace> Backtraces;
 
-  };
+  const std::string traces_to_string(Backtraces traces, std::string indent = "\t");
 
 }
 
diff --git a/libsass/src/bind.cpp b/libsass/src/bind.cpp
--- a/libsass/src/bind.cpp
+++ b/libsass/src/bind.cpp
@@ -2,6 +2,7 @@
 #include "bind.hpp"
 #include "ast.hpp"
 #include "context.hpp"
+#include "expand.hpp"
 #include "eval.hpp"
 #include <map>
 #include <iostream>
@@ -14,9 +15,11 @@
     std::string callee(type + " " + name);
 
     std::map<std::string, Parameter_Obj> param_map;
+    List_Obj varargs = SASS_MEMORY_NEW(List, as->pstate());
+    varargs->is_arglist(true); // enable keyword size handling
 
     for (size_t i = 0, L = as->length(); i < L; ++i) {
-      if (auto str = SASS_MEMORY_CAST(String_Quoted, (*as)[i]->value())) {
+      if (auto str = Cast<String_Quoted>((*as)[i]->value())) {
         // force optional quotes (only if needed)
         if (str->quote_mark()) {
           str->quote_mark('*');
@@ -42,7 +45,7 @@
       if (ip >= LP) {
         // skip empty rest arguments
         if (a->is_rest_argument()) {
-          if (List_Obj l = SASS_MEMORY_CAST(List, a->value())) {
+          if (List_Obj l = Cast<List>(a->value())) {
             if (l->length() == 0) {
               ++ ia; continue;
             }
@@ -51,7 +54,7 @@
         std::stringstream msg;
         msg << "wrong number of arguments (" << LA << " for " << LP << ")";
         msg << " for `" << name << "'";
-        return error(msg.str(), as->pstate());
+        return error(msg.str(), as->pstate(), eval->exp.traces);
       }
       Parameter_Obj p = ps->at(ip);
 
@@ -61,7 +64,7 @@
         if (a->is_rest_argument()) {
 
           // We should always get a list for rest arguments
-          if (List_Obj rest = SASS_MEMORY_CAST(List, a->value())) {
+          if (List_Obj rest = Cast<List>(a->value())) {
               // create a new list object for wrapped items
               List_Ptr arglist = SASS_MEMORY_NEW(List,
                                               p->pstate(),
@@ -70,12 +73,12 @@
                                               true);
               // wrap each item from list as an argument
               for (Expression_Obj item : rest->elements()) {
-                if (Argument_Obj arg = SASS_MEMORY_CAST(Argument, item)) {
+                if (Argument_Obj arg = Cast<Argument>(item)) {
                   arglist->append(SASS_MEMORY_COPY(arg)); // copy
                 } else {
                   arglist->append(SASS_MEMORY_NEW(Argument,
                                                   item->pstate(),
-                                                  &item,
+                                                  item,
                                                   "",
                                                   false,
                                                   false));
@@ -93,15 +96,20 @@
           // expand keyword arguments into their parameters
           List_Ptr arglist = SASS_MEMORY_NEW(List, p->pstate(), 0, SASS_COMMA, true);
           env->local_frame()[p->name()] = arglist;
-          Map_Obj argmap = SASS_MEMORY_CAST(Map, a->value());
+          Map_Obj argmap = Cast<Map>(a->value());
           for (auto key : argmap->keys()) {
-            std::string name = unquote(SASS_MEMORY_CAST(String_Constant, key)->value());
-            arglist->append(SASS_MEMORY_NEW(Argument,
-                                            key->pstate(),
-                                            argmap->at(key),
-                                            "$" + name,
-                                            false,
-                                            false));
+            if (String_Constant_Obj str = Cast<String_Constant>(key)) {
+              std::string param = unquote(str->value());
+              arglist->append(SASS_MEMORY_NEW(Argument,
+                                              key->pstate(),
+                                              argmap->at(key),
+                                              "$" + param,
+                                              false,
+                                              false));
+            } else {
+              eval->exp.traces.push_back(Backtrace(key->pstate()));
+              throw Exception::InvalidVarKwdType(key->pstate(), eval->exp.traces, key->inspect(), a);
+            }
           }
 
         } else {
@@ -117,25 +125,25 @@
             // get and post inc
             a = (*as)[ia++];
             // maybe we have another list as argument
-            List_Obj ls = SASS_MEMORY_CAST(List, a->value());
+            List_Obj ls = Cast<List>(a->value());
             // skip any list completely if empty
             if (ls && ls->empty() && a->is_rest_argument()) continue;
 
             Expression_Obj value = a->value();
-            if (Argument_Obj arg = SASS_MEMORY_CAST(Argument, value)) {
-              arglist->append(&arg);
+            if (Argument_Obj arg = Cast<Argument>(value)) {
+              arglist->append(arg);
             }
             // check if we have rest argument
             else if (a->is_rest_argument()) {
               // preserve the list separator from rest args
-              if (List_Obj rest = SASS_MEMORY_CAST(List, a->value())) {
+              if (List_Obj rest = Cast<List>(a->value())) {
                 arglist->separator(rest->separator());
 
-                for (size_t i = 0, L = rest->size(); i < L; ++i) {
-                  Expression_Obj obj = rest->at(i);
+                for (size_t i = 0, L = rest->length(); i < L; ++i) {
+                  Expression_Obj obj = rest->value_at_index(i);
                   arglist->append(SASS_MEMORY_NEW(Argument,
                                                 obj->pstate(),
-                                                &obj,
+                                                obj,
                                                 "",
                                                 false,
                                                 false));
@@ -155,7 +163,7 @@
             }
           }
           // assign new arglist to environment
-          env->local_frame()[p->name()] = &arglist;
+          env->local_frame()[p->name()] = arglist;
         }
         // consumed parameter
         ++ip;
@@ -166,9 +174,16 @@
       // If the current argument is the rest argument, extract a value for processing
       else if (a->is_rest_argument()) {
         // normal param and rest arg
-        List_Obj arglist = SASS_MEMORY_CAST(List, a->value());
+        List_Obj arglist = Cast<List>(a->value());
+        if (!arglist) {
+          if (Expression_Obj arg = Cast<Expression>(a->value())) {
+            arglist = SASS_MEMORY_NEW(List, a->pstate(), 1);
+            arglist->append(arg);
+          }
+        }
+
         // empty rest arg - treat all args as default values
-        if (!arglist->length()) {
+        if (!arglist || !arglist->length()) {
           break;
         } else {
           if (arglist->length() > LP - ip && !ps->has_rest_parameter()) {
@@ -187,8 +202,8 @@
         }
         // otherwise move one of the rest args into the param, converting to argument if necessary
         Expression_Obj obj = arglist->at(0);
-        if (!(a = SASS_MEMORY_CAST(Argument, obj))) {
-          Expression_Ptr a_to_convert = &obj;
+        if (!(a = Cast<Argument>(obj))) {
+          Expression_Ptr a_to_convert = obj;
           a = SASS_MEMORY_NEW(Argument,
                               a_to_convert->pstate(),
                               a_to_convert,
@@ -202,17 +217,22 @@
         }
 
       } else if (a->is_keyword_argument()) {
-        Map_Obj argmap = SASS_MEMORY_CAST(Map, a->value());
+        Map_Obj argmap = Cast<Map>(a->value());
 
         for (auto key : argmap->keys()) {
-          std::string name = "$" + unquote(SASS_MEMORY_CAST(String_Constant, key)->value());
+          String_Constant_Ptr val = Cast<String_Constant>(key);
+          if (val == NULL) {
+            eval->exp.traces.push_back(Backtrace(key->pstate()));
+            throw Exception::InvalidVarKwdType(key->pstate(), eval->exp.traces, key->inspect(), a);
+          }
+          std::string param = "$" + unquote(val->value());
 
-          if (!param_map.count(name)) {
+          if (!param_map.count(param)) {
             std::stringstream msg;
-            msg << callee << " has no parameter named " << name;
-            error(msg.str(), a->pstate());
+            msg << callee << " has no parameter named " << param;
+            error(msg.str(), a->pstate(), eval->exp.traces);
           }
-          env->local_frame()[name] = &argmap->at(&key);
+          env->local_frame()[param] = argmap->at(key);
         }
         ++ia;
         continue;
@@ -225,32 +245,38 @@
           std::stringstream msg;
           msg << "parameter " << p->name()
           << " provided more than once in call to " << callee;
-          error(msg.str(), a->pstate());
+          error(msg.str(), a->pstate(), eval->exp.traces);
         }
         // ordinal arg -- bind it to the next param
-        env->local_frame()[p->name()] = &a->value();
+        env->local_frame()[p->name()] = a->value();
         ++ip;
       }
       else {
         // named arg -- bind it to the appropriately named param
         if (!param_map.count(a->name())) {
-          std::stringstream msg;
-          msg << callee << " has no parameter named " << a->name();
-          error(msg.str(), a->pstate());
+          if (ps->has_rest_parameter()) {
+            varargs->append(a);
+          } else {
+            std::stringstream msg;
+            msg << callee << " has no parameter named " << a->name();
+            error(msg.str(), a->pstate(), eval->exp.traces);
+          }
         }
-        if (param_map[a->name()]->is_rest_parameter()) {
-          std::stringstream msg;
-          msg << "argument " << a->name() << " of " << callee
-              << "cannot be used as named argument";
-          error(msg.str(), a->pstate());
+        if (param_map[a->name()]) {
+          if (param_map[a->name()]->is_rest_parameter()) {
+            std::stringstream msg;
+            msg << "argument " << a->name() << " of " << callee
+                << "cannot be used as named argument";
+            error(msg.str(), a->pstate(), eval->exp.traces);
+          }
         }
         if (env->has_local(a->name())) {
           std::stringstream msg;
           msg << "parameter " << p->name()
               << "provided more than once in call to " << callee;
-          error(msg.str(), a->pstate());
+          error(msg.str(), a->pstate(), eval->exp.traces);
         }
-        env->local_frame()[a->name()] = &a->value();
+        env->local_frame()[a->name()] = a->value();
       }
     }
     // EO while ia
@@ -265,11 +291,7 @@
       // cerr << "********" << endl;
       if (!env->has_local(leftover->name())) {
         if (leftover->is_rest_parameter()) {
-          env->local_frame()[leftover->name()] = SASS_MEMORY_NEW(List,
-                                                                   leftover->pstate(),
-                                                                   0,
-                                                                   SASS_COMMA,
-                                                                   true);
+          env->local_frame()[leftover->name()] = varargs;
         }
         else if (leftover->default_value()) {
           Expression_Ptr dv = leftover->default_value()->perform(eval);
@@ -277,7 +299,7 @@
         }
         else {
           // param is unbound and has no default value -- error
-          throw Exception::MissingArgument(as->pstate(), name, leftover->name(), type);
+          throw Exception::MissingArgument(as->pstate(), eval->exp.traces, name, leftover->name(), type);
         }
       }
     }
diff --git a/libsass/src/bind.hpp b/libsass/src/bind.hpp
--- a/libsass/src/bind.hpp
+++ b/libsass/src/bind.hpp
@@ -6,7 +6,6 @@
 #include "ast_fwd_decl.hpp"
 
 namespace Sass {
-  typedef Environment<AST_Node_Obj> Env;
 
   void bind(std::string type, std::string name, Parameters_Obj, Arguments_Obj, Context*, Env*, Eval*);
 }
diff --git a/libsass/src/cencode.c b/libsass/src/cencode.c
--- a/libsass/src/cencode.c
+++ b/libsass/src/cencode.c
@@ -46,6 +46,9 @@
 			result = (fragment & 0x0fc) >> 2;
 			*codechar++ = base64_encode_value(result);
 			result = (fragment & 0x003) << 4;
+			#ifndef _MSC_VER
+				__attribute__ ((fallthrough));
+			#endif
 	case step_B:
 			if (plainchar == plaintextend)
 			{
@@ -57,6 +60,9 @@
 			result |= (fragment & 0x0f0) >> 4;
 			*codechar++ = base64_encode_value(result);
 			result = (fragment & 0x00f) << 2;
+			#ifndef _MSC_VER
+				__attribute__ ((fallthrough));
+			#endif
 	case step_C:
 			if (plainchar == plaintextend)
 			{
diff --git a/libsass/src/check_nesting.cpp b/libsass/src/check_nesting.cpp
--- a/libsass/src/check_nesting.cpp
+++ b/libsass/src/check_nesting.cpp
@@ -7,15 +7,20 @@
 
   CheckNesting::CheckNesting()
   : parents(std::vector<Statement_Ptr>()),
-    parent(0),
-    current_mixin_definition(0)
+    traces(std::vector<Backtrace>()),
+    parent(0), current_mixin_definition(0)
   { }
 
+  void error(AST_Node_Ptr node, Backtraces traces, std::string msg) {
+    traces.push_back(Backtrace(node->pstate()));
+    throw Exception::InvalidSass(node->pstate(), traces, msg);
+  }
+
   Statement_Ptr CheckNesting::visit_children(Statement_Ptr parent)
   {
     Statement_Ptr old_parent = this->parent;
 
-    if (At_Root_Block_Ptr root = SASS_MEMORY_CAST_PTR(At_Root_Block, parent)) {
+    if (At_Root_Block_Ptr root = Cast<At_Root_Block>(parent)) {
       std::vector<Statement_Ptr> old_parents = this->parents;
       std::vector<Statement_Ptr> new_parents;
 
@@ -39,9 +44,15 @@
         }
       }
 
-      At_Root_Block_Ptr ar = SASS_MEMORY_CAST_PTR(At_Root_Block, parent);
-      Statement_Ptr ret = this->visit_children(&ar->block());
+      At_Root_Block_Ptr ar = Cast<At_Root_Block>(parent);
+      Block_Ptr ret = ar->block();
 
+      if (ret != NULL) {
+        for (auto n : ret->elements()) {
+          n->perform(this);
+        }
+      }
+
       this->parent = old_parent;
       this->parents = old_parents;
 
@@ -54,11 +65,17 @@
 
     this->parents.push_back(parent);
 
-    Block_Ptr b = SASS_MEMORY_CAST_PTR(Block, parent);
+    Block_Ptr b = Cast<Block>(parent);
 
+    if (Trace_Ptr trace = Cast<Trace>(parent)) {
+      if (trace->type() == 'i') {
+        this->traces.push_back(Backtrace(trace->pstate()));
+      }
+    }
+
     if (!b) {
-      if (Has_Block_Ptr bb = SASS_MEMORY_CAST(Has_Block, *parent)) {
-        b = &bb->block();
+      if (Has_Block_Ptr bb = Cast<Has_Block>(parent)) {
+        b = bb->block();
       }
     }
 
@@ -67,9 +84,16 @@
         n->perform(this);
       }
     }
+
     this->parent = old_parent;
     this->parents.pop_back();
 
+    if (Trace_Ptr trace = Cast<Trace>(parent)) {
+      if (trace->type() == 'i') {
+        this->traces.pop_back();
+      }
+    }
+
     return b;
   }
 
@@ -97,10 +121,21 @@
     return n;
   }
 
+  Statement_Ptr CheckNesting::operator()(If_Ptr i)
+  {
+    this->visit_children(i);
+
+    if (Block_Ptr b = Cast<Block>(i->alternative())) {
+      for (auto n : b->elements()) n->perform(this);
+    }
+
+    return i;
+  }
+
   Statement_Ptr CheckNesting::fallback_impl(Statement_Ptr s)
   {
-    Block_Ptr b1 = SASS_MEMORY_CAST_PTR(Block, s);
-    Has_Block_Ptr b2 = SASS_MEMORY_CAST_PTR(Has_Block, s);
+    Block_Ptr b1 = Cast<Block>(s);
+    Has_Block_Ptr b2 = Cast<Has_Block>(s);
     return b1 || b2 ? visit_children(s) : s;
   }
 
@@ -108,91 +143,82 @@
   {
     if (!this->parent) return true;
 
-    if (SASS_MEMORY_CAST_PTR(Content, node))
-    { this->invalid_content_parent(this->parent); }
+    if (Cast<Content>(node))
+    { this->invalid_content_parent(this->parent, node); }
 
     if (is_charset(node))
-    { this->invalid_charset_parent(this->parent); }
+    { this->invalid_charset_parent(this->parent, node); }
 
-    if (SASS_MEMORY_CAST_PTR(Extension, node))
-    { this->invalid_extend_parent(this->parent); }
+    if (Cast<Extension>(node))
+    { this->invalid_extend_parent(this->parent, node); }
 
-    // if (SASS_MEMORY_CAST(Import, node))
+    // if (Cast<Import>(node))
     // { this->invalid_import_parent(this->parent); }
 
     if (this->is_mixin(node))
-    { this->invalid_mixin_definition_parent(this->parent); }
+    { this->invalid_mixin_definition_parent(this->parent, node); }
 
     if (this->is_function(node))
-    { this->invalid_function_parent(this->parent); }
+    { this->invalid_function_parent(this->parent, node); }
 
     if (this->is_function(this->parent))
     { this->invalid_function_child(node); }
 
-    if (SASS_MEMORY_CAST_PTR(Declaration, node))
-    { this->invalid_prop_parent(this->parent); }
+    if (Declaration_Ptr d = Cast<Declaration>(node))
+    {
+      this->invalid_prop_parent(this->parent, node);
+      this->invalid_value_child(d->value());
+    }
 
-    if (SASS_MEMORY_CAST_PTR(Declaration, this->parent))
+    if (Cast<Declaration>(this->parent))
     { this->invalid_prop_child(node); }
 
-    if (SASS_MEMORY_CAST_PTR(Return, node))
-    { this->invalid_return_parent(this->parent); }
+    if (Cast<Return>(node))
+    { this->invalid_return_parent(this->parent, node); }
 
     return true;
   }
 
-  void CheckNesting::invalid_content_parent(Statement_Ptr parent)
+  void CheckNesting::invalid_content_parent(Statement_Ptr parent, AST_Node_Ptr node)
   {
     if (!this->current_mixin_definition) {
-      throw Exception::InvalidSass(
-        parent->pstate(),
-        "@content may only be used within a mixin."
-      );
+      error(node, traces, "@content may only be used within a mixin.");
     }
   }
 
-  void CheckNesting::invalid_charset_parent(Statement_Ptr parent)
+  void CheckNesting::invalid_charset_parent(Statement_Ptr parent, AST_Node_Ptr node)
   {
     if (!(
         is_root_node(parent)
     )) {
-      throw Exception::InvalidSass(
-        parent->pstate(),
-        "@charset may only be used at the root of a document."
-      );
+      error(node, traces, "@charset may only be used at the root of a document.");
     }
   }
 
-  void CheckNesting::invalid_extend_parent(Statement_Ptr parent)
+  void CheckNesting::invalid_extend_parent(Statement_Ptr parent, AST_Node_Ptr node)
   {
     if (!(
-        SASS_MEMORY_CAST_PTR(Ruleset, parent) ||
-        SASS_MEMORY_CAST_PTR(Mixin_Call, parent) ||
+        Cast<Ruleset>(parent) ||
+        Cast<Mixin_Call>(parent) ||
         is_mixin(parent)
     )) {
-      throw Exception::InvalidSass(
-        parent->pstate(),
-        "Extend directives may only be used within rules."
-      );
+      error(node, traces, "Extend directives may only be used within rules.");
     }
   }
 
-  // void CheckNesting::invalid_import_parent(Statement_Ptr parent)
+  // void CheckNesting::invalid_import_parent(Statement_Ptr parent, AST_Node_Ptr node)
   // {
   //   for (auto pp : this->parents) {
   //     if (
-  //         SASS_MEMORY_CAST(Each, pp) ||
-  //         SASS_MEMORY_CAST(For, pp) ||
-  //         SASS_MEMORY_CAST(If, pp) ||
-  //         SASS_MEMORY_CAST(While, pp) ||
-  //         SASS_MEMORY_CAST(Trace, pp) ||
-  //         SASS_MEMORY_CAST(Mixin_Call, pp) ||
+  //         Cast<Each>(pp) ||
+  //         Cast<For>(pp) ||
+  //         Cast<If>(pp) ||
+  //         Cast<While>(pp) ||
+  //         Cast<Trace>(pp) ||
+  //         Cast<Mixin_Call>(pp) ||
   //         is_mixin(pp)
   //     ) {
-  //       throw Exception::InvalidSass(
-  //         parent->pstate(),
-  //         "Import directives may not be defined within control directives or other mixins."
-  //       );
+  //       error(node, traces, "Import directives may not be defined within control directives or other mixins.");
   //     }
   //   }
 
@@ -201,49 +227,40 @@
   //   }
 
   //   if (false/*n.css_import?*/) {
-  //     throw Exception::InvalidSass(
-  //       parent->pstate(),
-  //       "CSS import directives may only be used at the root of a document."
-  //     );
+  //     error(node, traces, "CSS import directives may only be used at the root of a document.");
   //   }
   // }
 
-  void CheckNesting::invalid_mixin_definition_parent(Statement_Ptr parent)
+  void CheckNesting::invalid_mixin_definition_parent(Statement_Ptr parent, AST_Node_Ptr node)
   {
     for (Statement_Ptr pp : this->parents) {
       if (
-          SASS_MEMORY_CAST_PTR(Each, pp) ||
-          SASS_MEMORY_CAST_PTR(For, pp) ||
-          SASS_MEMORY_CAST_PTR(If, pp) ||
-          SASS_MEMORY_CAST_PTR(While, pp) ||
-          SASS_MEMORY_CAST_PTR(Trace, pp) ||
-          SASS_MEMORY_CAST_PTR(Mixin_Call, pp) ||
+          Cast<Each>(pp) ||
+          Cast<For>(pp) ||
+          Cast<If>(pp) ||
+          Cast<While>(pp) ||
+          Cast<Trace>(pp) ||
+          Cast<Mixin_Call>(pp) ||
           is_mixin(pp)
       ) {
-        throw Exception::InvalidSass(
-          parent->pstate(),
-          "Mixins may not be defined within control directives or other mixins."
-        );
+        error(node, traces, "Mixins may not be defined within control directives or other mixins.");
       }
     }
   }
 
-  void CheckNesting::invalid_function_parent(Statement_Ptr parent)
+  void CheckNesting::invalid_function_parent(Statement_Ptr parent, AST_Node_Ptr node)
   {
     for (Statement_Ptr pp : this->parents) {
       if (
-          SASS_MEMORY_CAST_PTR(Each, pp) ||
-          SASS_MEMORY_CAST_PTR(For, pp) ||
-          SASS_MEMORY_CAST_PTR(If, pp) ||
-          SASS_MEMORY_CAST_PTR(While, pp) ||
-          SASS_MEMORY_CAST_PTR(Trace, pp) ||
-          SASS_MEMORY_CAST_PTR(Mixin_Call, pp) ||
+          Cast<Each>(pp) ||
+          Cast<For>(pp) ||
+          Cast<If>(pp) ||
+          Cast<While>(pp) ||
+          Cast<Trace>(pp) ||
+          Cast<Mixin_Call>(pp) ||
           is_mixin(pp)
       ) {
-        throw Exception::InvalidSass(
-          parent->pstate(),
-          "Functions may not be defined within control directives or other mixins."
-        );
+        error(node, traces, "Functions may not be defined within control directives or other mixins.");
       }
     }
   }
@@ -251,70 +268,75 @@
   void CheckNesting::invalid_function_child(Statement_Ptr child)
   {
     if (!(
-        SASS_MEMORY_CAST_PTR(Each, child) ||
-        SASS_MEMORY_CAST_PTR(For, child) ||
-        SASS_MEMORY_CAST_PTR(If, child) ||
-        SASS_MEMORY_CAST_PTR(While, child) ||
-        SASS_MEMORY_CAST_PTR(Trace, child) ||
-        SASS_MEMORY_CAST_PTR(Comment, child) ||
-        SASS_MEMORY_CAST_PTR(Debug, child) ||
-        SASS_MEMORY_CAST_PTR(Return, child) ||
-        SASS_MEMORY_CAST_PTR(Variable, child) ||
+        Cast<Each>(child) ||
+        Cast<For>(child) ||
+        Cast<If>(child) ||
+        Cast<While>(child) ||
+        Cast<Trace>(child) ||
+        Cast<Comment>(child) ||
+        Cast<Debug>(child) ||
+        Cast<Return>(child) ||
+        Cast<Variable>(child) ||
         // Ruby Sass doesn't distinguish variables and assignments
-        SASS_MEMORY_CAST_PTR(Assignment, child) ||
-        SASS_MEMORY_CAST_PTR(Warning, child) ||
-        SASS_MEMORY_CAST_PTR(Error, child)
+        Cast<Assignment>(child) ||
+        Cast<Warning>(child) ||
+        Cast<Error>(child)
     )) {
-      throw Exception::InvalidSass(
-        child->pstate(),
-        "Functions can only contain variable declarations and control directives."
-      );
+      error(child, traces, "Functions can only contain variable declarations and control directives.");
     }
   }
 
   void CheckNesting::invalid_prop_child(Statement_Ptr child)
   {
     if (!(
-        SASS_MEMORY_CAST_PTR(Each, child) ||
-        SASS_MEMORY_CAST_PTR(For, child) ||
-        SASS_MEMORY_CAST_PTR(If, child) ||
-        SASS_MEMORY_CAST_PTR(While, child) ||
-        SASS_MEMORY_CAST_PTR(Trace, child) ||
-        SASS_MEMORY_CAST_PTR(Comment, child) ||
-        SASS_MEMORY_CAST_PTR(Declaration, child) ||
-        SASS_MEMORY_CAST_PTR(Mixin_Call, child)
+        Cast<Each>(child) ||
+        Cast<For>(child) ||
+        Cast<If>(child) ||
+        Cast<While>(child) ||
+        Cast<Trace>(child) ||
+        Cast<Comment>(child) ||
+        Cast<Declaration>(child) ||
+        Cast<Mixin_Call>(child)
     )) {
-      throw Exception::InvalidSass(
-        child->pstate(),
-        "Illegal nesting: Only properties may be nested beneath properties."
-      );
+      error(child, traces, "Illegal nesting: Only properties may be nested beneath properties.");
     }
   }
 
-  void CheckNesting::invalid_prop_parent(Statement_Ptr parent)
+  void CheckNesting::invalid_prop_parent(Statement_Ptr parent, AST_Node_Ptr node)
   {
     if (!(
         is_mixin(parent) ||
         is_directive_node(parent) ||
-        SASS_MEMORY_CAST_PTR(Ruleset, parent) ||
-        SASS_MEMORY_CAST_PTR(Keyframe_Rule, parent) ||
-        SASS_MEMORY_CAST_PTR(Declaration, parent) ||
-        SASS_MEMORY_CAST_PTR(Mixin_Call, parent)
+        Cast<Ruleset>(parent) ||
+        Cast<Keyframe_Rule>(parent) ||
+        Cast<Declaration>(parent) ||
+        Cast<Mixin_Call>(parent)
     )) {
-      throw Exception::InvalidSass(
-        parent->pstate(),
-        "Properties are only allowed within rules, directives, mixin includes, or other properties."
-      );
+      error(node, traces, "Properties are only allowed within rules, directives, mixin includes, or other properties.");
     }
   }
 
-  void CheckNesting::invalid_return_parent(Statement_Ptr parent)
+  void CheckNesting::invalid_value_child(AST_Node_Ptr d)
   {
+    if (Map_Ptr m = Cast<Map>(d)) {
+      traces.push_back(Backtrace(m->pstate()));
+      throw Exception::InvalidValue(traces, *m);
+    }
+    if (Number_Ptr n = Cast<Number>(d)) {
+      if (!n->is_valid_css_unit()) {
+        traces.push_back(Backtrace(n->pstate()));
+        throw Exception::InvalidValue(traces, *n);
+      }
+    }
+
+    // error(dbg + " isn't a valid CSS value.", m->pstate(),);
+
+  }
+
+  void CheckNesting::invalid_return_parent(Statement_Ptr parent, AST_Node_Ptr node)
+  {
     if (!this->is_function(parent)) {
-      throw Exception::InvalidSass(
-        parent->pstate(),
-        "@return may only be used within a function."
-      );
+      error(node, traces, "@return may only be used within a function.");
     }
   }
 
@@ -326,51 +348,51 @@
                              !is_root_node(grandparent) &&
                              !is_at_root_node(grandparent);
 
-    return SASS_MEMORY_CAST_PTR(Import, parent) ||
-           SASS_MEMORY_CAST_PTR(Each, parent) ||
-           SASS_MEMORY_CAST_PTR(For, parent) ||
-           SASS_MEMORY_CAST_PTR(If, parent) ||
-           SASS_MEMORY_CAST_PTR(While, parent) ||
-           SASS_MEMORY_CAST_PTR(Trace, parent) ||
+    return Cast<Import>(parent) ||
+           Cast<Each>(parent) ||
+           Cast<For>(parent) ||
+           Cast<If>(parent) ||
+           Cast<While>(parent) ||
+           Cast<Trace>(parent) ||
            valid_bubble_node;
   }
 
   bool CheckNesting::is_charset(Statement_Ptr n)
   {
-    Directive_Ptr d = SASS_MEMORY_CAST_PTR(Directive, n);
+    Directive_Ptr d = Cast<Directive>(n);
     return d && d->keyword() == "charset";
   }
 
   bool CheckNesting::is_mixin(Statement_Ptr n)
   {
-    Definition_Ptr def = SASS_MEMORY_CAST_PTR(Definition, n);
+    Definition_Ptr def = Cast<Definition>(n);
     return def && def->type() == Definition::MIXIN;
   }
 
   bool CheckNesting::is_function(Statement_Ptr n)
   {
-    Definition_Ptr def = SASS_MEMORY_CAST_PTR(Definition, n);
+    Definition_Ptr def = Cast<Definition>(n);
     return def && def->type() == Definition::FUNCTION;
   }
 
   bool CheckNesting::is_root_node(Statement_Ptr n)
   {
-    if (SASS_MEMORY_CAST_PTR(Ruleset, n)) return false;
+    if (Cast<Ruleset>(n)) return false;
 
-    Block_Ptr b = SASS_MEMORY_CAST_PTR(Block, n);
+    Block_Ptr b = Cast<Block>(n);
     return b && b->is_root();
   }
 
   bool CheckNesting::is_at_root_node(Statement_Ptr n)
   {
-    return SASS_MEMORY_CAST_PTR(At_Root_Block, n) != NULL;
+    return Cast<At_Root_Block>(n) != NULL;
   }
 
   bool CheckNesting::is_directive_node(Statement_Ptr n)
   {
-    return SASS_MEMORY_CAST_PTR(Directive, n) ||
-           SASS_MEMORY_CAST_PTR(Import, n) ||
-           SASS_MEMORY_CAST_PTR(Media_Block, n) ||
-           SASS_MEMORY_CAST_PTR(Supports_Block, n);
+    return Cast<Directive>(n) ||
+           Cast<Import>(n) ||
+           Cast<Media_Block>(n) ||
+           Cast<Supports_Block>(n);
   }
 }
diff --git a/libsass/src/check_nesting.hpp b/libsass/src/check_nesting.hpp
--- a/libsass/src/check_nesting.hpp
+++ b/libsass/src/check_nesting.hpp
@@ -6,11 +6,10 @@
 
 namespace Sass {
 
-  typedef Environment<AST_Node_Obj> Env;
-
   class CheckNesting : public Operation_CRTP<Statement_Ptr, CheckNesting> {
 
     std::vector<Statement_Ptr>  parents;
+    Backtraces                  traces;
     Statement_Ptr               parent;
     Definition_Ptr              current_mixin_definition;
 
@@ -24,10 +23,11 @@
 
     Statement_Ptr operator()(Block_Ptr);
     Statement_Ptr operator()(Definition_Ptr);
+    Statement_Ptr operator()(If_Ptr);
 
     template <typename U>
     Statement_Ptr fallback(U x) {
-      Statement_Ptr n = SASS_MEMORY_CAST_PTR(Statement, x);
+      Statement_Ptr n = Cast<Statement>(x);
       if (this->should_visit(n)) {
         return fallback_impl(n);
       }
@@ -35,17 +35,18 @@
     }
 
   private:
-    void invalid_content_parent(Statement_Ptr);
-    void invalid_charset_parent(Statement_Ptr);
-    void invalid_extend_parent(Statement_Ptr);
+    void invalid_content_parent(Statement_Ptr, AST_Node_Ptr);
+    void invalid_charset_parent(Statement_Ptr, AST_Node_Ptr);
+    void invalid_extend_parent(Statement_Ptr, AST_Node_Ptr);
     // void invalid_import_parent(Statement_Ptr);
-    void invalid_mixin_definition_parent(Statement_Ptr);
-    void invalid_function_parent(Statement_Ptr);
+    void invalid_mixin_definition_parent(Statement_Ptr, AST_Node_Ptr);
+    void invalid_function_parent(Statement_Ptr, AST_Node_Ptr);
 
     void invalid_function_child(Statement_Ptr);
     void invalid_prop_child(Statement_Ptr);
-    void invalid_prop_parent(Statement_Ptr);
-    void invalid_return_parent(Statement_Ptr);
+    void invalid_prop_parent(Statement_Ptr, AST_Node_Ptr);
+    void invalid_return_parent(Statement_Ptr, AST_Node_Ptr);
+    void invalid_value_child(AST_Node_Ptr);
 
     bool is_transparent_parent(Statement_Ptr, Statement_Ptr);
 
diff --git a/libsass/src/color_maps.cpp b/libsass/src/color_maps.cpp
--- a/libsass/src/color_maps.cpp
+++ b/libsass/src/color_maps.cpp
@@ -607,16 +607,20 @@
 
   Color_Ptr_Const name_to_color(const char* key)
   {
-    auto p = names_to_colors.find(key);
-    if (p != names_to_colors.end()) {
-      return p->second;
-    }
-    return 0;
+    return name_to_color(std::string(key));
   }
 
   Color_Ptr_Const name_to_color(const std::string& key)
   {
-    return name_to_color(key.c_str());
+    // case insensitive lookup.  See #2462
+    std::string lower{key};
+    std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower);
+
+    auto p = names_to_colors.find(lower.c_str());
+    if (p != names_to_colors.end()) {
+      return p->second;
+    }
+    return 0;
   }
 
   const char* color_to_name(const int key)
diff --git a/libsass/src/color_maps.hpp b/libsass/src/color_maps.hpp
--- a/libsass/src/color_maps.hpp
+++ b/libsass/src/color_maps.hpp
@@ -1,3 +1,4 @@
+
 #ifndef SASS_COLOR_MAPS_H
 #define SASS_COLOR_MAPS_H
 
@@ -319,14 +320,11 @@
     extern const Color transparent;
   }
 
-  extern const std::map<const int, const char*> colors_to_names;
-  extern const std::map<const char*, Color_Ptr_Const, map_cmp_str> names_to_colors;
-
-  extern Color_Ptr_Const name_to_color(const char*);
-  extern Color_Ptr_Const name_to_color(const std::string&);
-  extern const char* color_to_name(const int);
-  extern const char* color_to_name(const Color&);
-  extern const char* color_to_name(const double);
+  Color_Ptr_Const name_to_color(const char*);
+  Color_Ptr_Const name_to_color(const std::string&);
+  const char* color_to_name(const int);
+  const char* color_to_name(const Color&);
+  const char* color_to_name(const double);
 
 }
 
diff --git a/libsass/src/constants.cpp b/libsass/src/constants.cpp
--- a/libsass/src/constants.cpp
+++ b/libsass/src/constants.cpp
@@ -79,11 +79,12 @@
     extern const char supports_kwd[]     = "@supports";
     extern const char keyframes_kwd[]    = "keyframes";
     extern const char only_kwd[]         = "only";
-    extern const char rgb_kwd[]          = "rgb(";
+    extern const char rgb_fn_kwd[]       = "rgb(";
+    extern const char url_fn_kwd[]       = "url(";
     extern const char url_kwd[]          = "url";
-    // extern const char url_prefix_kwd[]   = "url-prefix(";
+    // extern const char url_prefix_fn_kwd[] = "url-prefix(";
     extern const char important_kwd[]    = "important";
-    extern const char pseudo_not_kwd[]   = ":not(";
+    extern const char pseudo_not_fn_kwd[] = ":not(";
     extern const char even_kwd[]         = "even";
     extern const char odd_kwd[]          = "odd";
     extern const char progid_kwd[]       = "progid";
diff --git a/libsass/src/constants.hpp b/libsass/src/constants.hpp
--- a/libsass/src/constants.hpp
+++ b/libsass/src/constants.hpp
@@ -79,11 +79,12 @@
     extern const char supports_kwd[];
     extern const char keyframes_kwd[];
     extern const char only_kwd[];
-    extern const char rgb_kwd[];
+    extern const char rgb_fn_kwd[];
+    extern const char url_fn_kwd[];
     extern const char url_kwd[];
-    // extern const char url_prefix_kwd[];
+    // extern const char url_prefix_fn_kwd[];
     extern const char important_kwd[];
-    extern const char pseudo_not_kwd[];
+    extern const char pseudo_not_fn_kwd[];
     extern const char even_kwd[];
     extern const char odd_kwd[];
     extern const char progid_kwd[];
diff --git a/libsass/src/context.cpp b/libsass/src/context.cpp
--- a/libsass/src/context.cpp
+++ b/libsass/src/context.cpp
@@ -67,11 +67,15 @@
     plugins(),
     emitter(c_options),
 
+    ast_gc(),
     strings(),
     resources(),
     sheets(),
     subset_map(),
     import_stack(),
+    callee_stack(),
+    traces(),
+    c_compiler(NULL),
 
     c_headers               (std::vector<Sass_Importer_Entry>()),
     c_importers             (std::vector<Sass_Importer_Entry>()),
@@ -87,8 +91,9 @@
 
   {
 
-    // add cwd to include paths
-    include_paths.push_back(CWD);
+    // Sass 3.4: The current working directory will no longer be placed onto the Sass load path by default.
+    // If you need the current working directory to be available, set SASS_PATH=. in your shell's environment.
+    // include_paths.push_back(CWD);
 
     // collect more paths from different options
     collect_include_paths(c_options.include_path);
@@ -129,7 +134,7 @@
 
   Context::~Context()
   {
-    // resources were allocated by strdup or malloc
+    // resources were allocated by malloc
     for (size_t i = 0; i < resources.size(); ++i) {
       free(resources[i].contents);
       free(resources[i].srcmap);
@@ -246,10 +251,9 @@
     return vec;
   }
 
-
   // register include with resolved path and its content
   // memory of the resources will be freed by us on exit
-  void Context::register_resource(const Include& inc, const Resource& res, ParserState* prstate)
+  void Context::register_resource(const Include& inc, const Resource& res)
   {
 
     // do not parse same resource twice
@@ -297,21 +301,22 @@
     for (size_t i = 0; i < import_stack.size() - 2; ++i) {
       auto parent = import_stack[i];
       if (std::strcmp(parent->abs_path, import->abs_path) == 0) {
+        std::string cwd(File::get_cwd());
+        // make path relative to the current directory
         std::string stack("An @import loop has been found:");
         for (size_t n = 1; n < i + 2; ++n) {
-          stack += "\n    " + std::string(import_stack[n]->imp_path) +
-            " imports " + std::string(import_stack[n+1]->imp_path);
+          stack += "\n    " + std::string(File::abs2rel(import_stack[n]->abs_path, cwd, cwd)) +
+            " imports " + std::string(File::abs2rel(import_stack[n+1]->abs_path, cwd, cwd));
         }
         // implement error throw directly until we
         // decided how to handle full stack traces
-        ParserState state = prstate ? *prstate : pstate;
-        throw Exception::InvalidSyntax(state, stack, &import_stack);
+        throw Exception::InvalidSyntax(pstate, traces, stack);
         // error(stack, prstate ? *prstate : pstate, import_stack);
       }
     }
 
     // create a parser instance from the given c_str buffer
-    Parser p(Parser::from_c_str(contents, *this, pstate));
+    Parser p(Parser::from_c_str(contents, *this, traces, pstate));
     // do not yet dispose these buffers
     sass_import_take_source(import);
     sass_import_take_srcmap(import);
@@ -326,7 +331,15 @@
       ast_pair(inc.abs_path, { res, root });
     // register resulting resource
     sheets.insert(ast_pair);
+  }
 
+  // register include with resolved path and its content
+  // memory of the resources will be freed by us on exit
+  void Context::register_resource(const Include& inc, const Resource& res, ParserState& prstate)
+  {
+    traces.push_back(Backtrace(prstate));
+    register_resource(inc, res);
+    traces.pop_back();
   }
 
   // Add a new import to the context (called from `import_url`)
@@ -346,7 +359,7 @@
       for (size_t i = 0, L = resolved.size(); i < L; ++i)
       { msg_stream << "  " << resolved[i].imp_path << "\n"; }
       msg_stream << "Please delete or rename all but one of these files." << "\n";
-      error(msg_stream.str(), pstate);
+      error(msg_stream.str(), pstate, traces);
     }
 
     // process the resolved entry
@@ -358,7 +371,7 @@
       // the memory buffer returned must be freed by us!
       if (char* contents = read_file(resolved[0].abs_path)) {
         // register the newly resolved file resource
-        register_resource(resolved[0], { contents, 0 }, &pstate);
+        register_resource(resolved[0], { contents, 0 }, pstate);
         // return resolved entry
         return resolved[0];
       }
@@ -391,15 +404,15 @@
       String_Constant_Ptr loc = SASS_MEMORY_NEW(String_Constant, pstate, unquote(load_path));
       Argument_Obj loc_arg = SASS_MEMORY_NEW(Argument, pstate, loc);
       Arguments_Obj loc_args = SASS_MEMORY_NEW(Arguments, pstate);
-      loc_args->append(&loc_arg);
-      Function_Call_Ptr new_url = SASS_MEMORY_NEW(Function_Call, pstate, "url", &loc_args);
+      loc_args->append(loc_arg);
+      Function_Call_Ptr new_url = SASS_MEMORY_NEW(Function_Call, pstate, "url", loc_args);
       imp->urls().push_back(new_url);
     }
     else {
       const Importer importer(imp_path, ctx_path);
       Include include(load_import(importer, pstate));
       if (include.abs_path.empty()) {
-        error("File to import not found or unreadable: " + imp_path + ".\nParent style sheet: " + ctx_path, pstate);
+        error("File to import not found or unreadable: " + imp_path + ".", pstate, traces);
       }
       imp->incs().push_back(include);
     }
@@ -415,12 +428,12 @@
     // need one correct import
     bool has_import = false;
     // process all custom importers (or custom headers)
-    for (Sass_Importer_Entry& importer : importers) {
+    for (Sass_Importer_Entry& importer_ent : importers) {
       // int priority = sass_importer_get_priority(importer);
-      Sass_Importer_Fn fn = sass_importer_get_function(importer);
+      Sass_Importer_Fn fn = sass_importer_get_function(importer_ent);
       // skip importer if it returns NULL
       if (Sass_Import_List includes =
-          fn(load_path.c_str(), importer, c_compiler)
+          fn(load_path.c_str(), importer_ent, c_compiler)
       ) {
         // get c pointer copy to iterate over
         Sass_Import_List it_includes = includes;
@@ -435,18 +448,18 @@
           // create the importer struct
           Importer importer(uniq_path, ctx_path);
           // query data from the current include
-          Sass_Import_Entry include = *it_includes;
-          char* source = sass_import_take_source(include);
-          char* srcmap = sass_import_take_srcmap(include);
-          size_t line = sass_import_get_error_line(include);
-          size_t column = sass_import_get_error_column(include);
-          const char *abs_path = sass_import_get_abs_path(include);
+          Sass_Import_Entry include_ent = *it_includes;
+          char* source = sass_import_take_source(include_ent);
+          char* srcmap = sass_import_take_srcmap(include_ent);
+          size_t line = sass_import_get_error_line(include_ent);
+          size_t column = sass_import_get_error_column(include_ent);
+          const char *abs_path = sass_import_get_abs_path(include_ent);
           // handle error message passed back from custom importer
           // it may (or may not) override the line and column info
-          if (const char* err_message = sass_import_get_error_message(include)) {
-            if (source || srcmap) register_resource({ importer, uniq_path }, { source, srcmap }, &pstate);
-            if (line == std::string::npos && column == std::string::npos) error(err_message, pstate);
-            else error(err_message, ParserState(ctx_path, source, Position(line, column)));
+          if (const char* err_message = sass_import_get_error_message(include_ent)) {
+            if (source || srcmap) register_resource({ importer, uniq_path }, { source, srcmap }, pstate);
+            if (line == std::string::npos && column == std::string::npos) error(err_message, pstate, traces);
+            else error(err_message, ParserState(ctx_path, source, Position(line, column)), traces);
           }
           // content for import was set
           else if (source) {
@@ -458,7 +471,7 @@
             // attach information to AST node
             imp->incs().push_back(include);
             // register the resource buffers
-            register_resource(include, { source, srcmap }, &pstate);
+            register_resource(include, { source, srcmap }, pstate);
           }
           // only a path was retuned
           // try to load it like normal
@@ -528,11 +541,11 @@
     Import_Obj imp = SASS_MEMORY_NEW(Import, pstate);
     // dispatch headers which will add custom functions
     // custom headers are added to the import instance
-    call_headers(entry_path, ctx_path, pstate, &imp);
+    call_headers(entry_path, ctx_path, pstate, imp);
     // increase head count to skip later
     head_imports += resources.size() - 1;
     // add the statement if we have urls
-    if (!imp->urls().empty()) root->append(&imp);
+    if (!imp->urls().empty()) root->append(imp);
     // process all other resources (add Import_Stub nodes)
     for (size_t i = 0, S = imp->incs().size(); i < S; ++i) {
       root->append(SASS_MEMORY_NEW(Import_Stub, pstate, imp->incs()[i]));
@@ -644,30 +657,33 @@
     for (size_t i = 0, S = c_functions.size(); i < S; ++i)
     { register_c_function(*this, &global, c_functions[i]); }
     // create initial backtrace entry
-    Backtrace backtrace(0, ParserState("", 0), "");
     // create crtp visitor objects
-    Expand expand(*this, &global, &backtrace);
-    Cssize cssize(*this, &backtrace);
+    Expand expand(*this, &global);
+    Cssize cssize(*this);
     CheckNesting check_nesting;
-    // check nesting
-    check_nesting(&root);
+    // check nesting in all files
+    for (auto sheet : sheets) {
+      auto styles = sheet.second;
+      check_nesting(styles.root);
+    }
     // expand and eval the tree
-    root = expand(&root);
+    root = expand(root);
     // check nesting
-    check_nesting(&root);
+    check_nesting(root);
     // merge and bubble certain rules
-    root = cssize(&root);
+    root = cssize(root);
     // should we extend something?
     if (!subset_map.empty()) {
       // create crtp visitor object
-      Extend extend(*this, subset_map);
+      Extend extend(subset_map);
+      extend.setEval(expand.eval);
       // extend tree nodes
-      extend(&root);
+      extend(root);
     }
 
     // clean up by removing empty placeholders
     // ToDo: maybe we can do this somewhere else?
-    Remove_Placeholders remove_placeholders(*this);
+    Remove_Placeholders remove_placeholders;
     root->perform(&remove_placeholders);
     // return processed tree
     return root;
@@ -695,10 +711,8 @@
   char* Context::render_srcmap()
   {
     if (source_map_file == "") return 0;
-    char* result = 0;
     std::string map = emitter.render_srcmap(*this);
-    result = sass_copy_c_string(map.c_str());
-    return result;
+    return sass_copy_c_string(map.c_str());
   }
 
 
@@ -810,6 +824,7 @@
     register_function(ctx, append_sig, append, env);
     register_function(ctx, zip_sig, zip, env);
     register_function(ctx, list_separator_sig, list_separator, env);
+    register_function(ctx, is_bracketed_sig, is_bracketed, env);
     // Map Functions
     register_function(ctx, map_get_sig, map_get, env);
     register_function(ctx, map_merge_sig, map_merge, env);
@@ -829,6 +844,8 @@
     register_function(ctx, mixin_exists_sig, mixin_exists, env);
     register_function(ctx, feature_exists_sig, feature_exists, env);
     register_function(ctx, call_sig, call, env);
+    register_function(ctx, content_exists_sig, content_exists, env);
+    register_function(ctx, get_function_sig, get_function, env);
     // Boolean Functions
     register_function(ctx, not_sig, sass_not, env);
     register_function(ctx, if_sig, sass_if, env);
diff --git a/libsass/src/context.hpp b/libsass/src/context.hpp
--- a/libsass/src/context.hpp
+++ b/libsass/src/context.hpp
@@ -15,6 +15,7 @@
 #include "environment.hpp"
 #include "source_map.hpp"
 #include "subset_map.hpp"
+#include "backtrace.hpp"
 #include "output.hpp"
 #include "plugins.hpp"
 #include "file.hpp"
@@ -43,6 +44,9 @@
     Plugins plugins;
     Output emitter;
 
+    // generic ast node garbage container
+    // used to avoid possible circular refs
+    std::vector<AST_Node_Obj> ast_gc;
     // resources add under our control
     // these are guaranteed to be freed
     std::vector<char*> strings;
@@ -50,6 +54,8 @@
     std::map<const std::string, StyleSheet> sheets;
     Subset_Map subset_map;
     std::vector<Sass_Import_Entry> import_stack;
+    std::vector<Sass_Callee> callee_stack;
+    std::vector<Backtrace> traces;
 
     struct Sass_Compiler* c_compiler;
 
@@ -90,7 +96,8 @@
     virtual char* render(Block_Obj root);
     virtual char* render_srcmap();
 
-    void register_resource(const Include&, const Resource&, ParserState* = 0);
+    void register_resource(const Include&, const Resource&);
+    void register_resource(const Include&, const Resource&, ParserState&);
     std::vector<Include> find_includes(const Importer& import);
     Include load_import(const Importer&, ParserState pstate);
 
diff --git a/libsass/src/cssize.cpp b/libsass/src/cssize.cpp
--- a/libsass/src/cssize.cpp
+++ b/libsass/src/cssize.cpp
@@ -5,15 +5,14 @@
 
 #include "cssize.hpp"
 #include "context.hpp"
-#include "backtrace.hpp"
 
 namespace Sass {
 
-  Cssize::Cssize(Context& ctx, Backtrace* bt)
+  Cssize::Cssize(Context& ctx)
   : ctx(ctx),
+    traces(ctx.traces),
     block_stack(std::vector<Block_Ptr>()),
-    p_stack(std::vector<Statement_Ptr>()),
-    backtrace(bt)
+    p_stack(std::vector<Statement_Ptr>())
   { }
 
   Statement_Ptr Cssize::parent()
@@ -23,25 +22,28 @@
 
   Block_Ptr Cssize::operator()(Block_Ptr b)
   {
-    Block_Ptr bb = SASS_MEMORY_NEW(Block, b->pstate(), b->length(), b->is_root());
+    Block_Obj bb = SASS_MEMORY_NEW(Block, b->pstate(), b->length(), b->is_root());
     // bb->tabs(b->tabs());
     block_stack.push_back(bb);
     append_block(b, bb);
     block_stack.pop_back();
-    return bb;
+    return bb.detach();
   }
 
   Statement_Ptr Cssize::operator()(Trace_Ptr t)
   {
-    return t->block()->perform(this);
+    traces.push_back(Backtrace(t->pstate()));
+    auto result = t->block()->perform(this);
+    traces.pop_back();
+    return result;
   }
 
   Statement_Ptr Cssize::operator()(Declaration_Ptr d)
   {
-    String_Obj property = SASS_MEMORY_CAST(String, d->property());
+    String_Obj property = Cast<String>(d->property());
 
-    if (Declaration_Ptr dd = dynamic_cast<Declaration_Ptr>(parent())) {
-      String_Obj parent_property = SASS_MEMORY_CAST(String, dd->property());
+    if (Declaration_Ptr dd = Cast<Declaration>(parent())) {
+      String_Obj parent_property = Cast<String>(dd->property());
       property = SASS_MEMORY_NEW(String_Constant,
                                  d->property()->pstate(),
                                  parent_property->to_string() + "-" + property->to_string());
@@ -54,17 +56,18 @@
                                       d->pstate(),
                                       property,
                                       d->value(),
-                                      d->is_important());
+                                      d->is_important(),
+                                      d->is_custom_property());
     dd->is_indented(d->is_indented());
     dd->tabs(d->tabs());
 
-    p_stack.push_back(&dd);
-    Block_Obj bb = d->block() ? operator()(&d->block()) : NULL;
+    p_stack.push_back(dd);
+    Block_Obj bb = d->block() ? operator()(d->block()) : NULL;
     p_stack.pop_back();
 
     if (bb && bb->length()) {
       if (dd->value() && !dd->value()->is_invisible()) {
-        bb->unshift(&dd);
+        bb->unshift(dd);
       }
       return bb.detach();
     }
@@ -89,7 +92,7 @@
                                   r->pstate(),
                                   r->keyword(),
                                   r->selector(),
-                                  r->block() ? operator()(&r->block()) : 0);
+                                  r->block() ? operator()(r->block()) : 0);
     if (r->value()) rr->value(r->value());
     p_stack.pop_back();
 
@@ -99,10 +102,10 @@
       Statement_Obj s = r->block()->at(i);
       if (s->statement_type() != Statement::BUBBLE) directive_exists = true;
       else {
-        Bubble_Obj s_obj = SASS_MEMORY_CAST(Bubble, s);
+        Bubble_Obj s_obj = Cast<Bubble>(s);
         s = s_obj->node();
         if (s->statement_type() != Statement::DIRECTIVE) directive_exists = false;
-        else directive_exists = (static_cast<Directive_Ptr>(&s)->keyword() == rr->keyword());
+        else directive_exists = (Cast<Directive>(s)->keyword() == rr->keyword());
       }
 
     }
@@ -110,12 +113,14 @@
     Block_Ptr result = SASS_MEMORY_NEW(Block, rr->pstate());
     if (!(directive_exists || rr->is_keyframes()))
     {
-      Directive_Ptr empty_node = SASS_MEMORY_CAST(Directive, rr);
+      Directive_Ptr empty_node = Cast<Directive>(rr);
       empty_node->block(SASS_MEMORY_NEW(Block, rr->block() ? rr->block()->pstate() : rr->pstate()));
       result->append(empty_node);
     }
 
-    Block_Obj ss = debubble(rr->block() ? &rr->block() : SASS_MEMORY_NEW(Block, rr->pstate()), &rr);
+    Block_Obj db = rr->block();
+    if (db.isNull()) db = SASS_MEMORY_NEW(Block, rr->pstate());
+    Block_Obj ss = debubble(db, rr);
     for (size_t i = 0, L = ss->length(); i < L; ++i) {
       result->append(ss->at(i));
     }
@@ -129,10 +134,10 @@
 
     Keyframe_Rule_Obj rr = SASS_MEMORY_NEW(Keyframe_Rule,
                                         r->pstate(),
-                                        operator()(&r->block()));
-    if (&r->name()) rr->name(r->name());
+                                        operator()(r->block()));
+    if (!r->name().isNull()) rr->name(r->name());
 
-    return debubble(&rr->block(), &rr);
+    return debubble(rr->block(), rr);
   }
 
   Statement_Ptr Cssize::operator()(Ruleset_Ptr r)
@@ -142,11 +147,11 @@
     // string schema is not a statement!
     // r->block() is already a string schema
     // and that is comming from propset expand
-    Block_Ptr bb = operator()(&r->block());
+    Block_Ptr bb = operator()(r->block());
     // this should protect us (at least a bit) from our mess
     // fixing this properly is harder that it should be ...
-    if (dynamic_cast<Statement_Ptr>(bb) == NULL) {
-      error("Illegal nesting: Only properties may be nested beneath properties.", r->block()->pstate());
+    if (Cast<Statement>(bb) == NULL) {
+      error("Illegal nesting: Only properties may be nested beneath properties.", r->block()->pstate(), traces);
     }
     Ruleset_Obj rr = SASS_MEMORY_NEW(Ruleset,
                                   r->pstate(),
@@ -158,31 +163,31 @@
     p_stack.pop_back();
 
     if (!rr->block()) {
-      error("Illegal nesting: Only properties may be nested beneath properties.", r->block()->pstate());
+      error("Illegal nesting: Only properties may be nested beneath properties.", r->block()->pstate(), traces);
     }
 
     Block_Obj props = SASS_MEMORY_NEW(Block, rr->block()->pstate());
     Block_Ptr rules = SASS_MEMORY_NEW(Block, rr->block()->pstate());
     for (size_t i = 0, L = rr->block()->length(); i < L; i++)
     {
-      Statement_Ptr s = &rr->block()->at(i);
+      Statement_Ptr s = rr->block()->at(i);
       if (bubblable(s)) rules->append(s);
       if (!bubblable(s)) props->append(s);
     }
 
     if (props->length())
     {
-      Block_Obj bb = SASS_MEMORY_NEW(Block, rr->block()->pstate());
-      bb->concat(&props);
-      rr->block(bb);
+      Block_Obj pb = SASS_MEMORY_NEW(Block, rr->block()->pstate());
+      pb->concat(props);
+      rr->block(pb);
 
       for (size_t i = 0, L = rules->length(); i < L; i++)
       {
-        Statement_Ptr stm = &rules->at(i);
+        Statement_Ptr stm = rules->at(i);
         stm->tabs(stm->tabs() + 1);
       }
 
-      rules->unshift(&rr);
+      rules->unshift(rr);
     }
 
     Block_Ptr ptr = rules;
@@ -194,7 +199,7 @@
     }
 
     if (!(!rules->length() ||
-          !bubblable(&rules->last()) ||
+          !bubblable(rules->last()) ||
           parent()->statement_type() == Statement::RULESET))
     {
       rules->last()->group_end(true);
@@ -219,13 +224,13 @@
 
     Media_Block_Obj mm = SASS_MEMORY_NEW(Media_Block,
                                       m->pstate(),
-                                      &m->media_queries(),
-                                      operator()(&m->block()));
+                                      m->media_queries(),
+                                      operator()(m->block()));
     mm->tabs(m->tabs());
 
     p_stack.pop_back();
 
-    return debubble(&mm->block(), &mm);
+    return debubble(mm->block(), mm);
   }
 
   Statement_Ptr Cssize::operator()(Supports_Block_Ptr m)
@@ -240,13 +245,13 @@
 
     Supports_Block_Obj mm = SASS_MEMORY_NEW(Supports_Block,
                                        m->pstate(),
-                                       &m->condition(),
-                                       operator()(&m->block()));
+                                       m->condition(),
+                                       operator()(m->block()));
     mm->tabs(m->tabs());
 
     p_stack.pop_back();
 
-    return debubble(&mm->block(), &mm);
+    return debubble(mm->block(), mm);
   }
 
   Statement_Ptr Cssize::operator()(At_Root_Block_Ptr m)
@@ -257,15 +262,15 @@
       tmp |= m->exclude_node(s);
     }
 
-    if (!tmp)
+    if (!tmp && m->block())
     {
-      Block_Ptr bb = operator()(&m->block());
+      Block_Ptr bb = operator()(m->block());
       for (size_t i = 0, L = bb->length(); i < L; ++i) {
         // (bb->elements())[i]->tabs(m->tabs());
         Statement_Obj stm = bb->at(i);
-        if (bubblable(&stm)) stm->tabs(stm->tabs() + m->tabs());
+        if (bubblable(stm)) stm->tabs(stm->tabs() + m->tabs());
       }
-      if (bb->length() && bubblable(&bb->last())) bb->last()->group_end(m->group_end());
+      if (bb->length() && bubblable(bb->last())) bb->last()->group_end(m->group_end());
       return bb;
     }
 
@@ -280,13 +285,13 @@
   Statement_Ptr Cssize::bubble(Directive_Ptr m)
   {
     Block_Ptr bb = SASS_MEMORY_NEW(Block, this->parent()->pstate());
-    Has_Block_Obj new_rule = static_cast<Has_Block_Ptr>(SASS_MEMORY_COPY(this->parent()));
+    Has_Block_Obj new_rule = Cast<Has_Block>(SASS_MEMORY_COPY(this->parent()));
     new_rule->block(bb);
     new_rule->tabs(this->parent()->tabs());
-    new_rule->block()->concat(&m->block());
+    new_rule->block()->concat(m->block());
 
     Block_Obj wrapper_block = SASS_MEMORY_NEW(Block, m->block() ? m->block()->pstate() : m->pstate());
-    wrapper_block->append(&new_rule);
+    wrapper_block->append(new_rule);
     Directive_Obj mm = SASS_MEMORY_NEW(Directive,
                                   m->pstate(),
                                   m->keyword(),
@@ -294,20 +299,23 @@
                                   wrapper_block);
     if (m->value()) mm->value(m->value());
 
-    Bubble_Ptr bubble = SASS_MEMORY_NEW(Bubble, mm->pstate(), &mm);
+    Bubble_Ptr bubble = SASS_MEMORY_NEW(Bubble, mm->pstate(), mm);
     return bubble;
   }
 
   Statement_Ptr Cssize::bubble(At_Root_Block_Ptr m)
   {
+    if (!m || !m->block()) return NULL;
     Block_Ptr bb = SASS_MEMORY_NEW(Block, this->parent()->pstate());
-    Has_Block_Obj new_rule = static_cast<Has_Block_Ptr>(SASS_MEMORY_COPY(this->parent()));
-    new_rule->block(bb);
-    new_rule->tabs(this->parent()->tabs());
-    new_rule->block()->concat(&m->block());
-
+    Has_Block_Obj new_rule = Cast<Has_Block>(SASS_MEMORY_COPY(this->parent()));
     Block_Ptr wrapper_block = SASS_MEMORY_NEW(Block, m->block()->pstate());
-    wrapper_block->append(&new_rule);
+    if (new_rule) {
+      new_rule->block(bb);
+      new_rule->tabs(this->parent()->tabs());
+      new_rule->block()->concat(m->block());
+      wrapper_block->append(new_rule);
+    }
+
     At_Root_Block_Ptr mm = SASS_MEMORY_NEW(At_Root_Block,
                                         m->pstate(),
                                         wrapper_block,
@@ -318,7 +326,7 @@
 
   Statement_Ptr Cssize::bubble(Supports_Block_Ptr m)
   {
-    Ruleset_Obj parent = static_cast<Ruleset_Ptr>(SASS_MEMORY_COPY(this->parent()));
+    Ruleset_Obj parent = Cast<Ruleset>(SASS_MEMORY_COPY(this->parent()));
 
     Block_Ptr bb = SASS_MEMORY_NEW(Block, parent->block()->pstate());
     Ruleset_Ptr new_rule = SASS_MEMORY_NEW(Ruleset,
@@ -326,13 +334,13 @@
                                         parent->selector(),
                                         bb);
     new_rule->tabs(parent->tabs());
-    new_rule->block()->concat(&m->block());
+    new_rule->block()->concat(m->block());
 
     Block_Ptr wrapper_block = SASS_MEMORY_NEW(Block, m->block()->pstate());
     wrapper_block->append(new_rule);
     Supports_Block_Ptr mm = SASS_MEMORY_NEW(Supports_Block,
                                        m->pstate(),
-                                       &m->condition(),
+                                       m->condition(),
                                        wrapper_block);
 
     mm->tabs(m->tabs());
@@ -343,7 +351,7 @@
 
   Statement_Ptr Cssize::bubble(Media_Block_Ptr m)
   {
-    Ruleset_Obj parent = static_cast<Ruleset_Ptr>(SASS_MEMORY_COPY(this->parent()));
+    Ruleset_Obj parent = Cast<Ruleset>(SASS_MEMORY_COPY(this->parent()));
 
     Block_Ptr bb = SASS_MEMORY_NEW(Block, parent->block()->pstate());
     Ruleset_Ptr new_rule = SASS_MEMORY_NEW(Ruleset,
@@ -351,32 +359,31 @@
                                         parent->selector(),
                                         bb);
     new_rule->tabs(parent->tabs());
-    new_rule->block()->concat(&m->block());
+    new_rule->block()->concat(m->block());
 
     Block_Ptr wrapper_block = SASS_MEMORY_NEW(Block, m->block()->pstate());
     wrapper_block->append(new_rule);
     Media_Block_Obj mm = SASS_MEMORY_NEW(Media_Block,
                                       m->pstate(),
-                                      &m->media_queries(),
-                                      wrapper_block,
-                                      0);
+                                      m->media_queries(),
+                                      wrapper_block);
 
     mm->tabs(m->tabs());
 
-    return SASS_MEMORY_NEW(Bubble, mm->pstate(), &mm);
+    return SASS_MEMORY_NEW(Bubble, mm->pstate(), mm);
   }
 
   bool Cssize::bubblable(Statement_Ptr s)
   {
-    return dynamic_cast<Ruleset_Ptr>(s) || s->bubbles();
+    return Cast<Ruleset>(s) || s->bubbles();
   }
 
   Block_Ptr Cssize::flatten(Block_Ptr b)
   {
     Block_Ptr result = SASS_MEMORY_NEW(Block, b->pstate(), 0, b->is_root());
     for (size_t i = 0, L = b->length(); i < L; ++i) {
-      Statement_Ptr ss = &b->at(i);
-      if (Block_Ptr bb = SASS_MEMORY_CAST_PTR(Block, ss)) {
+      Statement_Ptr ss = b->at(i);
+      if (Block_Ptr bb = Cast<Block>(ss)) {
         Block_Obj bs = flatten(bb);
         for (size_t j = 0, K = bs->length(); j < K; ++j) {
           result->append(bs->at(j));
@@ -395,7 +402,7 @@
 
     for (size_t i = 0, L = b->length(); i < L; ++i) {
       Statement_Obj value = b->at(i);
-      bool key = dynamic_cast<Bubble_Ptr>(&value) != NULL;
+      bool key = Cast<Bubble>(value) != NULL;
 
       if (!results.empty() && results.back().first == key)
       {
@@ -424,45 +431,50 @@
 
       if (!is_bubble) {
         if (!parent) {
-          result->append(&slice);
+          result->append(slice);
         }
         else if (previous_parent) {
-          previous_parent->block()->concat(&slice);
+          previous_parent->block()->concat(slice);
         }
         else {
-          previous_parent = static_cast<Has_Block_Ptr>(SASS_MEMORY_COPY(parent));
+          previous_parent = Cast<Has_Block>(SASS_MEMORY_COPY(parent));
           previous_parent->block(slice);
           previous_parent->tabs(parent->tabs());
 
-          result->append(&previous_parent);
+          result->append(previous_parent);
         }
         continue;
       }
 
       for (size_t j = 0, K = slice->length(); j < K; ++j)
       {
-        Statement_Ptr ss = NULL;
+        Statement_Ptr ss;
         Statement_Obj stm = slice->at(j);
         // this has to go now here (too bad)
-        Bubble_Obj node = SASS_MEMORY_CAST(Bubble, stm);
+        Bubble_Obj node = Cast<Bubble>(stm);
         Media_Block_Ptr m1 = NULL;
         Media_Block_Ptr m2 = NULL;
-        if (parent) m1 = SASS_MEMORY_CAST(Media_Block, *parent);
-        if (node) m2 = SASS_MEMORY_CAST(Media_Block, node->node());
+        if (parent) m1 = Cast<Media_Block>(parent);
+        if (node) m2 = Cast<Media_Block>(node->node());
         if (!parent ||
             parent->statement_type() != Statement::MEDIA ||
             node->node()->statement_type() != Statement::MEDIA ||
-            (m1 && m2 && &m1->media_queries() == &m2->media_queries())
+            (m1 && m2 && *m1->media_queries() == *m2->media_queries())
           )
         {
-          ss = &node->node();
+          ss = node->node();
         }
         else
         {
-          List_Obj mq = merge_media_queries(static_cast<Media_Block_Ptr>(&node->node()), static_cast<Media_Block_Ptr>(parent));
+          List_Obj mq = merge_media_queries(
+            Cast<Media_Block>(node->node()),
+            Cast<Media_Block>(parent)
+          );
           if (!mq->length()) continue;
-          static_cast<Media_Block_Ptr>(&node->node())->media_queries(mq);
-          ss = &node->node();
+          if (Media_Block* b = Cast<Media_Block>(node->node())) {
+            b->media_queries(mq);
+          }
+          ss = node->node();
         }
 
         if (!ss) continue;
@@ -470,8 +482,6 @@
         ss->tabs(ss->tabs() + node->tabs());
         ss->group_end(node->group_end());
 
-        if (!ss) continue;
-
         Block_Obj bb = SASS_MEMORY_NEW(Block,
                                     children->pstate(),
                                     children->length(),
@@ -483,7 +493,7 @@
                                               children->length(),
                                               children->is_root());
 
-        Block_Ptr wrapper = flatten(&bb);
+        Block_Ptr wrapper = flatten(bb);
         wrapper_block->append(wrapper);
 
         if (wrapper->length()) {
@@ -491,12 +501,12 @@
         }
 
         if (wrapper_block) {
-          result->append(&wrapper_block);
+          result->append(wrapper_block);
         }
       }
     }
 
-    return flatten(&result);
+    return flatten(result);
   }
 
   Statement_Ptr Cssize::fallback_impl(AST_Node_Ptr n)
@@ -508,7 +518,7 @@
   {
     for (size_t i = 0, L = b->length(); i < L; ++i) {
       Statement_Obj ith = b->at(i)->perform(this);
-      if (Block_Ptr bb = SASS_MEMORY_CAST(Block, ith)) {
+      if (Block_Ptr bb = Cast<Block>(ith)) {
         for (size_t j = 0, K = bb->length(); j < K; ++j) {
           cur->append(bb->at(j));
         }
@@ -530,8 +540,8 @@
       for (size_t j = 0, K = m2->media_queries()->length(); j < K; j++) {
         Expression_Obj l1 = m1->media_queries()->at(i);
         Expression_Obj l2 = m2->media_queries()->at(j);
-        Media_Query_Ptr mq1 = SASS_MEMORY_CAST(Media_Query, l1);
-        Media_Query_Ptr mq2 = SASS_MEMORY_CAST(Media_Query, l2);
+        Media_Query_Ptr mq1 = Cast<Media_Query>(l1);
+        Media_Query_Ptr mq2 = Cast<Media_Query>(l2);
         Media_Query_Ptr mq = merge_media_query(mq1, mq2);
         if (mq) qq->append(mq);
       }
@@ -548,9 +558,9 @@
     std::string mod;
 
     std::string m1 = std::string(mq1->is_restricted() ? "only" : mq1->is_negated() ? "not" : "");
-    std::string t1 = &mq1->media_type() ? mq1->media_type()->to_string(ctx.c_options) : "";
+    std::string t1 = mq1->media_type() ? mq1->media_type()->to_string(ctx.c_options) : "";
     std::string m2 = std::string(mq2->is_restricted() ? "only" : mq1->is_negated() ? "not" : "");
-    std::string t2 = &mq2->media_type() ? mq2->media_type()->to_string(ctx.c_options) : "";
+    std::string t2 = mq2->media_type() ? mq2->media_type()->to_string(ctx.c_options) : "";
 
 
     if (t1.empty()) t1 = t2;
@@ -578,10 +588,11 @@
     }
 
     Media_Query_Ptr mm = SASS_MEMORY_NEW(Media_Query,
-
-mq1->pstate(), 0,
-mq1->length() + mq2->length(), mod == "not", mod == "only"
-);
+                                         mq1->pstate(),
+                                         0,
+                                         mq1->length() + mq2->length(),
+                                         mod == "not",
+                                         mod == "only");
 
     if (!type.empty()) {
       mm->media_type(SASS_MEMORY_NEW(String_Quoted, mq1->pstate(), type));
diff --git a/libsass/src/cssize.hpp b/libsass/src/cssize.hpp
--- a/libsass/src/cssize.hpp
+++ b/libsass/src/cssize.hpp
@@ -8,20 +8,19 @@
 
 namespace Sass {
 
-  typedef Environment<AST_Node_Obj> Env;
   struct Backtrace;
 
   class Cssize : public Operation_CRTP<Statement_Ptr, Cssize> {
 
     Context&                    ctx;
-    std::vector<Block_Ptr>         block_stack;
-    std::vector<Statement_Ptr>     p_stack;
-    Backtrace*                  backtrace;
+    Backtraces&                 traces;
+    std::vector<Block_Ptr>      block_stack;
+    std::vector<Statement_Ptr>  p_stack;
 
     Statement_Ptr fallback_impl(AST_Node_Ptr n);
 
   public:
-    Cssize(Context&, Backtrace*);
+    Cssize(Context&);
     ~Cssize() { }
 
     Selector_List_Ptr selector();
diff --git a/libsass/src/debugger.hpp b/libsass/src/debugger.hpp
--- a/libsass/src/debugger.hpp
+++ b/libsass/src/debugger.hpp
@@ -10,11 +10,15 @@
 
 inline void debug_ast(AST_Node_Ptr node, std::string ind = "", Env* env = 0);
 
-inline void debug_sources_set(SourcesSet& set, std::string ind = "")
+inline void debug_ast(const AST_Node* node, std::string ind = "", Env* env = 0) {
+  debug_ast(const_cast<AST_Node*>(node), ind, env);
+}
+
+inline void debug_sources_set(ComplexSelectorSet& set, std::string ind = "")
 {
   if (ind == "") std::cerr << "#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
   for(auto const &pair : set) {
-    debug_ast(&pair, ind + "");
+    debug_ast(pair, ind + "");
     // debug_ast(set[pair], ind + "first: ");
   }
   if (ind == "") std::cerr << "#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
@@ -64,30 +68,30 @@
 {
   if (node == 0) return;
   if (ind == "") std::cerr << "####################################################################\n";
-  if (dynamic_cast<Bubble_Ptr>(node)) {
-    Bubble_Ptr bubble = dynamic_cast<Bubble_Ptr>(node);
+  if (Cast<Bubble>(node)) {
+    Bubble_Ptr bubble = Cast<Bubble>(node);
     std::cerr << ind << "Bubble " << bubble;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " " << bubble->tabs();
     std::cerr << std::endl;
-    debug_ast(&bubble->node(), ind + " ", env);
-  } else if (dynamic_cast<Trace_Ptr>(node)) {
-    Trace_Ptr trace = dynamic_cast<Trace_Ptr>(node);
+    debug_ast(bubble->node(), ind + " ", env);
+  } else if (Cast<Trace>(node)) {
+    Trace_Ptr trace = Cast<Trace>(node);
     std::cerr << ind << "Trace " << trace;
     std::cerr << " (" << pstate_source_position(node) << ")"
-    << " [name:" << trace->name() << "]"
+    << " [name:" << trace->name() << ", type: " << trace->type() << "]"
     << std::endl;
-    debug_ast(&trace->block(), ind + " ", env);
-  } else if (dynamic_cast<At_Root_Block_Ptr>(node)) {
-    At_Root_Block_Ptr root_block = dynamic_cast<At_Root_Block_Ptr>(node);
+    debug_ast(trace->block(), ind + " ", env);
+  } else if (Cast<At_Root_Block>(node)) {
+    At_Root_Block_Ptr root_block = Cast<At_Root_Block>(node);
     std::cerr << ind << "At_Root_Block " << root_block;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " " << root_block->tabs();
     std::cerr << std::endl;
-    debug_ast(&root_block->expression(), ind + ":", env);
-    debug_ast(&root_block->block(), ind + " ", env);
-  } else if (dynamic_cast<Selector_List_Ptr>(node)) {
-    Selector_List_Ptr selector = dynamic_cast<Selector_List_Ptr>(node);
+    debug_ast(root_block->expression(), ind + ":", env);
+    debug_ast(root_block->block(), ind + " ", env);
+  } else if (Cast<Selector_List>(node)) {
+    Selector_List_Ptr selector = Cast<Selector_List>(node);
     std::cerr << ind << "Selector_List " << selector;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " <" << selector->hash() << ">";
@@ -99,15 +103,16 @@
     std::cerr << (selector->has_line_break() ? " [line-break]": " -");
     std::cerr << (selector->has_line_feed() ? " [line-feed]": " -");
     std::cerr << std::endl;
+    debug_ast(selector->schema(), ind + "#{} ");
 
-    for(const Complex_Selector_Obj& i : selector->elements()) { debug_ast(&i, ind + " ", env); }
+    for(const Complex_Selector_Obj& i : selector->elements()) { debug_ast(i, ind + " ", env); }
 
-//  } else if (dynamic_cast<Expression_Ptr>(node)) {
-//    Expression_Ptr expression = dynamic_cast<Expression_Ptr>(node);
+//  } else if (Cast<Expression>(node)) {
+//    Expression_Ptr expression = Cast<Expression>(node);
 //    std::cerr << ind << "Expression " << expression << " " << expression->concrete_type() << std::endl;
 
-  } else if (dynamic_cast<Parent_Selector_Ptr>(node)) {
-    Parent_Selector_Ptr selector = dynamic_cast<Parent_Selector_Ptr>(node);
+  } else if (Cast<Parent_Selector>(node)) {
+    Parent_Selector_Ptr selector = Cast<Parent_Selector>(node);
     std::cerr << ind << "Parent_Selector " << selector;
 //    if (selector->not_selector()) cerr << " [in_declaration]";
     std::cerr << " (" << pstate_source_position(node) << ")";
@@ -116,8 +121,8 @@
     std::cerr << " <" << prettyprint(selector->pstate().token.ws_before()) << ">" << std::endl;
 //    debug_ast(selector->selector(), ind + "->", env);
 
-  } else if (dynamic_cast<Complex_Selector_Ptr>(node)) {
-    Complex_Selector_Ptr selector = dynamic_cast<Complex_Selector_Ptr>(node);
+  } else if (Cast<Complex_Selector>(node)) {
+    Complex_Selector_Ptr selector = Cast<Complex_Selector>(node);
     std::cerr << ind << "Complex_Selector " << selector
       << " (" << pstate_source_position(node) << ")"
       << " <" << selector->hash() << ">"
@@ -141,16 +146,16 @@
       }
       // if (del = "/") del += selector->reference()->perform(&to_string) + "/";
     std::cerr << " <" << prettyprint(selector->pstate().token.ws_before()) << ">" << std::endl;
-    debug_ast(&selector->head(), ind + " " /* + "[" + del + "]" */, env);
+    debug_ast(selector->head(), ind + " " /* + "[" + del + "]" */, env);
     if (selector->tail()) {
-      debug_ast(&selector->tail(), ind + "{" + del + "}", env);
+      debug_ast(selector->tail(), ind + "{" + del + "}", env);
     } else if(del != " ") {
       std::cerr << ind << " |" << del << "| {trailing op}" << std::endl;
     }
-    SourcesSet set = selector->sources();
+    ComplexSelectorSet set = selector->sources();
     // debug_sources_set(set, ind + "  @--> ");
-  } else if (dynamic_cast<Compound_Selector_Ptr>(node)) {
-    Compound_Selector_Ptr selector = dynamic_cast<Compound_Selector_Ptr>(node);
+  } else if (Cast<Compound_Selector>(node)) {
+    Compound_Selector_Ptr selector = Cast<Compound_Selector>(node);
     std::cerr << ind << "Compound_Selector " << selector;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " <" << selector->hash() << ">";
@@ -162,9 +167,9 @@
     std::cerr << (selector->has_line_break() ? " [line-break]": " -");
     std::cerr << (selector->has_line_feed() ? " [line-feed]": " -");
     std::cerr << " <" << prettyprint(selector->pstate().token.ws_before()) << ">" << std::endl;
-    for(const Simple_Selector_Obj& i : selector->elements()) { debug_ast(&i, ind + " ", env); }
-  } else if (dynamic_cast<Wrapped_Selector_Ptr>(node)) {
-    Wrapped_Selector_Ptr selector = dynamic_cast<Wrapped_Selector_Ptr>(node);
+    for(const Simple_Selector_Obj& i : selector->elements()) { debug_ast(i, ind + " ", env); }
+  } else if (Cast<Wrapped_Selector>(node)) {
+    Wrapped_Selector_Ptr selector = Cast<Wrapped_Selector>(node);
     std::cerr << ind << "Wrapped_Selector " << selector;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " <" << selector->hash() << ">";
@@ -174,9 +179,9 @@
     std::cerr << (selector->has_line_break() ? " [line-break]": " -");
     std::cerr << (selector->has_line_feed() ? " [line-feed]": " -");
     std::cerr << std::endl;
-    debug_ast(&selector->selector(), ind + " () ", env);
-  } else if (dynamic_cast<Pseudo_Selector_Ptr>(node)) {
-    Pseudo_Selector_Ptr selector = dynamic_cast<Pseudo_Selector_Ptr>(node);
+    debug_ast(selector->selector(), ind + " () ", env);
+  } else if (Cast<Pseudo_Selector>(node)) {
+    Pseudo_Selector_Ptr selector = Cast<Pseudo_Selector>(node);
     std::cerr << ind << "Pseudo_Selector " << selector;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " <" << selector->hash() << ">";
@@ -186,9 +191,9 @@
     std::cerr << (selector->has_line_break() ? " [line-break]": " -");
     std::cerr << (selector->has_line_feed() ? " [line-feed]": " -");
     std::cerr << std::endl;
-    debug_ast(&selector->expression(), ind + " <= ", env);
-  } else if (dynamic_cast<Attribute_Selector_Ptr>(node)) {
-    Attribute_Selector_Ptr selector = dynamic_cast<Attribute_Selector_Ptr>(node);
+    debug_ast(selector->expression(), ind + " <= ", env);
+  } else if (Cast<Attribute_Selector>(node)) {
+    Attribute_Selector_Ptr selector = Cast<Attribute_Selector>(node);
     std::cerr << ind << "Attribute_Selector " << selector;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " <" << selector->hash() << ">";
@@ -198,9 +203,9 @@
     std::cerr << (selector->has_line_break() ? " [line-break]": " -");
     std::cerr << (selector->has_line_feed() ? " [line-feed]": " -");
     std::cerr << std::endl;
-    debug_ast(&selector->value(), ind + "[" + selector->matcher() + "] ", env);
-  } else if (dynamic_cast<Class_Selector_Ptr>(node)) {
-    Class_Selector_Ptr selector = dynamic_cast<Class_Selector_Ptr>(node);
+    debug_ast(selector->value(), ind + "[" + selector->matcher() + "] ", env);
+  } else if (Cast<Class_Selector>(node)) {
+    Class_Selector_Ptr selector = Cast<Class_Selector>(node);
     std::cerr << ind << "Class_Selector " << selector;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " <" << selector->hash() << ">";
@@ -210,8 +215,8 @@
     std::cerr << (selector->has_line_break() ? " [line-break]": " -");
     std::cerr << (selector->has_line_feed() ? " [line-feed]": " -");
     std::cerr << std::endl;
-  } else if (dynamic_cast<Id_Selector_Ptr>(node)) {
-    Id_Selector_Ptr selector = dynamic_cast<Id_Selector_Ptr>(node);
+  } else if (Cast<Id_Selector>(node)) {
+    Id_Selector_Ptr selector = Cast<Id_Selector>(node);
     std::cerr << ind << "Id_Selector " << selector;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " <" << selector->hash() << ">";
@@ -221,8 +226,8 @@
     std::cerr << (selector->has_line_break() ? " [line-break]": " -");
     std::cerr << (selector->has_line_feed() ? " [line-feed]": " -");
     std::cerr << std::endl;
-  } else if (dynamic_cast<Element_Selector_Ptr>(node)) {
-    Element_Selector_Ptr selector = dynamic_cast<Element_Selector_Ptr>(node);
+  } else if (Cast<Element_Selector>(node)) {
+    Element_Selector_Ptr selector = Cast<Element_Selector>(node);
     std::cerr << ind << "Element_Selector " << selector;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " <" << selector->hash() << ">";
@@ -233,9 +238,9 @@
     std::cerr << (selector->has_line_feed() ? " [line-feed]": " -");
     std::cerr << " <" << prettyprint(selector->pstate().token.ws_before()) << ">";
     std::cerr << std::endl;
-  } else if (dynamic_cast<Placeholder_Selector_Ptr>(node)) {
+  } else if (Cast<Placeholder_Selector>(node)) {
 
-    Placeholder_Selector_Ptr selector = dynamic_cast<Placeholder_Selector_Ptr>(node);
+    Placeholder_Selector_Ptr selector = Cast<Placeholder_Selector>(node);
     std::cerr << ind << "Placeholder_Selector [" << selector->ns_name() << "] " << selector;
     std::cerr << " (" << pstate_source_position(selector) << ")"
       << " <" << selector->hash() << ">"
@@ -245,212 +250,211 @@
       << (selector->has_line_feed() ? " [line-feed]": " -")
     << std::endl;
 
-  } else if (dynamic_cast<Simple_Selector*>(node)) {
-    Simple_Selector* selector = dynamic_cast<Simple_Selector*>(node);
+  } else if (Cast<Simple_Selector>(node)) {
+    Simple_Selector* selector = Cast<Simple_Selector>(node);
     std::cerr << ind << "Simple_Selector " << selector;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << (selector->has_line_break() ? " [line-break]": " -") << (selector->has_line_feed() ? " [line-feed]": " -") << std::endl;
 
-  } else if (dynamic_cast<Selector_Schema_Ptr>(node)) {
-    Selector_Schema_Ptr selector = dynamic_cast<Selector_Schema_Ptr>(node);
+  } else if (Cast<Selector_Schema>(node)) {
+    Selector_Schema_Ptr selector = Cast<Selector_Schema>(node);
     std::cerr << ind << "Selector_Schema " << selector;
     std::cerr << " (" << pstate_source_position(node) << ")"
-      << (selector->at_root() && selector->at_root() ? " [@ROOT]" : "")
       << " [@media:" << selector->media_block() << "]"
-      << (selector->has_line_break() ? " [line-break]": " -")
-      << (selector->has_line_feed() ? " [line-feed]": " -")
+      << (selector->connect_parent() ? " [connect-parent]": " -")
     << std::endl;
 
-    debug_ast(&selector->contents(), ind + " ");
+    debug_ast(selector->contents(), ind + " ");
     // for(auto i : selector->elements()) { debug_ast(i, ind + " ", env); }
 
-  } else if (dynamic_cast<Selector_Ptr>(node)) {
-    Selector_Ptr selector = dynamic_cast<Selector_Ptr>(node);
+  } else if (Cast<Selector>(node)) {
+    Selector_Ptr selector = Cast<Selector>(node);
     std::cerr << ind << "Selector " << selector;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << (selector->has_line_break() ? " [line-break]": " -")
       << (selector->has_line_feed() ? " [line-feed]": " -")
     << std::endl;
 
-  } else if (dynamic_cast<Media_Query_Expression_Ptr>(node)) {
-    Media_Query_Expression_Ptr block = dynamic_cast<Media_Query_Expression_Ptr>(node);
+  } else if (Cast<Media_Query_Expression>(node)) {
+    Media_Query_Expression_Ptr block = Cast<Media_Query_Expression>(node);
     std::cerr << ind << "Media_Query_Expression " << block;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << (block->is_interpolated() ? " [is_interpolated]": " -")
     << std::endl;
-    debug_ast(&block->feature(), ind + " feature) ");
-    debug_ast(&block->value(), ind + " value) ");
+    debug_ast(block->feature(), ind + " feature) ");
+    debug_ast(block->value(), ind + " value) ");
 
-  } else if (dynamic_cast<Media_Query_Ptr>(node)) {
-    Media_Query_Ptr block = dynamic_cast<Media_Query_Ptr>(node);
+  } else if (Cast<Media_Query>(node)) {
+    Media_Query_Ptr block = Cast<Media_Query>(node);
     std::cerr << ind << "Media_Query " << block;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << (block->is_negated() ? " [is_negated]": " -")
       << (block->is_restricted() ? " [is_restricted]": " -")
     << std::endl;
-    debug_ast(&block->media_type(), ind + " ");
-    for(const auto& i : block->elements()) { debug_ast(&i, ind + " ", env); }
+    debug_ast(block->media_type(), ind + " ");
+    for(const auto& i : block->elements()) { debug_ast(i, ind + " ", env); }
 
-  } else if (dynamic_cast<Media_Block_Ptr>(node)) {
-    Media_Block_Ptr block = dynamic_cast<Media_Block_Ptr>(node);
+  } else if (Cast<Media_Block>(node)) {
+    Media_Block_Ptr block = Cast<Media_Block>(node);
     std::cerr << ind << "Media_Block " << block;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " " << block->tabs() << std::endl;
-    debug_ast(&block->media_queries(), ind + " =@ ");
-    if (block->block()) for(const Statement_Obj& i : block->block()->elements()) { debug_ast(&i, ind + " ", env); }
-  } else if (dynamic_cast<Supports_Block_Ptr>(node)) {
-    Supports_Block_Ptr block = dynamic_cast<Supports_Block_Ptr>(node);
+    debug_ast(block->media_queries(), ind + " =@ ");
+    if (block->block()) for(const Statement_Obj& i : block->block()->elements()) { debug_ast(i, ind + " ", env); }
+  } else if (Cast<Supports_Block>(node)) {
+    Supports_Block_Ptr block = Cast<Supports_Block>(node);
     std::cerr << ind << "Supports_Block " << block;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " " << block->tabs() << std::endl;
-    debug_ast(&block->condition(), ind + " =@ ");
-    debug_ast(&block->block(), ind + " <>");
-  } else if (dynamic_cast<Supports_Operator_Ptr>(node)) {
-    Supports_Operator_Ptr block = dynamic_cast<Supports_Operator_Ptr>(node);
+    debug_ast(block->condition(), ind + " =@ ");
+    debug_ast(block->block(), ind + " <>");
+  } else if (Cast<Supports_Operator>(node)) {
+    Supports_Operator_Ptr block = Cast<Supports_Operator>(node);
     std::cerr << ind << "Supports_Operator " << block;
     std::cerr << " (" << pstate_source_position(node) << ")"
     << std::endl;
-    debug_ast(&block->left(), ind + " left) ");
-    debug_ast(&block->right(), ind + " right) ");
-  } else if (dynamic_cast<Supports_Negation_Ptr>(node)) {
-    Supports_Negation_Ptr block = dynamic_cast<Supports_Negation_Ptr>(node);
+    debug_ast(block->left(), ind + " left) ");
+    debug_ast(block->right(), ind + " right) ");
+  } else if (Cast<Supports_Negation>(node)) {
+    Supports_Negation_Ptr block = Cast<Supports_Negation>(node);
     std::cerr << ind << "Supports_Negation " << block;
     std::cerr << " (" << pstate_source_position(node) << ")"
     << std::endl;
-    debug_ast(&block->condition(), ind + " condition) ");
-  } else if (dynamic_cast<At_Root_Query_Ptr>(node)) {
-    At_Root_Query_Ptr block = dynamic_cast<At_Root_Query_Ptr>(node);
+    debug_ast(block->condition(), ind + " condition) ");
+  } else if (Cast<At_Root_Query>(node)) {
+    At_Root_Query_Ptr block = Cast<At_Root_Query>(node);
     std::cerr << ind << "At_Root_Query " << block;
     std::cerr << " (" << pstate_source_position(node) << ")"
     << std::endl;
-    debug_ast(&block->feature(), ind + " feature) ");
-    debug_ast(&block->value(), ind + " value) ");
-  } else if (dynamic_cast<Supports_Declaration_Ptr>(node)) {
-    Supports_Declaration_Ptr block = dynamic_cast<Supports_Declaration_Ptr>(node);
+    debug_ast(block->feature(), ind + " feature) ");
+    debug_ast(block->value(), ind + " value) ");
+  } else if (Cast<Supports_Declaration>(node)) {
+    Supports_Declaration_Ptr block = Cast<Supports_Declaration>(node);
     std::cerr << ind << "Supports_Declaration " << block;
     std::cerr << " (" << pstate_source_position(node) << ")"
     << std::endl;
-    debug_ast(&block->feature(), ind + " feature) ");
-    debug_ast(&block->value(), ind + " value) ");
-  } else if (dynamic_cast<Block_Ptr>(node)) {
-    Block_Ptr root_block = dynamic_cast<Block_Ptr>(node);
+    debug_ast(block->feature(), ind + " feature) ");
+    debug_ast(block->value(), ind + " value) ");
+  } else if (Cast<Block>(node)) {
+    Block_Ptr root_block = Cast<Block>(node);
     std::cerr << ind << "Block " << root_block;
     std::cerr << " (" << pstate_source_position(node) << ")";
     if (root_block->is_root()) std::cerr << " [root]";
     std::cerr << " " << root_block->tabs() << std::endl;
-    for(const Statement_Obj& i : root_block->elements()) { debug_ast(&i, ind + " ", env); }
-  } else if (dynamic_cast<Warning_Ptr>(node)) {
-    Warning_Ptr block = dynamic_cast<Warning_Ptr>(node);
+    for(const Statement_Obj& i : root_block->elements()) { debug_ast(i, ind + " ", env); }
+  } else if (Cast<Warning>(node)) {
+    Warning_Ptr block = Cast<Warning>(node);
     std::cerr << ind << "Warning " << block;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " " << block->tabs() << std::endl;
-    debug_ast(&block->message(), ind + " : ");
-  } else if (dynamic_cast<Error_Ptr>(node)) {
-    Error_Ptr block = dynamic_cast<Error_Ptr>(node);
+    debug_ast(block->message(), ind + " : ");
+  } else if (Cast<Error>(node)) {
+    Error_Ptr block = Cast<Error>(node);
     std::cerr << ind << "Error " << block;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " " << block->tabs() << std::endl;
-  } else if (dynamic_cast<Debug_Ptr>(node)) {
-    Debug_Ptr block = dynamic_cast<Debug_Ptr>(node);
+  } else if (Cast<Debug>(node)) {
+    Debug_Ptr block = Cast<Debug>(node);
     std::cerr << ind << "Debug " << block;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " " << block->tabs() << std::endl;
-    debug_ast(&block->value(), ind + " ");
-  } else if (dynamic_cast<Comment_Ptr>(node)) {
-    Comment_Ptr block = dynamic_cast<Comment_Ptr>(node);
+    debug_ast(block->value(), ind + " ");
+  } else if (Cast<Comment>(node)) {
+    Comment_Ptr block = Cast<Comment>(node);
     std::cerr << ind << "Comment " << block;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " " << block->tabs() <<
       " <" << prettyprint(block->pstate().token.ws_before()) << ">" << std::endl;
-    debug_ast(&block->text(), ind + "// ", env);
-  } else if (dynamic_cast<If_Ptr>(node)) {
-    If_Ptr block = dynamic_cast<If_Ptr>(node);
+    debug_ast(block->text(), ind + "// ", env);
+  } else if (Cast<If>(node)) {
+    If_Ptr block = Cast<If>(node);
     std::cerr << ind << "If " << block;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " " << block->tabs() << std::endl;
-    debug_ast(&block->predicate(), ind + " = ");
-    debug_ast(&block->block(), ind + " <>");
-    debug_ast(&block->alternative(), ind + " ><");
-  } else if (dynamic_cast<Return_Ptr>(node)) {
-    Return_Ptr block = dynamic_cast<Return_Ptr>(node);
+    debug_ast(block->predicate(), ind + " = ");
+    debug_ast(block->block(), ind + " <>");
+    debug_ast(block->alternative(), ind + " ><");
+  } else if (Cast<Return>(node)) {
+    Return_Ptr block = Cast<Return>(node);
     std::cerr << ind << "Return " << block;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " " << block->tabs() << std::endl;
-  } else if (dynamic_cast<Extension_Ptr>(node)) {
-    Extension_Ptr block = dynamic_cast<Extension_Ptr>(node);
+  } else if (Cast<Extension>(node)) {
+    Extension_Ptr block = Cast<Extension>(node);
     std::cerr << ind << "Extension " << block;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " " << block->tabs() << std::endl;
-    debug_ast(&block->selector(), ind + "-> ", env);
-  } else if (dynamic_cast<Content_Ptr>(node)) {
-    Content_Ptr block = dynamic_cast<Content_Ptr>(node);
+    debug_ast(block->selector(), ind + "-> ", env);
+  } else if (Cast<Content>(node)) {
+    Content_Ptr block = Cast<Content>(node);
     std::cerr << ind << "Content " << block;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " [@media:" << block->media_block() << "]";
     std::cerr << " " << block->tabs() << std::endl;
-  } else if (dynamic_cast<Import_Stub_Ptr>(node)) {
-    Import_Stub_Ptr block = dynamic_cast<Import_Stub_Ptr>(node);
+  } else if (Cast<Import_Stub>(node)) {
+    Import_Stub_Ptr block = Cast<Import_Stub>(node);
     std::cerr << ind << "Import_Stub " << block;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " [" << block->imp_path() << "] ";
     std::cerr << " " << block->tabs() << std::endl;
-  } else if (dynamic_cast<Import_Ptr>(node)) {
-    Import_Ptr block = dynamic_cast<Import_Ptr>(node);
+  } else if (Cast<Import>(node)) {
+    Import_Ptr block = Cast<Import>(node);
     std::cerr << ind << "Import " << block;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " " << block->tabs() << std::endl;
     // std::vector<std::string>         files_;
-    for (auto imp : block->urls()) debug_ast(&imp, ind + "@: ", env);
-    debug_ast(&block->import_queries(), ind + "@@ ");
-  } else if (dynamic_cast<Assignment_Ptr>(node)) {
-    Assignment_Ptr block = dynamic_cast<Assignment_Ptr>(node);
+    for (auto imp : block->urls()) debug_ast(imp, ind + "@: ", env);
+    debug_ast(block->import_queries(), ind + "@@ ");
+  } else if (Cast<Assignment>(node)) {
+    Assignment_Ptr block = Cast<Assignment>(node);
     std::cerr << ind << "Assignment " << block;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " <<" << block->variable() << ">> " << block->tabs() << std::endl;
-    debug_ast(&block->value(), ind + "=", env);
-  } else if (dynamic_cast<Declaration_Ptr>(node)) {
-    Declaration_Ptr block = dynamic_cast<Declaration_Ptr>(node);
+    debug_ast(block->value(), ind + "=", env);
+  } else if (Cast<Declaration>(node)) {
+    Declaration_Ptr block = Cast<Declaration>(node);
     std::cerr << ind << "Declaration " << block;
     std::cerr << " (" << pstate_source_position(node) << ")";
+    std::cerr << " [is_custom_property: " << block->is_custom_property() << "] ";
     std::cerr << " " << block->tabs() << std::endl;
-    debug_ast(&block->property(), ind + " prop: ", env);
-    debug_ast(&block->value(), ind + " value: ", env);
-    debug_ast(&block->block(), ind + " ", env);
-  } else if (dynamic_cast<Keyframe_Rule_Ptr>(node)) {
-    Keyframe_Rule_Ptr has_block = dynamic_cast<Keyframe_Rule_Ptr>(node);
+    debug_ast(block->property(), ind + " prop: ", env);
+    debug_ast(block->value(), ind + " value: ", env);
+    debug_ast(block->block(), ind + " ", env);
+  } else if (Cast<Keyframe_Rule>(node)) {
+    Keyframe_Rule_Ptr has_block = Cast<Keyframe_Rule>(node);
     std::cerr << ind << "Keyframe_Rule " << has_block;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " " << has_block->tabs() << std::endl;
-    if (has_block->name()) debug_ast(&has_block->name(), ind + "@");
-    if (has_block->block()) for(const Statement_Obj& i : has_block->block()->elements()) { debug_ast(&i, ind + " ", env); }
-  } else if (dynamic_cast<Directive_Ptr>(node)) {
-    Directive_Ptr block = dynamic_cast<Directive_Ptr>(node);
+    if (has_block->name()) debug_ast(has_block->name(), ind + "@");
+    if (has_block->block()) for(const Statement_Obj& i : has_block->block()->elements()) { debug_ast(i, ind + " ", env); }
+  } else if (Cast<Directive>(node)) {
+    Directive_Ptr block = Cast<Directive>(node);
     std::cerr << ind << "Directive " << block;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " [" << block->keyword() << "] " << block->tabs() << std::endl;
-    debug_ast(&block->selector(), ind + "~", env);
-    debug_ast(&block->value(), ind + "+", env);
-    if (block->block()) for(const Statement_Obj& i : block->block()->elements()) { debug_ast(&i, ind + " ", env); }
-  } else if (dynamic_cast<Each_Ptr>(node)) {
-    Each_Ptr block = dynamic_cast<Each_Ptr>(node);
+    debug_ast(block->selector(), ind + "~", env);
+    debug_ast(block->value(), ind + "+", env);
+    if (block->block()) for(const Statement_Obj& i : block->block()->elements()) { debug_ast(i, ind + " ", env); }
+  } else if (Cast<Each>(node)) {
+    Each_Ptr block = Cast<Each>(node);
     std::cerr << ind << "Each " << block;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " " << block->tabs() << std::endl;
-    if (block->block()) for(const Statement_Obj& i : block->block()->elements()) { debug_ast(&i, ind + " ", env); }
-  } else if (dynamic_cast<For_Ptr>(node)) {
-    For_Ptr block = dynamic_cast<For_Ptr>(node);
+    if (block->block()) for(const Statement_Obj& i : block->block()->elements()) { debug_ast(i, ind + " ", env); }
+  } else if (Cast<For>(node)) {
+    For_Ptr block = Cast<For>(node);
     std::cerr << ind << "For " << block;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " " << block->tabs() << std::endl;
-    if (block->block()) for(const Statement_Obj& i : block->block()->elements()) { debug_ast(&i, ind + " ", env); }
-  } else if (dynamic_cast<While_Ptr>(node)) {
-    While_Ptr block = dynamic_cast<While_Ptr>(node);
+    if (block->block()) for(const Statement_Obj& i : block->block()->elements()) { debug_ast(i, ind + " ", env); }
+  } else if (Cast<While>(node)) {
+    While_Ptr block = Cast<While>(node);
     std::cerr << ind << "While " << block;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " " << block->tabs() << std::endl;
-    if (block->block()) for(const Statement_Obj& i : block->block()->elements()) { debug_ast(&i, ind + " ", env); }
-  } else if (dynamic_cast<Definition_Ptr>(node)) {
-    Definition_Ptr block = dynamic_cast<Definition_Ptr>(node);
+    if (block->block()) for(const Statement_Obj& i : block->block()->elements()) { debug_ast(i, ind + " ", env); }
+  } else if (Cast<Definition>(node)) {
+    Definition_Ptr block = Cast<Definition>(node);
     std::cerr << ind << "Definition " << block;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " [name: " << block->name() << "] ";
@@ -459,73 +463,69 @@
     // std::cerr << " [signature: " << block->signature() << "] ";
     std::cerr << " [native: " << block->native_function() << "] ";
     std::cerr << " " << block->tabs() << std::endl;
-    debug_ast(&block->parameters(), ind + " params: ", env);
-    if (block->block()) debug_ast(&block->block(), ind + " ", env);
-  } else if (dynamic_cast<Mixin_Call_Ptr>(node)) {
-    Mixin_Call_Ptr block = dynamic_cast<Mixin_Call_Ptr>(node);
+    debug_ast(block->parameters(), ind + " params: ", env);
+    if (block->block()) debug_ast(block->block(), ind + " ", env);
+  } else if (Cast<Mixin_Call>(node)) {
+    Mixin_Call_Ptr block = Cast<Mixin_Call>(node);
     std::cerr << ind << "Mixin_Call " << block << " " << block->tabs();
     std::cerr << " (" << pstate_source_position(block) << ")";
     std::cerr << " [" <<  block->name() << "]";
     std::cerr << " [has_content: " << block->has_content() << "] " << std::endl;
-    debug_ast(&block->arguments(), ind + " args: ");
-    if (block->block()) debug_ast(&block->block(), ind + " ", env);
-  } else if (Ruleset_Ptr ruleset = dynamic_cast<Ruleset_Ptr>(node)) {
+    debug_ast(block->arguments(), ind + " args: ");
+    if (block->block()) debug_ast(block->block(), ind + " ", env);
+  } else if (Ruleset_Ptr ruleset = Cast<Ruleset>(node)) {
     std::cerr << ind << "Ruleset " << ruleset;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " [indent: " << ruleset->tabs() << "]";
     std::cerr << (ruleset->is_invisible() ? " [INVISIBLE]" : "");
-    std::cerr << (ruleset->at_root() ? " [@ROOT]" : "");
     std::cerr << (ruleset->is_root() ? " [root]" : "");
     std::cerr << std::endl;
-    debug_ast(&ruleset->selector(), ind + ">");
-    debug_ast(&ruleset->block(), ind + " ");
-  } else if (dynamic_cast<Block_Ptr>(node)) {
-    Block_Ptr block = dynamic_cast<Block_Ptr>(node);
+    debug_ast(ruleset->selector(), ind + ">");
+    debug_ast(ruleset->block(), ind + " ");
+  } else if (Cast<Block>(node)) {
+    Block_Ptr block = Cast<Block>(node);
     std::cerr << ind << "Block " << block;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << (block->is_invisible() ? " [INVISIBLE]" : "");
     std::cerr << " [indent: " << block->tabs() << "]" << std::endl;
-    for(const Statement_Obj& i : block->elements()) { debug_ast(&i, ind + " ", env); }
-  } else if (dynamic_cast<Textual_Ptr>(node)) {
-    Textual_Ptr expression = dynamic_cast<Textual_Ptr>(node);
-    std::cerr << ind << "Textual " << expression;
-    std::cerr << " (" << pstate_source_position(node) << ")";
-    if (expression->type() == Textual::NUMBER) std::cerr << " [NUMBER]";
-    else if (expression->type() == Textual::PERCENTAGE) std::cerr << " [PERCENTAGE]";
-    else if (expression->type() == Textual::DIMENSION) std::cerr << " [DIMENSION]";
-    else if (expression->type() == Textual::HEX) std::cerr << " [HEX]";
-    std::cerr << " [" << expression->value() << "]";
-    std::cerr << " [interpolant: " << expression->is_interpolant() << "] ";
-    if (expression->is_delayed()) std::cerr << " [delayed]";
-    std::cerr << std::endl;
-  } else if (dynamic_cast<Variable_Ptr>(node)) {
-    Variable_Ptr expression = dynamic_cast<Variable_Ptr>(node);
+    for(const Statement_Obj& i : block->elements()) { debug_ast(i, ind + " ", env); }
+  } else if (Cast<Variable>(node)) {
+    Variable_Ptr expression = Cast<Variable>(node);
     std::cerr << ind << "Variable " << expression;
     std::cerr << " [interpolant: " << expression->is_interpolant() << "] ";
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " [" << expression->name() << "]" << std::endl;
     std::string name(expression->name());
-    if (env && env->has(name)) debug_ast(SASS_MEMORY_CAST(Expression, (*env)[name]), ind + " -> ", env);
-  } else if (dynamic_cast<Function_Call_Schema_Ptr>(node)) {
-    Function_Call_Schema_Ptr expression = dynamic_cast<Function_Call_Schema_Ptr>(node);
+    if (env && env->has(name)) debug_ast(Cast<Expression>((*env)[name]), ind + " -> ", env);
+  } else if (Cast<Function_Call_Schema>(node)) {
+    Function_Call_Schema_Ptr expression = Cast<Function_Call_Schema>(node);
     std::cerr << ind << "Function_Call_Schema " << expression;
     std::cerr << " [interpolant: " << expression->is_interpolant() << "] ";
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << "" << std::endl;
-    debug_ast(&expression->name(), ind + "name: ", env);
-    debug_ast(&expression->arguments(), ind + " args: ", env);
-  } else if (dynamic_cast<Function_Call_Ptr>(node)) {
-    Function_Call_Ptr expression = dynamic_cast<Function_Call_Ptr>(node);
+    debug_ast(expression->name(), ind + "name: ", env);
+    debug_ast(expression->arguments(), ind + " args: ", env);
+  } else if (Cast<Function_Call>(node)) {
+    Function_Call_Ptr expression = Cast<Function_Call>(node);
     std::cerr << ind << "Function_Call " << expression;
     std::cerr << " [interpolant: " << expression->is_interpolant() << "] ";
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " [" << expression->name() << "]";
     if (expression->is_delayed()) std::cerr << " [delayed]";
     if (expression->is_interpolant()) std::cerr << " [interpolant]";
+    if (expression->is_css()) std::cerr << " [css]";
     std::cerr << std::endl;
-    debug_ast(&expression->arguments(), ind + " args: ", env);
-  } else if (dynamic_cast<Arguments_Ptr>(node)) {
-    Arguments_Ptr expression = dynamic_cast<Arguments_Ptr>(node);
+    debug_ast(expression->arguments(), ind + " args: ", env);
+    debug_ast(expression->func(), ind + " func: ", env);
+  } else if (Cast<Function>(node)) {
+    Function_Ptr expression = Cast<Function>(node);
+    std::cerr << ind << "Function " << expression;
+    std::cerr << " (" << pstate_source_position(node) << ")";
+    if (expression->is_css()) std::cerr << " [css]";
+    std::cerr << std::endl;
+    debug_ast(expression->definition(), ind + " definition: ", env);
+  } else if (Cast<Arguments>(node)) {
+    Arguments_Ptr expression = Cast<Arguments>(node);
     std::cerr << ind << "Arguments " << expression;
     if (expression->is_delayed()) std::cerr << " [delayed]";
     std::cerr << " (" << pstate_source_position(node) << ")";
@@ -533,41 +533,41 @@
     if (expression->has_rest_argument()) std::cerr << " [has_rest_argument]";
     if (expression->has_keyword_argument()) std::cerr << " [has_keyword_argument]";
     std::cerr << std::endl;
-    for(const Argument_Obj& i : expression->elements()) { debug_ast(&i, ind + " ", env); }
-  } else if (dynamic_cast<Argument_Ptr>(node)) {
-    Argument_Ptr expression = dynamic_cast<Argument_Ptr>(node);
+    for(const Argument_Obj& i : expression->elements()) { debug_ast(i, ind + " ", env); }
+  } else if (Cast<Argument>(node)) {
+    Argument_Ptr expression = Cast<Argument>(node);
     std::cerr << ind << "Argument " << expression;
     std::cerr << " (" << pstate_source_position(node) << ")";
-    std::cerr << " [" << expression->value() << "]";
+    std::cerr << " [" << expression->value().ptr() << "]";
     std::cerr << " [name: " << expression->name() << "] ";
     std::cerr << " [rest: " << expression->is_rest_argument() << "] ";
     std::cerr << " [keyword: " << expression->is_keyword_argument() << "] " << std::endl;
-    debug_ast(&expression->value(), ind + " value: ", env);
-  } else if (dynamic_cast<Parameters_Ptr>(node)) {
-    Parameters_Ptr expression = dynamic_cast<Parameters_Ptr>(node);
+    debug_ast(expression->value(), ind + " value: ", env);
+  } else if (Cast<Parameters>(node)) {
+    Parameters_Ptr expression = Cast<Parameters>(node);
     std::cerr << ind << "Parameters " << expression;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " [has_optional: " << expression->has_optional_parameters() << "] ";
     std::cerr << " [has_rest: " << expression->has_rest_parameter() << "] ";
     std::cerr << std::endl;
-    for(const Parameter_Obj& i : expression->elements()) { debug_ast(&i, ind + " ", env); }
-  } else if (dynamic_cast<Parameter_Ptr>(node)) {
-    Parameter_Ptr expression = dynamic_cast<Parameter_Ptr>(node);
+    for(const Parameter_Obj& i : expression->elements()) { debug_ast(i, ind + " ", env); }
+  } else if (Cast<Parameter>(node)) {
+    Parameter_Ptr expression = Cast<Parameter>(node);
     std::cerr << ind << "Parameter " << expression;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " [name: " << expression->name() << "] ";
-    std::cerr << " [default: " << expression->default_value() << "] ";
+    std::cerr << " [default: " << expression->default_value().ptr() << "] ";
     std::cerr << " [rest: " << expression->is_rest_parameter() << "] " << std::endl;
-  } else if (dynamic_cast<Unary_Expression_Ptr>(node)) {
-    Unary_Expression_Ptr expression = dynamic_cast<Unary_Expression_Ptr>(node);
+  } else if (Cast<Unary_Expression>(node)) {
+    Unary_Expression_Ptr expression = Cast<Unary_Expression>(node);
     std::cerr << ind << "Unary_Expression " << expression;
     std::cerr << " [interpolant: " << expression->is_interpolant() << "] ";
     std::cerr << " [delayed: " << expression->is_delayed() << "] ";
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " [" << expression->type() << "]" << std::endl;
-    debug_ast(&expression->operand(), ind + " operand: ", env);
-  } else if (dynamic_cast<Binary_Expression_Ptr>(node)) {
-    Binary_Expression_Ptr expression = dynamic_cast<Binary_Expression_Ptr>(node);
+    debug_ast(expression->operand(), ind + " operand: ", env);
+  } else if (Cast<Binary_Expression>(node)) {
+    Binary_Expression_Ptr expression = Cast<Binary_Expression>(node);
     std::cerr << ind << "Binary_Expression " << expression;
     if (expression->is_interpolant()) std::cerr << " [is interpolant] ";
     if (expression->is_left_interpolant()) std::cerr << " [left interpolant] ";
@@ -577,67 +577,69 @@
     std::cerr << " [ws_after: " << expression->op().ws_after << "] ";
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " [" << expression->type_name() << "]" << std::endl;
-    debug_ast(&expression->left(), ind + " left:  ", env);
-    debug_ast(&expression->right(), ind + " right: ", env);
-  } else if (dynamic_cast<Map_Ptr>(node)) {
-    Map_Ptr expression = dynamic_cast<Map_Ptr>(node);
+    debug_ast(expression->left(), ind + " left:  ", env);
+    debug_ast(expression->right(), ind + " right: ", env);
+  } else if (Cast<Map>(node)) {
+    Map_Ptr expression = Cast<Map>(node);
     std::cerr << ind << "Map " << expression;
     std::cerr << " [interpolant: " << expression->is_interpolant() << "] ";
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " [Hashed]" << std::endl;
     for (const auto& i : expression->elements()) {
-      debug_ast(&i.first, ind + " key: ");
-      debug_ast(&i.second, ind + " val: ");
+      debug_ast(i.first, ind + " key: ");
+      debug_ast(i.second, ind + " val: ");
     }
-  } else if (dynamic_cast<List_Ptr>(node)) {
-    List_Ptr expression = dynamic_cast<List_Ptr>(node);
+  } else if (Cast<List>(node)) {
+    List_Ptr expression = Cast<List>(node);
     std::cerr << ind << "List " << expression;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " (" << expression->length() << ") " <<
-      (expression->separator() == SASS_COMMA ? "Comma " : expression->separator() == SASS_HASH ? "Map" : "Space ") <<
+      (expression->separator() == SASS_COMMA ? "Comma " : expression->separator() == SASS_HASH ? "Map " : "Space ") <<
       " [delayed: " << expression->is_delayed() << "] " <<
       " [interpolant: " << expression->is_interpolant() << "] " <<
       " [listized: " << expression->from_selector() << "] " <<
       " [arglist: " << expression->is_arglist() << "] " <<
+      " [bracketed: " << expression->is_bracketed() << "] " <<
+      " [expanded: " << expression->is_expanded() << "] " <<
       " [hash: " << expression->hash() << "] " <<
       std::endl;
-    for(const auto& i : expression->elements()) { debug_ast(&i, ind + " ", env); }
-  } else if (dynamic_cast<Content_Ptr>(node)) {
-    Content_Ptr expression = dynamic_cast<Content_Ptr>(node);
+    for(const auto& i : expression->elements()) { debug_ast(i, ind + " ", env); }
+  } else if (Cast<Content>(node)) {
+    Content_Ptr expression = Cast<Content>(node);
     std::cerr << ind << "Content " << expression;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " [@media:" << expression->media_block() << "]";
     std::cerr << " [Statement]" << std::endl;
-  } else if (dynamic_cast<Boolean_Ptr>(node)) {
-    Boolean_Ptr expression = dynamic_cast<Boolean_Ptr>(node);
+  } else if (Cast<Boolean>(node)) {
+    Boolean_Ptr expression = Cast<Boolean>(node);
     std::cerr << ind << "Boolean " << expression;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " [interpolant: " << expression->is_interpolant() << "] ";
     std::cerr << " [" << expression->value() << "]" << std::endl;
-  } else if (dynamic_cast<Color_Ptr>(node)) {
-    Color_Ptr expression = dynamic_cast<Color_Ptr>(node);
+  } else if (Cast<Color>(node)) {
+    Color_Ptr expression = Cast<Color>(node);
     std::cerr << ind << "Color " << expression;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " [delayed: " << expression->is_delayed() << "] ";
     std::cerr << " [interpolant: " << expression->is_interpolant() << "] ";
     std::cerr << " [" << expression->r() << ":"  << expression->g() << ":" << expression->b() << "@" << expression->a() << "]" << std::endl;
-  } else if (dynamic_cast<Number_Ptr>(node)) {
-    Number_Ptr expression = dynamic_cast<Number_Ptr>(node);
+  } else if (Cast<Number>(node)) {
+    Number_Ptr expression = Cast<Number>(node);
     std::cerr << ind << "Number " << expression;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " [interpolant: " << expression->is_interpolant() << "] ";
     std::cerr << " [" << expression->value() << expression->unit() << "]" <<
       " [hash: " << expression->hash() << "] " <<
       std::endl;
-  } else if (dynamic_cast<Null_Ptr>(node)) {
-    Null_Ptr expression = dynamic_cast<Null_Ptr>(node);
+  } else if (Cast<Null>(node)) {
+    Null_Ptr expression = Cast<Null>(node);
     std::cerr << ind << "Null " << expression;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " [interpolant: " << expression->is_interpolant() << "] "
       // " [hash: " << expression->hash() << "] "
       << std::endl;
-  } else if (dynamic_cast<String_Quoted_Ptr>(node)) {
-    String_Quoted_Ptr expression = dynamic_cast<String_Quoted_Ptr>(node);
+  } else if (Cast<String_Quoted>(node)) {
+    String_Quoted_Ptr expression = Cast<String_Quoted>(node);
     std::cerr << ind << "String_Quoted " << expression;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " [" << prettyprint(expression->value()) << "]";
@@ -645,8 +647,8 @@
     if (expression->is_interpolant()) std::cerr << " [interpolant]";
     if (expression->quote_mark()) std::cerr << " [quote_mark: " << expression->quote_mark() << "]";
     std::cerr << " <" << prettyprint(expression->pstate().token.ws_before()) << ">" << std::endl;
-  } else if (dynamic_cast<String_Constant_Ptr>(node)) {
-    String_Constant_Ptr expression = dynamic_cast<String_Constant_Ptr>(node);
+  } else if (Cast<String_Constant>(node)) {
+    String_Constant_Ptr expression = Cast<String_Constant>(node);
     std::cerr << ind << "String_Constant " << expression;
     if (expression->concrete_type()) {
       std::cerr << " " << expression->concrete_type();
@@ -656,28 +658,29 @@
     if (expression->is_delayed()) std::cerr << " [delayed]";
     if (expression->is_interpolant()) std::cerr << " [interpolant]";
     std::cerr << " <" << prettyprint(expression->pstate().token.ws_before()) << ">" << std::endl;
-  } else if (dynamic_cast<String_Schema_Ptr>(node)) {
-    String_Schema_Ptr expression = dynamic_cast<String_Schema_Ptr>(node);
+  } else if (Cast<String_Schema>(node)) {
+    String_Schema_Ptr expression = Cast<String_Schema>(node);
     std::cerr << ind << "String_Schema " << expression;
     std::cerr << " (" << pstate_source_position(expression) << ")";
     std::cerr << " " << expression->concrete_type();
     std::cerr << " (" << pstate_source_position(node) << ")";
+    if (expression->css()) std::cerr << " [css]";
     if (expression->is_delayed()) std::cerr << " [delayed]";
     if (expression->is_interpolant()) std::cerr << " [is interpolant]";
     if (expression->has_interpolant()) std::cerr << " [has interpolant]";
     if (expression->is_left_interpolant()) std::cerr << " [left interpolant] ";
     if (expression->is_right_interpolant()) std::cerr << " [right interpolant] ";
     std::cerr << " <" << prettyprint(expression->pstate().token.ws_before()) << ">" << std::endl;
-    for(const auto& i : expression->elements()) { debug_ast(&i, ind + " ", env); }
-  } else if (dynamic_cast<String_Ptr>(node)) {
-    String_Ptr expression = dynamic_cast<String_Ptr>(node);
+    for(const auto& i : expression->elements()) { debug_ast(i, ind + " ", env); }
+  } else if (Cast<String>(node)) {
+    String_Ptr expression = Cast<String>(node);
     std::cerr << ind << "String " << expression;
     std::cerr << " " << expression->concrete_type();
     std::cerr << " (" << pstate_source_position(node) << ")";
     if (expression->is_interpolant()) std::cerr << " [interpolant]";
     std::cerr << " <" << prettyprint(expression->pstate().token.ws_before()) << ">" << std::endl;
-  } else if (dynamic_cast<Expression_Ptr>(node)) {
-    Expression_Ptr expression = dynamic_cast<Expression_Ptr>(node);
+  } else if (Cast<Expression>(node)) {
+    Expression_Ptr expression = Cast<Expression>(node);
     std::cerr << ind << "Expression " << expression;
     std::cerr << " (" << pstate_source_position(node) << ")";
     switch (expression->concrete_type()) {
@@ -694,16 +697,18 @@
       case Expression::Concrete_Type::C_ERROR: std::cerr << " [C_ERROR]"; break;
       case Expression::Concrete_Type::FUNCTION: std::cerr << " [FUNCTION]"; break;
       case Expression::Concrete_Type::NUM_TYPES: std::cerr << " [NUM_TYPES]"; break;
+      case Expression::Concrete_Type::VARIABLE: std::cerr << " [VARIABLE]"; break;
+      case Expression::Concrete_Type::FUNCTION_VAL: std::cerr << " [FUNCTION_VAL]"; break;
     }
     std::cerr << std::endl;
-  } else if (dynamic_cast<Has_Block_Ptr>(node)) {
-    Has_Block_Ptr has_block = dynamic_cast<Has_Block_Ptr>(node);
+  } else if (Cast<Has_Block>(node)) {
+    Has_Block_Ptr has_block = Cast<Has_Block>(node);
     std::cerr << ind << "Has_Block " << has_block;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " " << has_block->tabs() << std::endl;
-    if (has_block->block()) for(const Statement_Obj& i : has_block->block()->elements()) { debug_ast(&i, ind + " ", env); }
-  } else if (dynamic_cast<Statement_Ptr>(node)) {
-    Statement_Ptr statement = dynamic_cast<Statement_Ptr>(node);
+    if (has_block->block()) for(const Statement_Obj& i : has_block->block()->elements()) { debug_ast(i, ind + " ", env); }
+  } else if (Cast<Statement>(node)) {
+    Statement_Ptr statement = Cast<Statement>(node);
     std::cerr << ind << "Statement " << statement;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " " << statement->tabs() << std::endl;
@@ -735,7 +740,7 @@
     std::cerr << node << " ";
     if (node->got_line_feed) std::cerr << "[LF] ";
     std::cerr << std::endl;
-    debug_ast(&node->selector(), ind + "  ");
+    debug_ast(node->selector(), ind + "  ");
   } else if (node->isCollection()) {
     std::cerr << ind;
     std::cerr << "Collection ";
@@ -776,21 +781,18 @@
 {
   if (ind == "") std::cerr << "#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
   for(auto const &it : map.values()) {
-    debug_ast(&it.first, ind + "first: ");
-    debug_ast(&it.second, ind + "second: ");
+    debug_ast(it.first, ind + "first: ");
+    debug_ast(it.second, ind + "second: ");
   }
   if (ind == "") std::cerr << "#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
 }
 
-typedef std::pair<Complex_Selector_Obj, Compound_Selector_Obj> ExtensionPair;
-typedef std::vector<ExtensionPair> SubsetMapEntries;
-
-inline void debug_subset_entries(SubsetMapEntries* entries, std::string ind = "")
+inline void debug_subset_entries(SubSetMapPairs* entries, std::string ind = "")
 {
   if (ind == "") std::cerr << "#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
   for(auto const &pair : *entries) {
-    debug_ast(&pair.first, ind + "first: ");
-    debug_ast(&pair.second, ind + "second: ");
+    debug_ast(pair.first, ind + "first: ");
+    debug_ast(pair.second, ind + "second: ");
   }
   if (ind == "") std::cerr << "#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
 }
diff --git a/libsass/src/emitter.cpp b/libsass/src/emitter.cpp
--- a/libsass/src/emitter.cpp
+++ b/libsass/src/emitter.cpp
@@ -14,7 +14,9 @@
     scheduled_space(0),
     scheduled_linefeed(0),
     scheduled_delimiter(false),
+    scheduled_crutch(0),
     scheduled_mapping(0),
+    in_custom_property(false),
     in_comment(false),
     in_wrapped(false),
     in_media_block(false),
@@ -101,10 +103,30 @@
   // prepend some text or token to the buffer
   void Emitter::prepend_string(const std::string& text)
   {
-    wbuf.smap.prepend(Offset(text));
+    // do not adjust mappings for utf8 bom
+    // seems they are not counted in any UA
+    if (text.compare("\xEF\xBB\xBF") != 0) {
+      wbuf.smap.prepend(Offset(text));
+    }
     wbuf.buffer = text + wbuf.buffer;
   }
 
+  char Emitter::last_char()
+  {
+    return wbuf.buffer.back();
+  }
+
+  // append a single char to the buffer
+  void Emitter::append_char(const char chr)
+  {
+    // write space/lf
+    flush_schedules();
+    // add to buffer
+    wbuf.buffer += chr;
+    // account for data in source-maps
+    wbuf.smap.append(Offset(chr));
+  }
+
   // append some text or token to the buffer
   void Emitter::append_string(const std::string& text)
   {
@@ -145,9 +167,9 @@
     add_open_mapping(node);
     // hotfix for browser issues
     // this is pretty ugly indeed
-    if (scheduled_mapping) {
-      add_open_mapping(scheduled_mapping);
-      scheduled_mapping = 0;
+    if (scheduled_crutch) {
+      add_open_mapping(scheduled_crutch);
+      scheduled_crutch = 0;
     }
     append_string(text);
     add_close_mapping(node);
@@ -193,7 +215,7 @@
   {
     scheduled_space = 0;
     append_string(":");
-    append_optional_space();
+    if (!in_custom_property) append_optional_space();
   }
 
   void Emitter::append_mandatory_space()
@@ -206,7 +228,9 @@
     if ((output_style() != COMPRESSED) && buffer().size()) {
       unsigned char lst = buffer().at(buffer().length() - 1);
       if (!isspace(lst) || scheduled_delimiter) {
-        append_mandatory_space();
+        if (last_char() != '(') {
+          append_mandatory_space();
+        }
       }
     }
   }
diff --git a/libsass/src/emitter.hpp b/libsass/src/emitter.hpp
--- a/libsass/src/emitter.hpp
+++ b/libsass/src/emitter.hpp
@@ -37,9 +37,12 @@
       size_t scheduled_space;
       size_t scheduled_linefeed;
       bool scheduled_delimiter;
+      AST_Node_Ptr scheduled_crutch;
       AST_Node_Ptr scheduled_mapping;
 
     public:
+      // output strings different in custom css properties
+      bool in_custom_property;
       // output strings different in comments
       bool in_comment;
       // selector list does not get linefeeds
@@ -66,11 +69,15 @@
       void prepend_output(const OutputBuffer& out);
       // append some text or token to the buffer
       void append_string(const std::string& text);
+      // append a single character to buffer
+      void append_char(const char chr);
       // append some white-space only text
       void append_wspace(const std::string& text);
       // append some text or token to the buffer
       // this adds source-mappings for node start and end
       void append_token(const std::string& text, const AST_Node_Ptr node);
+      // query last appended character
+      char last_char();
 
     public: // syntax sugar
       void append_indentation();
diff --git a/libsass/src/environment.cpp b/libsass/src/environment.cpp
--- a/libsass/src/environment.cpp
+++ b/libsass/src/environment.cpp
@@ -6,17 +6,17 @@
 
   template <typename T>
   Environment<T>::Environment(bool is_shadow)
-  : local_frame_(std::map<std::string, T>()),
+  : local_frame_(environment_map<std::string, T>()),
     parent_(0), is_shadow_(false)
   { }
   template <typename T>
   Environment<T>::Environment(Environment<T>* env, bool is_shadow)
-  : local_frame_(std::map<std::string, T>()),
+  : local_frame_(environment_map<std::string, T>()),
     parent_(env), is_shadow_(is_shadow)
   { }
   template <typename T>
   Environment<T>::Environment(Environment<T>& env, bool is_shadow)
-  : local_frame_(std::map<std::string, T>()),
+  : local_frame_(environment_map<std::string, T>()),
     parent_(&env), is_shadow_(is_shadow)
   { }
 
@@ -45,7 +45,7 @@
   }
 
   template <typename T>
-  std::map<std::string, T>& Environment<T>::local_frame() {
+  environment_map<std::string, T>& Environment<T>::local_frame() {
     return local_frame_;
   }
 
@@ -53,15 +53,28 @@
   bool Environment<T>::has_local(const std::string& key) const
   { return local_frame_.find(key) != local_frame_.end(); }
 
+  template <typename T> EnvResult
+  Environment<T>::find_local(const std::string& key)
+  {
+    auto end = local_frame_.end();
+    auto it = local_frame_.find(key);
+    return EnvResult(it, it != end);
+  }
+
   template <typename T>
   T& Environment<T>::get_local(const std::string& key)
   { return local_frame_[key]; }
 
   template <typename T>
-  void Environment<T>::set_local(const std::string& key, T val)
+  void Environment<T>::set_local(const std::string& key, const T& val)
   {
     local_frame_[key] = val;
   }
+  template <typename T>
+  void Environment<T>::set_local(const std::string& key, T&& val)
+  {
+    local_frame_[key] = val;
+  }
 
   template <typename T>
   void Environment<T>::del_local(const std::string& key)
@@ -86,10 +99,15 @@
   { return (*global_env())[key]; }
 
   template <typename T>
-  void Environment<T>::set_global(const std::string& key, T val)
+  void Environment<T>::set_global(const std::string& key, const T& val)
   {
     global_env()->local_frame_[key] = val;
   }
+  template <typename T>
+  void Environment<T>::set_global(const std::string& key, T&& val)
+  {
+    global_env()->local_frame_[key] = val;
+  }
 
   template <typename T>
   void Environment<T>::del_global(const std::string& key)
@@ -126,12 +144,14 @@
   // either update already existing lexical value
   // or if flag is set, we create one if no lexical found
   template <typename T>
-  void Environment<T>::set_lexical(const std::string& key, T val)
+  void Environment<T>::set_lexical(const std::string& key, const T& val)
   {
-    auto cur = this; bool shadow = false;
-    while (cur->is_lexical() || shadow) {
-      if (cur->has_local(key)) {
-        cur->set_local(key, val);
+    Environment<T>* cur = this;
+    bool shadow = false;
+    while ((cur && cur->is_lexical()) || shadow) {
+      EnvResult rv(cur->find_local(key));
+      if (rv.found) {
+        rv.it->second = val;
         return;
       }
       shadow = cur->is_shadow();
@@ -139,6 +159,23 @@
     }
     set_local(key, val);
   }
+  // this one moves the value
+  template <typename T>
+  void Environment<T>::set_lexical(const std::string& key, T&& val)
+  {
+    Environment<T>* cur = this;
+    bool shadow = false;
+    while ((cur && cur->is_lexical()) || shadow) {
+      EnvResult rv(cur->find_local(key));
+      if (rv.found) {
+        rv.it->second = val;
+        return;
+      }
+      shadow = cur->is_shadow();
+      cur = cur->parent_;
+    }
+    set_local(key, val);
+  }
 
   // look on the full stack for key
   // include all scopes available
@@ -155,6 +192,20 @@
     return false;
   }
 
+  // look on the full stack for key
+  // include all scopes available
+  template <typename T> EnvResult
+  Environment<T>::find(const std::string& key)
+  {
+    auto cur = this;
+    while (true) {
+      EnvResult rv(cur->find_local(key));
+      if (rv.found) return rv;
+      cur = cur->parent_;
+      if (!cur) return rv;
+    }
+  };
+
   // use array access for getter and setter functions
   template <typename T>
   T& Environment<T>::operator[](const std::string& key)
@@ -168,7 +219,7 @@
     }
     return get_local(key);
   }
-
+/*
   #ifdef DEBUG
   template <typename T>
   size_t Environment<T>::print(std::string prefix)
@@ -176,10 +227,10 @@
     size_t indent = 0;
     if (parent_) indent = parent_->print(prefix) + 1;
     std::cerr << prefix << std::string(indent, ' ') << "== " << this << std::endl;
-    for (typename std::map<std::string, T>::iterator i = local_frame_.begin(); i != local_frame_.end(); ++i) {
+    for (typename environment_map<std::string, T>::iterator i = local_frame_.begin(); i != local_frame_.end(); ++i) {
       if (!ends_with(i->first, "[f]") && !ends_with(i->first, "[f]4") && !ends_with(i->first, "[f]2")) {
-        std::cerr << prefix << std::string(indent, ' ') << i->first << " "  << i->second;
-        if (Value_Ptr val = SASS_MEMORY_CAST_PTR(Value, i->second))
+        std::cerr << prefix << std::string(indent, ' ') << i->first << " " << i->second;
+        if (Value_Ptr val = Cast<Value>(i->second))
         { std::cerr << " : " << val->to_string(); }
         std::cerr << std::endl;
       }
@@ -187,7 +238,7 @@
     return indent ;
   }
   #endif
-
+*/
   // compile implementation for AST_Node
   template class Environment<AST_Node_Obj>;
 
diff --git a/libsass/src/environment.hpp b/libsass/src/environment.hpp
--- a/libsass/src/environment.hpp
+++ b/libsass/src/environment.hpp
@@ -2,17 +2,26 @@
 #define SASS_ENVIRONMENT_H
 
 #include <string>
-#include <map>
-
 #include "ast_fwd_decl.hpp"
 #include "ast_def_macros.hpp"
 
 namespace Sass {
 
+  typedef environment_map<std::string, AST_Node_Obj>::iterator EnvIter;
+
+  class EnvResult {
+    public:
+      EnvIter it;
+      bool found;
+    public:
+      EnvResult(EnvIter it, bool found)
+      : it(it), found(found) {}
+  };
+
   template <typename T>
   class Environment {
     // TODO: test with map
-    std::map<std::string, T> local_frame_;
+    environment_map<std::string, T> local_frame_;
     ADD_PROPERTY(Environment*, parent)
     ADD_PROPERTY(bool, is_shadow)
 
@@ -37,14 +46,17 @@
 
     // scope operates on the current frame
 
-    std::map<std::string, T>& local_frame();
+    environment_map<std::string, T>& local_frame();
 
     bool has_local(const std::string& key) const;
 
+    EnvResult find_local(const std::string& key);
+
     T& get_local(const std::string& key);
 
     // set variable on the current frame
-    void set_local(const std::string& key, T val);
+    void set_local(const std::string& key, const T& val);
+    void set_local(const std::string& key, T&& val);
 
     void del_local(const std::string& key);
 
@@ -60,7 +72,8 @@
     T& get_global(const std::string& key);
 
     // set a variable on the global frame
-    void set_global(const std::string& key, T val);
+    void set_global(const std::string& key, const T& val);
+    void set_global(const std::string& key, T&& val);
 
     void del_global(const std::string& key);
 
@@ -72,12 +85,17 @@
     // see if we have a lexical we could update
     // either update already existing lexical value
     // or we create a new one on the current frame
-    void set_lexical(const std::string& key, T val);
+    void set_lexical(const std::string& key, T&& val);
+    void set_lexical(const std::string& key, const T& val);
 
     // look on the full stack for key
     // include all scopes available
     bool has(const std::string& key) const;
 
+    // look on the full stack for key
+    // include all scopes available
+    EnvResult find(const std::string& key);
+
     // use array access for getter and setter functions
     T& operator[](const std::string& key);
 
@@ -86,6 +104,9 @@
     #endif
 
   };
+
+  // define typedef for our use case
+  typedef Environment<AST_Node_Obj> Env;
 
 }
 
diff --git a/libsass/src/error_handling.cpp b/libsass/src/error_handling.cpp
--- a/libsass/src/error_handling.cpp
+++ b/libsass/src/error_handling.cpp
@@ -10,19 +10,18 @@
 
   namespace Exception {
 
-    Base::Base(ParserState pstate, std::string msg, std::vector<Sass_Import_Entry>* import_stack)
+    Base::Base(ParserState pstate, std::string msg, Backtraces traces)
     : std::runtime_error(msg), msg(msg),
-      prefix("Error"), pstate(pstate),
-      import_stack(import_stack)
+      prefix("Error"), pstate(pstate), traces(traces)
     { }
 
-    InvalidSass::InvalidSass(ParserState pstate, std::string msg)
-    : Base(pstate, msg)
+    InvalidSass::InvalidSass(ParserState pstate, Backtraces traces, std::string msg)
+    : Base(pstate, msg, traces)
     { }
 
 
-    InvalidParent::InvalidParent(Selector_Ptr parent, Selector_Ptr selector)
-    : Base(selector->pstate()), parent(parent), selector(selector)
+    InvalidParent::InvalidParent(Selector_Ptr parent, Backtraces traces, Selector_Ptr selector)
+    : Base(selector->pstate(), def_msg, traces), parent(parent), selector(selector)
     {
       msg = "Invalid parent selector for \"";
       msg += selector->to_string(Sass_Inspect_Options());
@@ -31,55 +30,40 @@
       msg += "\"";
     }
 
-    InvalidArgumentType::InvalidArgumentType(ParserState pstate, std::string fn, std::string arg, std::string type, const Value_Ptr value)
-    : Base(pstate), fn(fn), arg(arg), type(type), value(value)
+    InvalidVarKwdType::InvalidVarKwdType(ParserState pstate, Backtraces traces, std::string name, const Argument_Ptr arg)
+    : Base(pstate, def_msg, traces), name(name), arg(arg)
     {
+      msg = "Variable keyword argument map must have string keys.\n";
+      msg += name + " is not a string in " + arg->to_string() + ".";
+    }
+
+    InvalidArgumentType::InvalidArgumentType(ParserState pstate, Backtraces traces, std::string fn, std::string arg, std::string type, const Value_Ptr value)
+    : Base(pstate, def_msg, traces), fn(fn), arg(arg), type(type), value(value)
+    {
       msg  = arg + ": \"";
       if (value) msg += value->to_string(Sass_Inspect_Options());
       msg += "\" is not a " + type;
       msg += " for `" + fn + "'";
     }
 
-    MissingArgument::MissingArgument(ParserState pstate, std::string fn, std::string arg, std::string fntype)
-    : Base(pstate), fn(fn), arg(arg), fntype(fntype)
+    MissingArgument::MissingArgument(ParserState pstate, Backtraces traces, std::string fn, std::string arg, std::string fntype)
+    : Base(pstate, def_msg, traces), fn(fn), arg(arg), fntype(fntype)
     {
       msg  = fntype + " " + fn;
       msg += " is missing argument ";
       msg += arg + ".";
     }
 
-    InvalidSyntax::InvalidSyntax(ParserState pstate, std::string msg, std::vector<Sass_Import_Entry>* import_stack)
-    : Base(pstate, msg, import_stack)
+    InvalidSyntax::InvalidSyntax(ParserState pstate, Backtraces traces, std::string msg)
+    : Base(pstate, msg, traces)
     { }
 
-    UndefinedOperation::UndefinedOperation(Expression_Ptr_Const lhs, Expression_Ptr_Const rhs, const std::string& op)
-    : lhs(lhs), rhs(rhs), op(op)
-    {
-      msg  = def_op_msg + ": \"";
-      msg += lhs->to_string({ NESTED, 5 });
-      msg += " " + op + " ";
-      msg += rhs->to_string({ TO_SASS, 5 });
-      msg += "\".";
-    }
-
-    InvalidNullOperation::InvalidNullOperation(Expression_Ptr_Const lhs, Expression_Ptr_Const rhs, const std::string& op)
-    : UndefinedOperation(lhs, rhs, op)
-    {
-      msg  = def_op_null_msg + ": \"";
-      msg += lhs->inspect();
-      msg += " " + op + " ";
-      msg += rhs->inspect();
-      msg += "\".";
-    }
-
-    ZeroDivisionError::ZeroDivisionError(const Expression& lhs, const Expression& rhs)
-    : lhs(lhs), rhs(rhs)
-    {
-      msg  = "divided by 0";
-    }
+    NestingLimitError::NestingLimitError(ParserState pstate, Backtraces traces, std::string msg)
+    : Base(pstate, msg, traces)
+    { }
 
-    DuplicateKeyError::DuplicateKeyError(const Map& dup, const Expression& org)
-    : Base(org.pstate()), dup(dup), org(org)
+    DuplicateKeyError::DuplicateKeyError(Backtraces traces, const Map& dup, const Expression& org)
+    : Base(org.pstate(), def_msg, traces), dup(dup), org(org)
     {
       msg  = "Duplicate key ";
       msg += dup.get_duplicate_key()->inspect();
@@ -88,8 +72,8 @@
       msg += ").";
     }
 
-    TypeMismatch::TypeMismatch(const Expression& var, const std::string type)
-    : Base(var.pstate()), var(var), type(type)
+    TypeMismatch::TypeMismatch(Backtraces traces, const Expression& var, const std::string type)
+    : Base(var.pstate(), def_msg, traces), var(var), type(type)
     {
       msg  = var.to_string();
       msg += " is not an ";
@@ -97,21 +81,20 @@
       msg += ".";
     }
 
-    InvalidValue::InvalidValue(const Expression& val)
-    : Base(val.pstate()), val(val)
+    InvalidValue::InvalidValue(Backtraces traces, const Expression& val)
+    : Base(val.pstate(), def_msg, traces), val(val)
     {
       msg  = val.to_string();
       msg += " isn't a valid CSS value.";
     }
 
-    StackError::StackError(const AST_Node& node)
-    : Base(node.pstate()), node(node)
+    StackError::StackError(Backtraces traces, const AST_Node& node)
+    : Base(node.pstate(), def_msg, traces), node(node)
     {
       msg  = "stack level too deep";
     }
 
-    IncompatibleUnits::IncompatibleUnits(const Number& lhs, const Number& rhs)
-    : lhs(lhs), rhs(rhs)
+    IncompatibleUnits::IncompatibleUnits(const Units& lhs, const Units& rhs)
     {
       msg  = "Incompatible units: '";
       msg += rhs.unit();
@@ -120,20 +103,54 @@
       msg += "'.";
     }
 
-    AlphaChannelsNotEqual::AlphaChannelsNotEqual(Expression_Ptr_Const lhs, Expression_Ptr_Const rhs, const std::string& op)
-    : lhs(lhs), rhs(rhs), op(op)
+    IncompatibleUnits::IncompatibleUnits(const UnitType lhs, const UnitType rhs)
     {
+      msg  = "Incompatible units: '";
+      msg += unit_to_string(rhs);
+      msg += "' and '";
+      msg += unit_to_string(lhs);
+      msg += "'.";
+    }
+
+    AlphaChannelsNotEqual::AlphaChannelsNotEqual(Expression_Ptr_Const lhs, Expression_Ptr_Const rhs, enum Sass_OP op)
+    : OperationError(), lhs(lhs), rhs(rhs), op(op)
+    {
       msg  = "Alpha channels must be equal: ";
       msg += lhs->to_string({ NESTED, 5 });
-      msg += " " + op + " ";
+      msg += " " + sass_op_to_name(op) + " ";
       msg += rhs->to_string({ NESTED, 5 });
       msg += ".";
     }
 
+    ZeroDivisionError::ZeroDivisionError(const Expression& lhs, const Expression& rhs)
+    : OperationError(), lhs(lhs), rhs(rhs)
+    {
+      msg  = "divided by 0";
+    }
 
-    SassValueError::SassValueError(ParserState pstate, OperationError& err)
-    : Base(pstate, err.what())
+    UndefinedOperation::UndefinedOperation(Expression_Ptr_Const lhs, Expression_Ptr_Const rhs, enum Sass_OP op)
+    : OperationError(), lhs(lhs), rhs(rhs), op(op)
     {
+      msg  = def_op_msg + ": \"";
+      msg += lhs->to_string({ NESTED, 5 });
+      msg += " " + sass_op_to_name(op) + " ";
+      msg += rhs->to_string({ TO_SASS, 5 });
+      msg += "\".";
+    }
+
+    InvalidNullOperation::InvalidNullOperation(Expression_Ptr_Const lhs, Expression_Ptr_Const rhs, enum Sass_OP op)
+    : UndefinedOperation(lhs, rhs, op)
+    {
+      msg  = def_op_null_msg + ": \"";
+      msg += lhs->inspect();
+      msg += " " + sass_op_to_name(op) + " ";
+      msg += rhs->inspect();
+      msg += "\".";
+    }
+
+    SassValueError::SassValueError(Backtraces traces, ParserState pstate, OperationError& err)
+    : Base(pstate, err.what(), traces)
+    {
       msg = err.what();
       prefix = err.errtype();
     }
@@ -143,13 +160,22 @@
 
   void warn(std::string msg, ParserState pstate)
   {
-    std::cerr << "Warning: " << msg<< std::endl;
+    std::cerr << "Warning: " << msg << std::endl;
   }
 
+  void warning(std::string msg, ParserState pstate)
+  {
+    std::string cwd(Sass::File::get_cwd());
+    std::string abs_path(Sass::File::rel2abs(pstate.path, cwd, cwd));
+    std::string rel_path(Sass::File::abs2rel(pstate.path, cwd, cwd));
+    std::string output_path(Sass::File::path_for_console(rel_path, abs_path, pstate.path));
+
+    std::cerr << "WARNING on line " << pstate.line+1 << ", column " << pstate.column+1 << " of " << output_path << ":" << std::endl;
+    std::cerr << msg << std::endl << std::endl;
+  }
+
   void warn(std::string msg, ParserState pstate, Backtrace* bt)
   {
-    Backtrace top(bt, pstate, "");
-    msg += top.to_string();
     warn(msg, pstate);
   }
 
@@ -165,7 +191,7 @@
     std::cerr << "        on line " << pstate.line+1 << " of " << output_path << std::endl;
   }
 
-  void deprecated(std::string msg, std::string msg2, ParserState pstate)
+  void deprecated(std::string msg, std::string msg2, bool with_column, ParserState pstate)
   {
     std::string cwd(Sass::File::get_cwd());
     std::string abs_path(Sass::File::rel2abs(pstate.path, cwd, cwd));
@@ -173,9 +199,10 @@
     std::string output_path(Sass::File::path_for_console(rel_path, pstate.path, pstate.path));
 
     std::cerr << "DEPRECATION WARNING on line " << pstate.line + 1;
+    if (with_column) std::cerr << ", column " << pstate.column + pstate.offset.column + 1;
     if (output_path.length()) std::cerr << " of " << output_path;
     std::cerr << ":" << std::endl;
-    std::cerr << msg << " and will be an error in future versions of Sass." << std::endl;
+    std::cerr << msg << std::endl;
     if (msg2.length()) std::cerr << msg2 << std::endl;
     std::cerr << std::endl;
   }
@@ -192,16 +219,17 @@
     std::cerr << "This will be an error in future versions of Sass." << std::endl;
   }
 
-  void error(std::string msg, ParserState pstate)
+  // should be replaced with error with backtraces
+  void coreError(std::string msg, ParserState pstate)
   {
-    throw Exception::InvalidSyntax(pstate, msg);
+    Backtraces traces;
+    throw Exception::InvalidSyntax(pstate, traces, msg);
   }
 
-  void error(std::string msg, ParserState pstate, Backtrace* bt)
+  void error(std::string msg, ParserState pstate, Backtraces& traces)
   {
-    Backtrace top(bt, pstate, "");
-    msg += "\n" + top.to_string();
-    error(msg, pstate);
+    traces.push_back(Backtrace(pstate));
+    throw Exception::InvalidSyntax(pstate, traces, msg);
   }
 
 }
diff --git a/libsass/src/error_handling.hpp b/libsass/src/error_handling.hpp
--- a/libsass/src/error_handling.hpp
+++ b/libsass/src/error_handling.hpp
@@ -5,6 +5,9 @@
 #include <sstream>
 #include <stdexcept>
 #include "position.hpp"
+#include "backtrace.hpp"
+#include "ast_fwd_decl.hpp"
+#include "sass/functions.h"
 
 namespace Sass {
 
@@ -15,6 +18,7 @@
     const std::string def_msg = "Invalid sass detected";
     const std::string def_op_msg = "Undefined operation";
     const std::string def_op_null_msg = "Invalid null operation";
+    const std::string def_nesting_limit = "Code too deeply neested";
 
     class Base : public std::runtime_error {
       protected:
@@ -22,9 +26,9 @@
         std::string prefix;
       public:
         ParserState pstate;
-        std::vector<Sass_Import_Entry>* import_stack;
+        Backtraces traces;
       public:
-        Base(ParserState pstate, std::string msg = def_msg, std::vector<Sass_Import_Entry>* import_stack = 0);
+        Base(ParserState pstate, std::string msg, Backtraces traces);
         virtual const char* errtype() const { return prefix.c_str(); }
         virtual const char* what() const throw() { return msg.c_str(); }
         virtual ~Base() throw() {};
@@ -32,7 +36,7 @@
 
     class InvalidSass : public Base {
       public:
-        InvalidSass(ParserState pstate, std::string msg);
+        InvalidSass(ParserState pstate, Backtraces traces, std::string msg);
         virtual ~InvalidSass() throw() {};
     };
 
@@ -41,7 +45,7 @@
         Selector_Ptr parent;
         Selector_Ptr selector;
       public:
-        InvalidParent(Selector_Ptr parent, Selector_Ptr selector);
+        InvalidParent(Selector_Ptr parent, Backtraces traces, Selector_Ptr selector);
         virtual ~InvalidParent() throw() {};
     };
 
@@ -51,7 +55,7 @@
         std::string arg;
         std::string fntype;
       public:
-        MissingArgument(ParserState pstate, std::string fn, std::string arg, std::string fntype);
+        MissingArgument(ParserState pstate, Backtraces traces, std::string fn, std::string arg, std::string fntype);
         virtual ~MissingArgument() throw() {};
     };
 
@@ -62,38 +66,29 @@
         std::string type;
         const Value_Ptr value;
       public:
-        InvalidArgumentType(ParserState pstate, std::string fn, std::string arg, std::string type, const Value_Ptr value = 0);
+        InvalidArgumentType(ParserState pstate, Backtraces traces, std::string fn, std::string arg, std::string type, const Value_Ptr value = 0);
         virtual ~InvalidArgumentType() throw() {};
     };
 
-    class InvalidSyntax : public Base {
+    class InvalidVarKwdType : public Base {
+      protected:
+        std::string name;
+        const Argument_Ptr arg;
       public:
-        InvalidSyntax(ParserState pstate, std::string msg, std::vector<Sass_Import_Entry>* import_stack = 0);
-        virtual ~InvalidSyntax() throw() {};
+        InvalidVarKwdType(ParserState pstate, Backtraces traces, std::string name, const Argument_Ptr arg = 0);
+        virtual ~InvalidVarKwdType() throw() {};
     };
 
-    /* common virtual base class (has no pstate) */
-    class OperationError : public std::runtime_error {
-      protected:
-        std::string msg;
-      public:
-        OperationError(std::string msg = def_op_msg)
-        : std::runtime_error(msg), msg(msg)
-        {};
+    class InvalidSyntax : public Base {
       public:
-        virtual const char* errtype() const { return "Error"; }
-        virtual const char* what() const throw() { return msg.c_str(); }
-        virtual ~OperationError() throw() {};
+        InvalidSyntax(ParserState pstate, Backtraces traces, std::string msg);
+        virtual ~InvalidSyntax() throw() {};
     };
 
-    class ZeroDivisionError : public OperationError {
-      protected:
-        const Expression& lhs;
-        const Expression& rhs;
+    class NestingLimitError : public Base {
       public:
-        ZeroDivisionError(const Expression& lhs, const Expression& rhs);
-        virtual const char* errtype() const { return "ZeroDivisionError"; }
-        virtual ~ZeroDivisionError() throw() {};
+        NestingLimitError(ParserState pstate, Backtraces traces, std::string msg = def_nesting_limit);
+        virtual ~NestingLimitError() throw() {};
     };
 
     class DuplicateKeyError : public Base {
@@ -101,7 +96,7 @@
         const Map& dup;
         const Expression& org;
       public:
-        DuplicateKeyError(const Map& dup, const Expression& org);
+        DuplicateKeyError(Backtraces traces, const Map& dup, const Expression& org);
         virtual const char* errtype() const { return "Error"; }
         virtual ~DuplicateKeyError() throw() {};
     };
@@ -111,7 +106,7 @@
         const Expression& var;
         const std::string type;
       public:
-        TypeMismatch(const Expression& var, const std::string type);
+        TypeMismatch(Backtraces traces, const Expression& var, const std::string type);
         virtual const char* errtype() const { return "Error"; }
         virtual ~TypeMismatch() throw() {};
     };
@@ -120,7 +115,7 @@
       protected:
         const Expression& val;
       public:
-        InvalidValue(const Expression& val);
+        InvalidValue(Backtraces traces, const Expression& val);
         virtual const char* errtype() const { return "Error"; }
         virtual ~InvalidValue() throw() {};
     };
@@ -129,17 +124,42 @@
       protected:
         const AST_Node& node;
       public:
-        StackError(const AST_Node& node);
+        StackError(Backtraces traces, const AST_Node& node);
         virtual const char* errtype() const { return "SystemStackError"; }
         virtual ~StackError() throw() {};
     };
 
+    /* common virtual base class (has no pstate or trace) */
+    class OperationError : public std::runtime_error {
+      protected:
+        std::string msg;
+      public:
+        OperationError(std::string msg = def_op_msg)
+        : std::runtime_error(msg), msg(msg)
+        {};
+      public:
+        virtual const char* errtype() const { return "Error"; }
+        virtual const char* what() const throw() { return msg.c_str(); }
+        virtual ~OperationError() throw() {};
+    };
+
+    class ZeroDivisionError : public OperationError {
+      protected:
+        const Expression& lhs;
+        const Expression& rhs;
+      public:
+        ZeroDivisionError(const Expression& lhs, const Expression& rhs);
+        virtual const char* errtype() const { return "ZeroDivisionError"; }
+        virtual ~ZeroDivisionError() throw() {};
+    };
+
     class IncompatibleUnits : public OperationError {
       protected:
-        const Number& lhs;
-        const Number& rhs;
+        // const Sass::UnitType lhs;
+        // const Sass::UnitType rhs;
       public:
-        IncompatibleUnits(const Number& lhs, const Number& rhs);
+        IncompatibleUnits(const Units& lhs, const Units& rhs);
+        IncompatibleUnits(const UnitType lhs, const UnitType rhs);
         virtual ~IncompatibleUnits() throw() {};
     };
 
@@ -147,16 +167,16 @@
       protected:
         Expression_Ptr_Const lhs;
         Expression_Ptr_Const rhs;
-        const std::string op;
+        const Sass_OP op;
       public:
-        UndefinedOperation(Expression_Ptr_Const lhs, Expression_Ptr_Const rhs, const std::string& op);
+        UndefinedOperation(Expression_Ptr_Const lhs, Expression_Ptr_Const rhs, enum Sass_OP op);
         // virtual const char* errtype() const { return "Error"; }
         virtual ~UndefinedOperation() throw() {};
     };
 
     class InvalidNullOperation : public UndefinedOperation {
       public:
-        InvalidNullOperation(Expression_Ptr_Const lhs, Expression_Ptr_Const rhs, const std::string& op);
+        InvalidNullOperation(Expression_Ptr_Const lhs, Expression_Ptr_Const rhs, enum Sass_OP op);
         virtual ~InvalidNullOperation() throw() {};
     };
 
@@ -164,16 +184,16 @@
       protected:
         Expression_Ptr_Const lhs;
         Expression_Ptr_Const rhs;
-        const std::string op;
+        const Sass_OP op;
       public:
-        AlphaChannelsNotEqual(Expression_Ptr_Const lhs, Expression_Ptr_Const rhs, const std::string& op);
+        AlphaChannelsNotEqual(Expression_Ptr_Const lhs, Expression_Ptr_Const rhs, enum Sass_OP op);
         // virtual const char* errtype() const { return "Error"; }
         virtual ~AlphaChannelsNotEqual() throw() {};
     };
 
     class SassValueError : public Base {
       public:
-        SassValueError(ParserState pstate, OperationError& err);
+        SassValueError(Backtraces traces, ParserState pstate, OperationError& err);
         virtual ~SassValueError() throw() {};
     };
 
@@ -181,14 +201,15 @@
 
   void warn(std::string msg, ParserState pstate);
   void warn(std::string msg, ParserState pstate, Backtrace* bt);
+  void warning(std::string msg, ParserState pstate);
 
   void deprecated_function(std::string msg, ParserState pstate);
-  void deprecated(std::string msg, std::string msg2, ParserState pstate);
+  void deprecated(std::string msg, std::string msg2, bool with_column, ParserState pstate);
   void deprecated_bind(std::string msg, ParserState pstate);
   // void deprecated(std::string msg, ParserState pstate, Backtrace* bt);
 
-  void error(std::string msg, ParserState pstate);
-  void error(std::string msg, ParserState pstate, Backtrace* bt);
+  void coreError(std::string msg, ParserState pstate);
+  void error(std::string msg, ParserState pstate, Backtraces& traces);
 
 }
 
diff --git a/libsass/src/eval.cpp b/libsass/src/eval.cpp
--- a/libsass/src/eval.cpp
+++ b/libsass/src/eval.cpp
@@ -12,1702 +12,1667 @@
 #include "bind.hpp"
 #include "util.hpp"
 #include "inspect.hpp"
-#include "environment.hpp"
-#include "position.hpp"
-#include "sass/values.h"
-#include "to_value.hpp"
-#include "to_c.hpp"
-#include "context.hpp"
-#include "backtrace.hpp"
-#include "lexer.hpp"
-#include "prelexer.hpp"
-#include "parser.hpp"
-#include "expand.hpp"
-#include "color_maps.hpp"
-
-namespace Sass {
-
-  inline double add(double x, double y) { return x + y; }
-  inline double sub(double x, double y) { return x - y; }
-  inline double mul(double x, double y) { return x * y; }
-  inline double div(double x, double y) { return x / y; } // x/0 checked by caller
-  inline double mod(double x, double y) { // x/0 checked by caller
-    if ((x > 0 && y < 0) || (x < 0 && y > 0)) {
-      double ret = std::fmod(x, y);
-      return ret ? ret + y : ret;
-    } else {
-      return std::fmod(x, y);
-    }
-  }
-  typedef double (*bop)(double, double);
-  bop ops[Sass_OP::NUM_OPS] = {
-    0, 0, // and, or
-    0, 0, 0, 0, 0, 0, // eq, neq, gt, gte, lt, lte
-    add, sub, mul, div, mod
-  };
-
-  Eval::Eval(Expand& exp)
-  : exp(exp),
-    ctx(exp.ctx),
-    force(false),
-    is_in_comment(false)
-  { }
-  Eval::~Eval() { }
-
-  Env* Eval::environment()
-  {
-    return exp.environment();
-  }
-
-  Selector_List_Obj Eval::selector()
-  {
-    return exp.selector();
-  }
-
-  Backtrace* Eval::backtrace()
-  {
-    return exp.backtrace();
-  }
-
-  Expression_Ptr Eval::operator()(Block_Ptr b)
-  {
-    Expression_Ptr val = 0;
-    for (size_t i = 0, L = b->length(); i < L; ++i) {
-      val = b->at(i)->perform(this);
-      if (val) return val;
-    }
-    return val;
-  }
-
-  Expression_Ptr Eval::operator()(Assignment_Ptr a)
-  {
-    Env* env = exp.environment();
-    std::string var(a->variable());
-    if (a->is_global()) {
-      if (a->is_default()) {
-        if (env->has_global(var)) {
-          Expression_Ptr e = SASS_MEMORY_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 {
-        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_Obj node = cur->get_local(var)) {
-              Expression_Ptr e = SASS_MEMORY_CAST(Expression, node);
-              if (!e || e->concrete_type() == Expression::NULL_VAL) {
-                cur->set_local(var, a->value()->perform(this));
-              }
-            }
-            else {
-              throw std::runtime_error("Env not in sync");
-            }
-            return 0;
-          }
-          cur = cur->parent();
-        }
-        throw std::runtime_error("Env not in sync");
-      }
-      else if (env->has_global(var)) {
-        if (AST_Node_Obj node = env->get_global(var)) {
-          Expression_Ptr e = SASS_MEMORY_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));
-    }
-    return 0;
-  }
-
-  Expression_Ptr Eval::operator()(If_Ptr i)
-  {
-    Expression_Obj rv = 0;
-    Env env(exp.environment());
-    exp.env_stack.push_back(&env);
-    Expression_Obj cond = i->predicate()->perform(this);
-    if (!cond->is_false()) {
-      rv = i->block()->perform(this);
-    }
-    else {
-      Block_Obj alt = i->alternative();
-      if (alt) rv = alt->perform(this);
-    }
-    exp.env_stack.pop_back();
-    return rv.detach();
-  }
-
-  // For does not create a new env scope
-  // But iteration vars are reset afterwards
-  Expression_Ptr Eval::operator()(For_Ptr f)
-  {
-    std::string variable(f->variable());
-    Expression_Obj low = f->lower_bound()->perform(this);
-    if (low->concrete_type() != Expression::NUMBER) {
-      throw Exception::TypeMismatch(*low, "integer");
-    }
-    Expression_Obj high = f->upper_bound()->perform(this);
-    if (high->concrete_type() != Expression::NUMBER) {
-      throw Exception::TypeMismatch(*high, "integer");
-    }
-    Number_Obj sass_start = SASS_MEMORY_CAST(Number, low);
-    Number_Obj sass_end = SASS_MEMORY_CAST(Number, high);
-    // check if units are valid for sequence
-    if (sass_start->unit() != sass_end->unit()) {
-      std::stringstream msg; msg << "Incompatible units: '"
-        << sass_end->unit() << "' and '"
-        << sass_start->unit() << "'.";
-      error(msg.str(), low->pstate(), backtrace());
-    }
-    double start = sass_start->value();
-    double end = sass_end->value();
-    // only create iterator once in this environment
-    Env env(environment(), true);
-    exp.env_stack.push_back(&env);
-    Number_Ptr it = SASS_MEMORY_NEW(Number, low->pstate(), start, sass_end->unit());
-    env.set_local(variable, it);
-    Block_Obj body = f->block();
-    Expression_Ptr val = 0;
-    if (start < end) {
-      if (f->is_inclusive()) ++end;
-      for (double i = start;
-           i < end;
-           ++i) {
-        it->value(i);
-        env.set_local(variable, it);
-        val = body->perform(this);
-        if (val) break;
-      }
-    } else {
-      if (f->is_inclusive()) --end;
-      for (double i = start;
-           i > end;
-           --i) {
-        it->value(i);
-        env.set_local(variable, it);
-        val = body->perform(this);
-        if (val) break;
-      }
-    }
-    exp.env_stack.pop_back();
-    return val;
-  }
-
-  // Eval does not create a new env scope
-  // But iteration vars are reset afterwards
-  Expression_Ptr Eval::operator()(Each_Ptr e)
-  {
-    std::vector<std::string> variables(e->variables());
-    Expression_Obj expr = e->list()->perform(this);
-    Env env(environment(), true);
-    exp.env_stack.push_back(&env);
-    List_Obj list = 0;
-    Map_Ptr map = 0;
-    if (expr->concrete_type() == Expression::MAP) {
-      map = SASS_MEMORY_CAST(Map, expr);
-    }
-    else if (Selector_List_Ptr ls = SASS_MEMORY_CAST(Selector_List, expr)) {
-      Listize listize;
-      Expression_Obj rv = ls->perform(&listize);
-      list = dynamic_cast<List_Ptr>(&rv);
-    }
-    else if (expr->concrete_type() != Expression::LIST) {
-      list = SASS_MEMORY_NEW(List, expr->pstate(), 1, SASS_COMMA);
-      list->append(expr);
-    }
-    else {
-      list = SASS_MEMORY_CAST(List, expr);
-    }
-
-    Block_Obj body = e->block();
-    Expression_Obj val = 0;
-
-    if (map) {
-      for (Expression_Obj key : map->keys()) {
-        Expression_Obj value = map->at(key);
-
-        if (variables.size() == 1) {
-          List_Ptr variable = SASS_MEMORY_NEW(List, map->pstate(), 2, SASS_SPACE);
-          variable->append(key);
-          variable->append(value);
-          env.set_local(variables[0], variable);
-        } else {
-          env.set_local(variables[0], &key);
-          env.set_local(variables[1], &value);
-        }
-
-        val = body->perform(this);
-        if (val) break;
-      }
-    }
-    else {
-      if (list->length() == 1 && SASS_MEMORY_CAST(Selector_List, list)) {
-        list = SASS_MEMORY_CAST(List, list);
-      }
-      for (size_t i = 0, L = list->length(); i < L; ++i) {
-        Expression_Ptr e = &list->at(i);
-        // unwrap value if the expression is an argument
-        if (Argument_Ptr arg = SASS_MEMORY_CAST_PTR(Argument, e)) e = &arg->value();
-        // check if we got passed a list of args (investigate)
-        if (List_Ptr scalars = SASS_MEMORY_CAST_PTR(List, e)) {
-          if (variables.size() == 1) {
-            Expression_Ptr var = scalars;
-            env.set_local(variables[0], var);
-          } else {
-            // XXX: this is never hit via spec tests
-            for (size_t j = 0, K = variables.size(); j < K; ++j) {
-              Expression_Ptr res = j >= scalars->length()
-                ? SASS_MEMORY_NEW(Null, expr->pstate())
-                : &scalars->at(j);
-              env.set_local(variables[j], res);
-            }
-          }
-        } else {
-          if (variables.size() > 0) {
-            env.set_local(variables.at(0), e);
-            for (size_t j = 1, K = variables.size(); j < K; ++j) {
-              // XXX: this is never hit via spec tests
-              Expression_Ptr res = SASS_MEMORY_NEW(Null, expr->pstate());
-              env.set_local(variables[j], res);
-            }
-          }
-        }
-        val = body->perform(this);
-        if (val) break;
-      }
-    }
-    exp.env_stack.pop_back();
-    return val.detach();
-  }
-
-  Expression_Ptr Eval::operator()(While_Ptr w)
-  {
-    Expression_Obj pred = w->predicate();
-    Block_Obj body = w->block();
-    Env env(environment(), true);
-    exp.env_stack.push_back(&env);
-    Expression_Obj cond = pred->perform(this);
-    while (!cond->is_false()) {
-      Expression_Obj val = body->perform(this);
-      if (val) {
-        exp.env_stack.pop_back();
-        return val.detach();
-      }
-      cond = pred->perform(this);
-    }
-    exp.env_stack.pop_back();
-    return 0;
-  }
-
-  Expression_Ptr Eval::operator()(Return_Ptr r)
-  {
-    return r->value()->perform(this);
-  }
-
-  Expression_Ptr Eval::operator()(Warning_Ptr w)
-  {
-    Sass_Output_Style outstyle = ctx.c_options.output_style;
-    ctx.c_options.output_style = NESTED;
-    Expression_Obj message = w->message()->perform(this);
-    Env* env = exp.environment();
-
-    // try to use generic function
-    if (env->has("@warn[f]")) {
-
-      Definition_Ptr def = SASS_MEMORY_CAST(Definition, (*env)["@warn[f]"]);
-      // Block_Obj          body   = def->block();
-      // Native_Function func   = def->native_function();
-      Sass_Function_Entry c_function = def->c_function();
-      Sass_Function_Fn c_func = sass_function_get_function(c_function);
-
-      To_C to_c;
-      union Sass_Value* c_args = sass_make_list(1, SASS_COMMA);
-      sass_list_set_value(c_args, 0, message->perform(&to_c));
-      union Sass_Value* c_val = c_func(c_args, c_function, ctx.c_compiler);
-      ctx.c_options.output_style = outstyle;
-      sass_delete_value(c_args);
-      sass_delete_value(c_val);
-      return 0;
-
-    }
-
-    std::string result(unquote(message->to_sass()));
-    Backtrace top(backtrace(), w->pstate(), "");
-    std::cerr << "WARNING: " << result;
-    std::cerr << top.to_string();
-    std::cerr << std::endl << std::endl;
-    ctx.c_options.output_style = outstyle;
-    return 0;
-  }
-
-  Expression_Ptr Eval::operator()(Error_Ptr e)
-  {
-    Sass_Output_Style outstyle = ctx.c_options.output_style;
-    ctx.c_options.output_style = NESTED;
-    Expression_Obj message = e->message()->perform(this);
-    Env* env = exp.environment();
-
-    // try to use generic function
-    if (env->has("@error[f]")) {
-
-      Definition_Ptr def = SASS_MEMORY_CAST(Definition, (*env)["@error[f]"]);
-      // Block_Obj          body   = def->block();
-      // Native_Function func   = def->native_function();
-      Sass_Function_Entry c_function = def->c_function();
-      Sass_Function_Fn c_func = sass_function_get_function(c_function);
-
-      To_C to_c;
-      union Sass_Value* c_args = sass_make_list(1, SASS_COMMA);
-      sass_list_set_value(c_args, 0, message->perform(&to_c));
-      union Sass_Value* c_val = c_func(c_args, c_function, ctx.c_compiler);
-      ctx.c_options.output_style = outstyle;
-      sass_delete_value(c_args);
-      sass_delete_value(c_val);
-      return 0;
-
-    }
-
-    std::string result(unquote(message->to_sass()));
-    ctx.c_options.output_style = outstyle;
-    error(result, e->pstate());
-    return 0;
-  }
-
-  Expression_Ptr Eval::operator()(Debug_Ptr d)
-  {
-    Sass_Output_Style outstyle = ctx.c_options.output_style;
-    ctx.c_options.output_style = NESTED;
-    Expression_Obj message = d->value()->perform(this);
-    Env* env = exp.environment();
-
-    // try to use generic function
-    if (env->has("@debug[f]")) {
-
-      Definition_Ptr def = SASS_MEMORY_CAST(Definition, (*env)["@debug[f]"]);
-      // Block_Obj          body   = def->block();
-      // Native_Function func   = def->native_function();
-      Sass_Function_Entry c_function = def->c_function();
-      Sass_Function_Fn c_func = sass_function_get_function(c_function);
-
-      To_C to_c;
-      union Sass_Value* c_args = sass_make_list(1, SASS_COMMA);
-      sass_list_set_value(c_args, 0, message->perform(&to_c));
-      union Sass_Value* c_val = c_func(c_args, c_function, ctx.c_compiler);
-      ctx.c_options.output_style = outstyle;
-      sass_delete_value(c_args);
-      sass_delete_value(c_val);
-      return 0;
-
-    }
-
-    std::string cwd(ctx.cwd());
-    std::string result(unquote(message->to_sass()));
-    std::string abs_path(Sass::File::rel2abs(d->pstate().path, cwd, cwd));
-    std::string rel_path(Sass::File::abs2rel(d->pstate().path, cwd, cwd));
-    std::string output_path(Sass::File::path_for_console(rel_path, abs_path, d->pstate().path));
-    ctx.c_options.output_style = outstyle;
-
-    std::cerr << output_path << ":" << d->pstate().line+1 << " DEBUG: " << result;
-    std::cerr << std::endl;
-    return 0;
-  }
-
-  Expression_Ptr Eval::operator()(List_Ptr l)
-  {
-    // special case for unevaluated map
-    if (l->separator() == SASS_HASH) {
-      Map_Obj lm = SASS_MEMORY_NEW(Map,
-                                l->pstate(),
-                                l->length() / 2);
-      for (size_t i = 0, L = l->length(); i < L; i += 2)
-      {
-        Expression_Ptr key = (*l)[i+0]->perform(this);
-        Expression_Ptr val = (*l)[i+1]->perform(this);
-        // make sure the color key never displays its real name
-        key->is_delayed(true); // verified
-        *lm << std::make_pair(key, val);
-      }
-      if (lm->has_duplicate_key()) {
-        throw Exception::DuplicateKeyError(*lm, *l);
-      }
-
-      lm->is_interpolant(l->is_interpolant());
-      return lm->perform(this);
-    }
-    // check if we should expand it
-    if (l->is_expanded()) return l;
-    // regular case for unevaluated lists
-    List_Obj ll = SASS_MEMORY_NEW(List,
-                               l->pstate(),
-                               l->length(),
-                               l->separator(),
-                               l->is_arglist());
-    for (size_t i = 0, L = l->length(); i < L; ++i) {
-      ll->append((*l)[i]->perform(this));
-    }
-    ll->is_interpolant(l->is_interpolant());
-    ll->from_selector(l->from_selector());
-    ll->is_expanded(true);
-    return ll.detach();
-  }
-
-  Expression_Ptr Eval::operator()(Map_Ptr m)
-  {
-    if (m->is_expanded()) return m;
-
-    // make sure we're not starting with duplicate keys.
-    // the duplicate key state will have been set in the parser phase.
-    if (m->has_duplicate_key()) {
-      throw Exception::DuplicateKeyError(*m, *m);
-    }
-
-    Map_Obj mm = SASS_MEMORY_NEW(Map,
-                                m->pstate(),
-                                m->length());
-    for (auto key : m->keys()) {
-      Expression_Ptr ex_key = key->perform(this);
-      Expression_Ptr ex_val = m->at(key)->perform(this);
-      *mm << std::make_pair(ex_key, ex_val);
-    }
-
-    // check the evaluated keys aren't duplicates.
-    if (mm->has_duplicate_key()) {
-      throw Exception::DuplicateKeyError(*mm, *m);
-    }
-
-    mm->is_expanded(true);
-    return mm.detach();
-  }
-
-  Expression_Ptr Eval::operator()(Binary_Expression_Ptr b_in)
-  {
-
-    String_Schema_Obj ret_schema;
-    Binary_Expression_Obj b = b_in;
-    enum Sass_OP op_type = b->type();
-
-    // only the last item will be used to eval the binary expression
-    if (String_Schema_Ptr s_l = SASS_MEMORY_CAST(String_Schema, b->left())) {
-      if (!s_l->has_interpolant() && (!s_l->is_right_interpolant())) {
-        ret_schema = SASS_MEMORY_NEW(String_Schema, b->pstate());
-        Binary_Expression_Obj bin_ex = SASS_MEMORY_NEW(Binary_Expression, b->pstate(),
-                                                    b->op(), &s_l->last(), b->right());
-        bin_ex->is_delayed(b->left()->is_delayed() || b->right()->is_delayed()); // unverified
-        for (size_t i = 0; i < s_l->length() - 1; ++i) {
-          ret_schema->append(s_l->at(i)->perform(this));
-        }
-        ret_schema->append(bin_ex->perform(this));
-        return ret_schema->perform(this);
-      }
-    }
-    if (String_Schema_Ptr s_r = SASS_MEMORY_CAST(String_Schema, b->right())) {
-
-      if (!s_r->has_interpolant() && (!s_r->is_left_interpolant() || op_type == Sass_OP::DIV)) {
-        ret_schema = SASS_MEMORY_NEW(String_Schema, b->pstate());
-        Binary_Expression_Obj bin_ex = SASS_MEMORY_NEW(Binary_Expression, b->pstate(),
-                                                    b->op(), b->left(), &s_r->first());
-        bin_ex->is_delayed(b->left()->is_delayed() || b->right()->is_delayed()); // verified
-        ret_schema->append(bin_ex->perform(this));
-        for (size_t i = 1; i < s_r->length(); ++i) {
-          ret_schema->append(s_r->at(i)->perform(this));
-        }
-        return ret_schema->perform(this);
-      }
-    }
-
-    // don't eval delayed expressions (the '/' when used as a separator)
-    if (!force && op_type == Sass_OP::DIV && b->is_delayed()) {
-      b->right(b->right()->perform(this));
-      b->left(b->left()->perform(this));
-      return b.detach();
-    }
-
-    Expression_Obj lhs = b->left();
-    Expression_Obj rhs = b->right();
-
-    // fully evaluate their values
-    if (op_type == Sass_OP::EQ ||
-        op_type == Sass_OP::NEQ ||
-        op_type == Sass_OP::GT ||
-        op_type == Sass_OP::GTE ||
-        op_type == Sass_OP::LT ||
-        op_type == Sass_OP::LTE)
-    {
-      LOCAL_FLAG(force, true);
-      lhs->is_expanded(false);
-      lhs->set_delayed(false);
-      lhs = lhs->perform(this);
-      rhs->is_expanded(false);
-      rhs->set_delayed(false);
-      rhs = rhs->perform(this);
-    }
-    else {
-      lhs = lhs->perform(this);
-    }
-
-    Binary_Expression_Obj u3 = b;
-    switch (op_type) {
-      case Sass_OP::AND: {
-        return *lhs ? b->right()->perform(this) : lhs.detach();
-      } break;
-
-      case Sass_OP::OR: {
-        return *lhs ? lhs.detach() : b->right()->perform(this);
-      } break;
-
-      default:
-        break;
-    }
-    // not a logical connective, so go ahead and eval the rhs
-    rhs = rhs->perform(this);
-    AST_Node_Obj lu = &lhs;
-    AST_Node_Obj ru = &rhs;
-
-    Expression::Concrete_Type l_type = lhs->concrete_type();
-    Expression::Concrete_Type r_type = rhs->concrete_type();
-
-    // Is one of the operands an interpolant?
-    String_Schema_Obj s1 = SASS_MEMORY_CAST(String_Schema, b->left());
-    String_Schema_Obj s2 = SASS_MEMORY_CAST(String_Schema, b->right());
-    Binary_Expression_Obj b1 = SASS_MEMORY_CAST(Binary_Expression, b->left());
-    Binary_Expression_Obj b2 = SASS_MEMORY_CAST(Binary_Expression, b->right());
-
-    bool schema_op = false;
-
-    bool force_delay = (s2 && s2->is_left_interpolant()) ||
-                       (s1 && s1->is_right_interpolant()) ||
-                       (b1 && b1->is_right_interpolant()) ||
-                       (b2 && b2->is_left_interpolant());
-
-    if ((s1 && s1->has_interpolants()) || (s2 && s2->has_interpolants()) || force_delay)
-    {
-      if (op_type == Sass_OP::DIV || op_type == Sass_OP::MUL || op_type == Sass_OP::MOD || op_type == Sass_OP::ADD || op_type == Sass_OP::SUB ||
-          op_type == Sass_OP::EQ) {
-        // If possible upgrade LHS to a number (for number to string compare)
-        if (String_Constant_Ptr str = SASS_MEMORY_CAST(String_Constant, lhs)) {
-          std::string value(str->value());
-          const char* start = value.c_str();
-          if (Prelexer::sequence < Prelexer::dimension, Prelexer::end_of_file >(start) != 0) {
-            Textual_Obj l = SASS_MEMORY_NEW(Textual, b->pstate(), Textual::DIMENSION, str->value());
-            lhs = l->perform(this);
-          }
-        }
-        // If possible upgrade RHS to a number (for string to number compare)
-        if (String_Constant_Ptr str = SASS_MEMORY_CAST(String_Constant, rhs)) {
-          std::string value(str->value());
-          const char* start = value.c_str();
-          if (Prelexer::sequence < Prelexer::dimension, Prelexer::number >(start) != 0) {
-            Textual_Obj r = SASS_MEMORY_NEW(Textual, b->pstate(), Textual::DIMENSION, str->value());
-            rhs = r->perform(this);
-          }
-        }
-      }
-
-      To_Value to_value(ctx);
-      Value_Obj v_l = dynamic_cast<Value_Ptr>(lhs->perform(&to_value));
-      Value_Obj v_r = dynamic_cast<Value_Ptr>(rhs->perform(&to_value));
-      l_type = lhs->concrete_type();
-      r_type = rhs->concrete_type();
-
-      if (s2 && s2->has_interpolants() && s2->length()) {
-        Textual_Obj front = SASS_MEMORY_CAST(Textual, s2->elements().front());
-        if (front && !front->is_interpolant())
-        {
-          // XXX: this is never hit via spec tests
-          schema_op = true;
-          rhs = front->perform(this);
-        }
-      }
-
-      if (force_delay) {
-        std::string str("");
-        str += v_l->to_string(ctx.c_options);
-        if (b->op().ws_before) str += " ";
-        str += b->separator();
-        if (b->op().ws_after) str += " ";
-        str += v_r->to_string(ctx.c_options);
-        String_Constant_Ptr val = SASS_MEMORY_NEW(String_Constant, b->pstate(), str);
-        val->is_interpolant(b->left()->has_interpolant());
-        return val;
-      }
-    }
-
-    // see if it's a relational expression
-    try {
-      switch(op_type) {
-        case Sass_OP::EQ:  return SASS_MEMORY_NEW(Boolean, b->pstate(), eq(lhs, rhs));
-        case Sass_OP::NEQ: return SASS_MEMORY_NEW(Boolean, b->pstate(), !eq(lhs, rhs));
-        case Sass_OP::GT:  return SASS_MEMORY_NEW(Boolean, b->pstate(), !lt(lhs, rhs, "gt") && !eq(lhs, rhs));
-        case Sass_OP::GTE: return SASS_MEMORY_NEW(Boolean, b->pstate(), !lt(lhs, rhs, "gte"));
-        case Sass_OP::LT:  return SASS_MEMORY_NEW(Boolean, b->pstate(), lt(lhs, rhs, "lt"));
-        case Sass_OP::LTE: return SASS_MEMORY_NEW(Boolean, b->pstate(), lt(lhs, rhs, "lte") || eq(lhs, rhs));
-        default:                     break;
-      }
-    }
-    catch (Exception::OperationError& err)
-    {
-      // throw Exception::Base(b->pstate(), err.what());
-      throw Exception::SassValueError(b->pstate(), err);
-    }
-
-    l_type = lhs->concrete_type();
-    r_type = rhs->concrete_type();
-
-    // ToDo: throw error in op functions
-    // ToDo: then catch and re-throw them
-    Expression_Obj rv = 0;
-    try {
-      ParserState pstate(b->pstate());
-      if (l_type == Expression::NUMBER && r_type == Expression::NUMBER) {
-        Number_Ptr l_n = SASS_MEMORY_CAST(Number, lhs);
-        Number_Ptr r_n = SASS_MEMORY_CAST(Number, rhs);
-        rv = op_numbers(op_type, *l_n, *r_n, ctx.c_options, &pstate);
-      }
-      else if (l_type == Expression::NUMBER && r_type == Expression::COLOR) {
-        Number_Ptr l_n = SASS_MEMORY_CAST(Number, lhs);
-        Color_Ptr r_c = SASS_MEMORY_CAST(Color, rhs);
-        rv = op_number_color(op_type, *l_n, *r_c, ctx.c_options, &pstate);
-      }
-      else if (l_type == Expression::COLOR && r_type == Expression::NUMBER) {
-        Color_Ptr l_c = SASS_MEMORY_CAST(Color, lhs);
-        Number_Ptr r_n = SASS_MEMORY_CAST(Number, rhs);
-        rv = op_color_number(op_type, *l_c, *r_n, ctx.c_options, &pstate);
-      }
-      else if (l_type == Expression::COLOR && r_type == Expression::COLOR) {
-        Color_Ptr l_c = SASS_MEMORY_CAST(Color, lhs);
-        Color_Ptr r_c = SASS_MEMORY_CAST(Color, rhs);
-        rv = op_colors(op_type, *l_c, *r_c, ctx.c_options, &pstate);
-      }
-      else {
-        To_Value to_value(ctx);
-        // this will leak if perform does not return a value!
-        Value_Obj v_l = SASS_MEMORY_CAST_PTR(Value, lhs->perform(&to_value));
-        Value_Obj v_r = SASS_MEMORY_CAST_PTR(Value, rhs->perform(&to_value));
-        bool interpolant = b->is_right_interpolant() ||
-                           b->is_left_interpolant() ||
-                           b->is_interpolant();
-        if (op_type == Sass_OP::SUB) interpolant = false;
-        // if (op_type == Sass_OP::DIV) interpolant = true;
-        // check for type violations
-        if (l_type == Expression::MAP) {
-          throw Exception::InvalidValue(*v_l);
-        }
-        if (r_type == Expression::MAP) {
-          throw Exception::InvalidValue(*v_r);
-        }
-        Value_Ptr ex = op_strings(b->op(), *v_l, *v_r, ctx.c_options, &pstate, !interpolant); // pass true to compress
-        if (String_Constant_Ptr str = dynamic_cast<String_Constant_Ptr>(ex))
-        {
-          if (str->concrete_type() == Expression::STRING)
-          {
-            String_Constant_Ptr lstr = SASS_MEMORY_CAST(String_Constant, lhs);
-            String_Constant_Ptr rstr = SASS_MEMORY_CAST(String_Constant, rhs);
-            if (op_type != Sass_OP::SUB) {
-              if (String_Constant_Ptr org = lstr ? lstr : rstr)
-              { str->quote_mark(org->quote_mark()); }
-            }
-          }
-        }
-        ex->is_interpolant(b->is_interpolant());
-        rv = ex;
-      }
-    }
-    catch (Exception::OperationError& err)
-    {
-      // throw Exception::Base(b->pstate(), err.what());
-      throw Exception::SassValueError(b->pstate(), err);
-    }
-
-    if (rv) {
-      if (schema_op) {
-        // XXX: this is never hit via spec tests
-        (*s2)[0] = rv;
-        rv = s2->perform(this);
-      }
-    }
-
-    return rv.detach();
-
-  }
-
-  Expression_Ptr Eval::operator()(Unary_Expression_Ptr u)
-  {
-    Expression_Obj operand = u->operand()->perform(this);
-    if (u->type() == Unary_Expression::NOT) {
-      Boolean_Ptr result = SASS_MEMORY_NEW(Boolean, u->pstate(), (bool)*operand);
-      result->value(!result->value());
-      return result;
-    }
-    else if (operand->concrete_type() == Expression::NUMBER) {
-      Number_Ptr result = SASS_MEMORY_NEW(Number, static_cast<Number_Ptr>(&operand));
-      result->value(u->type() == Unary_Expression::MINUS
-                    ? -result->value()
-                    :  result->value());
-      return result;
-    }
-    else {
-      // Special cases: +/- variables which evaluate to null ouput just +/-,
-      // but +/- null itself outputs the string
-      if (operand->concrete_type() == Expression::NULL_VAL && SASS_MEMORY_CAST(Variable, u->operand())) {
-        u->operand(SASS_MEMORY_NEW(String_Quoted, u->pstate(), ""));
-      }
-      // Never apply unary opertions on colors @see #2140
-      else if (operand->concrete_type() == Expression::COLOR) {
-        Color_Ptr c = dynamic_cast<Color_Ptr>(&operand);
-
-        // Use the color name if this was eval with one
-        if (c->disp().length() > 0) {
-          operand = SASS_MEMORY_NEW(String_Constant, operand->pstate(), c->disp());
-          u->operand(operand);
-        }
-      }
-      else {
-        u->operand(operand);
-      }
-
-      String_Constant_Ptr result = SASS_MEMORY_NEW(String_Quoted,
-                                                  u->pstate(),
-                                                  u->inspect());
-      return result;
-    }
-    // unreachable
-    return u;
-  }
-
-  Expression_Ptr Eval::operator()(Function_Call_Ptr c)
-  {
-    if (backtrace()->parent != NULL && backtrace()->depth() > Constants::MaxCallStack) {
-        // XXX: this is never hit via spec tests
-        std::ostringstream stm;
-        stm << "Stack depth exceeded max of " << Constants::MaxCallStack;
-        error(stm.str(), c->pstate(), backtrace());
-    }
-    std::string name(Util::normalize_underscores(c->name()));
-    std::string full_name(name + "[f]");
-    // we make a clone here, need to implement that further
-    Arguments_Obj args = c->arguments();
-
-    Env* env = environment();
-    if (!env->has(full_name) || (!c->via_call() && Prelexer::re_special_fun(name.c_str()))) {
-      if (!env->has("*[f]")) {
-        for (Argument_Obj arg : args->elements()) {
-          if (List_Obj ls = SASS_MEMORY_CAST(List, arg->value())) {
-            if (ls->size() == 0) error("() isn't a valid CSS value.", c->pstate());
-          }
-        }
-        args = SASS_MEMORY_CAST_PTR(Arguments, args->perform(this));
-        Function_Call_Obj lit = SASS_MEMORY_NEW(Function_Call,
-                                             c->pstate(),
-                                             c->name(),
-                                             &args);
-        if (args->has_named_arguments()) {
-          error("Function " + c->name() + " doesn't support keyword arguments", c->pstate());
-        }
-        String_Quoted_Ptr str = SASS_MEMORY_NEW(String_Quoted,
-                                             c->pstate(),
-                                             lit->to_string(ctx.c_options));
-        str->is_interpolant(c->is_interpolant());
-        return str;
-      } else {
-        // call generic function
-        full_name = "*[f]";
-      }
-    }
-
-    // further delay for calls
-    if (full_name != "call[f]") {
-      args->set_delayed(false); // verified
-    }
-    if (full_name != "if[f]") {
-      args = SASS_MEMORY_CAST_PTR(Arguments, args->perform(this));
-    }
-    Definition_Ptr def = SASS_MEMORY_CAST(Definition, (*env)[full_name]);
-
-    if (def->is_overload_stub()) {
-      std::stringstream ss;
-      size_t L = args->length();
-      // account for rest arguments
-      if (args->has_rest_argument() && args->length() > 0) {
-        // get the rest arguments list
-        List_Ptr rest = SASS_MEMORY_CAST(List, args->last()->value());
-        // arguments before rest argument plus rest
-        if (rest) L += rest->length() - 1;
-      }
-      ss << full_name << L;
-      full_name = ss.str();
-      std::string resolved_name(full_name);
-      if (!env->has(resolved_name)) error("overloaded function `" + std::string(c->name()) + "` given wrong number of arguments", c->pstate());
-      def = SASS_MEMORY_CAST(Definition, (*env)[resolved_name]);
-    }
-
-    Expression_Obj     result = c;
-    Block_Obj          body   = def->block();
-    Native_Function func   = def->native_function();
-    Sass_Function_Entry c_function = def->c_function();
-
-    Parameters_Obj params = def->parameters();
-    Env fn_env(def->environment());
-    exp.env_stack.push_back(&fn_env);
-
-    if (func || body) {
-      bind(std::string("Function"), c->name(), params, args, &ctx, &fn_env, this);
-      Backtrace here(backtrace(), c->pstate(), ", in function `" + c->name() + "`");
-      exp.backtrace_stack.push_back(&here);
-      // eval the body if user-defined or special, invoke underlying CPP function if native
-      if (body /* && !Prelexer::re_special_fun(name.c_str()) */) {
-        result = body->perform(this);
-      }
-      else if (func) {
-        result = func(fn_env, *env, ctx, def->signature(), c->pstate(), backtrace(), exp.selector_stack);
-      }
-      if (!result) {
-        error(std::string("Function ") + c->name() + " did not return a value", c->pstate());
-      }
-      exp.backtrace_stack.pop_back();
-    }
-
-    // else if it's a user-defined c function
-    // convert call into C-API compatible form
-    else if (c_function) {
-      Sass_Function_Fn c_func = sass_function_get_function(c_function);
-      if (full_name == "*[f]") {
-        String_Quoted_Obj str = SASS_MEMORY_NEW(String_Quoted, c->pstate(), c->name());
-        Arguments_Obj new_args = SASS_MEMORY_NEW(Arguments, c->pstate());
-        new_args->append(SASS_MEMORY_NEW(Argument, c->pstate(), &str));
-        new_args->concat(&args);
-        args = new_args;
-      }
-
-      // populates env with default values for params
-      std::string ff(c->name());
-      bind(std::string("Function"), c->name(), params, args, &ctx, &fn_env, this);
-
-      Backtrace here(backtrace(), c->pstate(), ", in function `" + c->name() + "`");
-      exp.backtrace_stack.push_back(&here);
-
-      To_C to_c;
-      union Sass_Value* c_args = sass_make_list(params->length(), SASS_COMMA);
-      for(size_t i = 0; i < params->length(); i++) {
-        Parameter_Obj param = params->at(i);
-        std::string key = param->name();
-        AST_Node_Obj node = fn_env.get_local(key);
-        Expression_Obj arg = SASS_MEMORY_CAST(Expression, node);
-        sass_list_set_value(c_args, i, arg->perform(&to_c));
-      }
-      union Sass_Value* c_val = c_func(c_args, c_function, ctx.c_compiler);
-      if (sass_value_get_tag(c_val) == SASS_ERROR) {
-        error("error in C function " + c->name() + ": " + sass_error_get_message(c_val), c->pstate(), backtrace());
-      } else if (sass_value_get_tag(c_val) == SASS_WARNING) {
-        error("warning in C function " + c->name() + ": " + sass_warning_get_message(c_val), c->pstate(), backtrace());
-      }
-      result = cval_to_astnode(c_val, backtrace(), c->pstate());
-
-      exp.backtrace_stack.pop_back();
-      sass_delete_value(c_args);
-      if (c_val != c_args)
-        sass_delete_value(c_val);
-    }
-
-    // link back to function definition
-    // only do this for custom functions
-    if (result->pstate().file == std::string::npos)
-      result->pstate(c->pstate());
-
-    result = result->perform(this);
-    result->is_interpolant(c->is_interpolant());
-    exp.env_stack.pop_back();
-    return result.detach();
-  }
-
-  Expression_Ptr Eval::operator()(Function_Call_Schema_Ptr s)
-  {
-    Expression_Ptr evaluated_name = s->name()->perform(this);
-    Expression_Ptr evaluated_args = s->arguments()->perform(this);
-    String_Schema_Obj ss = SASS_MEMORY_NEW(String_Schema, s->pstate(), 2);
-    ss->append(evaluated_name);
-    ss->append(evaluated_args);
-    return ss->perform(this);
-  }
-
-  Expression_Ptr Eval::operator()(Variable_Ptr v)
-  {
-    std::string name(v->name());
-    Expression_Obj value = 0;
-    Env* env = environment();
-    if (env->has(name)) {
-      value = SASS_MEMORY_CAST(Expression, (*env)[name]);
-    }
-    else error("Undefined variable: \"" + v->name() + "\".", v->pstate());
-    if (typeid(*value) == typeid(Argument)) {
-      value = SASS_MEMORY_CAST(Argument, value)->value();
-    }
-
-    // behave according to as ruby sass (add leading zero)
-    if (Number_Ptr nr = SASS_MEMORY_CAST(Number, value)) {
-      nr->zero(true);
-    }
-
-    value->is_interpolant(v->is_interpolant());
-    if (force) value->is_expanded(false);
-    value->set_delayed(false); // verified
-    value = value->perform(this);
-    if(!force) (*env)[name] = &value;
-    return value.detach();
-  }
-
-  Expression_Ptr Eval::operator()(Textual_Ptr t)
-  {
-    using Prelexer::number;
-    Expression_Obj result = 0;
-    size_t L = t->value().length();
-    bool zero = !( (L > 0 && t->value().substr(0, 1) == ".") ||
-                   (L > 1 && t->value().substr(0, 2) == "0.") ||
-                   (L > 1 && t->value().substr(0, 2) == "-.")  ||
-                   (L > 2 && t->value().substr(0, 3) == "-0.")
-                 );
-
-    const std::string& text = t->value();
-    size_t num_pos = text.find_first_not_of(" \n\r\t");
-    if (num_pos == std::string::npos) num_pos = text.length();
-    size_t unit_pos = text.find_first_not_of("-+0123456789.", num_pos);
-    if (unit_pos == std::string::npos) unit_pos = text.length();
-    const std::string& num = text.substr(num_pos, unit_pos - num_pos);
-
-    switch (t->type())
-    {
-      case Textual::NUMBER:
-        result = SASS_MEMORY_NEW(Number,
-                                 t->pstate(),
-                                 sass_atof(num.c_str()),
-                                 "",
-                                 zero);
-        break;
-      case Textual::PERCENTAGE:
-        result = SASS_MEMORY_NEW(Number,
-                                 t->pstate(),
-                                 sass_atof(num.c_str()),
-                                 "%",
-                                 true);
-        break;
-      case Textual::DIMENSION:
-        result = SASS_MEMORY_NEW(Number,
-                                 t->pstate(),
-                                 sass_atof(num.c_str()),
-                                 Token(number(text.c_str())),
-                                 zero);
-        break;
-      case Textual::HEX: {
-        if (t->value().substr(0, 1) != "#") {
-          result = SASS_MEMORY_NEW(String_Quoted, t->pstate(), t->value());
-          break;
-        }
-        std::string hext(t->value().substr(1)); // chop off the '#'
-        if (hext.length() == 6) {
-          std::string r(hext.substr(0,2));
-          std::string g(hext.substr(2,2));
-          std::string b(hext.substr(4,2));
-          result = SASS_MEMORY_NEW(Color,
-                                   t->pstate(),
-                                   static_cast<double>(strtol(r.c_str(), NULL, 16)),
-                                   static_cast<double>(strtol(g.c_str(), NULL, 16)),
-                                   static_cast<double>(strtol(b.c_str(), NULL, 16)),
-                                   1, // alpha channel
-                                   t->value());
-        }
-        else {
-          result = SASS_MEMORY_NEW(Color,
-                                   t->pstate(),
-                                   static_cast<double>(strtol(std::string(2,hext[0]).c_str(), NULL, 16)),
-                                   static_cast<double>(strtol(std::string(2,hext[1]).c_str(), NULL, 16)),
-                                   static_cast<double>(strtol(std::string(2,hext[2]).c_str(), NULL, 16)),
-                                   1, // alpha channel
-                                   t->value());
-        }
-      } break;
-    }
-    result->is_interpolant(t->is_interpolant());
-    return result.detach();
-  }
-
-  Expression_Ptr Eval::operator()(Color_Ptr c)
-  {
-    return c;
-  }
-
-  Expression_Ptr Eval::operator()(Number_Ptr n)
-  {
-    return n;
-  }
-
-  Expression_Ptr Eval::operator()(Boolean_Ptr b)
-  {
-    return b;
-  }
-
-  void Eval::interpolation(Context& ctx, std::string& res, Expression_Obj ex, bool into_quotes, bool was_itpl) {
-
-    bool needs_closing_brace = false;
-
-    if (Arguments_Ptr args = SASS_MEMORY_CAST(Arguments, ex)) {
-      List_Ptr ll = SASS_MEMORY_NEW(List, args->pstate(), 0, SASS_COMMA);
-      for(auto arg : args->elements()) {
-        ll->append(arg->value());
-      }
-      ll->is_interpolant(args->is_interpolant());
-      needs_closing_brace = true;
-      res += "(";
-      ex = ll;
-    }
-    if (Number_Ptr nr = SASS_MEMORY_CAST(Number, ex)) {
-      if (!nr->is_valid_css_unit()) {
-        throw Exception::InvalidValue(*nr);
-      }
-    }
-    if (Argument_Ptr arg = SASS_MEMORY_CAST(Argument, ex)) {
-      ex = &arg->value();
-    }
-    if (String_Quoted_Ptr sq = SASS_MEMORY_CAST(String_Quoted, ex)) {
-      if (was_itpl) {
-        bool was_interpolant = ex->is_interpolant();
-        ex = SASS_MEMORY_NEW(String_Constant, sq->pstate(), sq->value());
-        ex->is_interpolant(was_interpolant);
-      }
-    }
-
-    if (SASS_MEMORY_CAST(Null, ex)) { return; }
-
-    // parent selector needs another go
-    if (SASS_MEMORY_CAST(Parent_Selector, ex)) {
-      // XXX: this is never hit via spec tests
-      ex = ex->perform(this);
-    }
-
-    if (List_Ptr l = SASS_MEMORY_CAST(List, ex)) {
-      List_Obj ll = SASS_MEMORY_NEW(List, l->pstate(), 0, l->separator());
-      // this fixes an issue with bourbon sample, not really sure why
-      // if (l->size() && dynamic_cast<Null_Ptr>((*l)[0])) { res += ""; }
-      for(Expression_Obj item : *l) {
-        item->is_interpolant(l->is_interpolant());
-        std::string rl(""); interpolation(ctx, rl, &item, into_quotes, l->is_interpolant());
-        bool is_null = dynamic_cast<Null_Ptr>(&item) != 0; // rl != ""
-        if (!is_null) ll->append(SASS_MEMORY_NEW(String_Quoted, item->pstate(), rl));
-      }
-      // Check indicates that we probably should not get a list
-      // here. Normally single list items are already unwrapped.
-      if (l->size() > 1) {
-        // string_to_output would fail "#{'_\a' '_\a'}";
-        std::string str(ll->to_string(ctx.c_options));
-        newline_to_space(str); // replace directly
-        res += str; // append to result string
-      } else {
-        res += (ll->to_string(ctx.c_options));
-      }
-      ll->is_interpolant(l->is_interpolant());
-    }
-
-    // Value
-    // Textual
-    // Function_Call
-    // Selector_List
-    // String_Quoted
-    // String_Constant
-    // Parent_Selector
-    // Binary_Expression
-    else {
-      // ex = ex->perform(this);
-      if (into_quotes && ex->is_interpolant()) {
-        res += evacuate_escapes(ex ? ex->to_string(ctx.c_options) : "");
-      } else {
-        res += ex ? ex->to_string(ctx.c_options) : "";
-      }
-    }
-
-    if (needs_closing_brace) res += ")";
-
-  }
-
-  Expression_Ptr Eval::operator()(String_Schema_Ptr s)
-  {
-    size_t L = s->length();
-    bool into_quotes = false;
-    if (L > 1) {
-      if (!SASS_MEMORY_CAST(String_Quoted, (*s)[0]) && !SASS_MEMORY_CAST(String_Quoted, (*s)[L - 1])) {
-      if (String_Constant_Ptr l = SASS_MEMORY_CAST(String_Constant, (*s)[0])) {
-        if (String_Constant_Ptr r = SASS_MEMORY_CAST(String_Constant, (*s)[L - 1])) {
-          if (r->value().size() > 0) {
-            if (l->value()[0] == '"' && r->value()[r->value().size() - 1] == '"') into_quotes = true;
-            if (l->value()[0] == '\'' && r->value()[r->value().size() - 1] == '\'') into_quotes = true;
-          }
-        }
-      }
-      }
-    }
-    bool was_quoted = false;
-    bool was_interpolant = false;
-    std::string res("");
-    for (size_t i = 0; i < L; ++i) {
-      bool is_quoted = SASS_MEMORY_CAST(String_Quoted, (*s)[i]) != NULL;
-      if (was_quoted && !(*s)[i]->is_interpolant() && !was_interpolant) { res += " "; }
-      else if (i > 0 && is_quoted && !(*s)[i]->is_interpolant() && !was_interpolant) { res += " "; }
-      Expression_Obj ex = (*s)[i]->perform(this);
-      interpolation(ctx, res, ex, into_quotes, ex->is_interpolant());
-      was_quoted = SASS_MEMORY_CAST(String_Quoted, (*s)[i]) != NULL;
-      was_interpolant = (*s)[i]->is_interpolant();
-
-    }
-    if (!s->is_interpolant()) {
-      if (s->length() > 1 && res == "") return SASS_MEMORY_NEW(Null, s->pstate());
-      return SASS_MEMORY_NEW(String_Constant, s->pstate(), res);
-    }
-    // string schema seems to have a special unquoting behavior (also handles "nested" quotes)
-    String_Quoted_Obj str = SASS_MEMORY_NEW(String_Quoted, s->pstate(), res, 0, false, false, false);
-    // if (s->is_interpolant()) str->quote_mark(0);
-    // String_Constant_Ptr str = SASS_MEMORY_NEW(String_Constant, s->pstate(), res);
-    if (str->quote_mark()) str->quote_mark('*');
-    else if (!is_in_comment) str->value(string_to_output(str->value()));
-    str->is_interpolant(s->is_interpolant());
-    return str.detach();
-  }
-
-
-  Expression_Ptr Eval::operator()(String_Constant_Ptr s)
-  {
-    if (!s->is_delayed() && name_to_color(s->value())) {
-      Color_Ptr c = SASS_MEMORY_COPY(name_to_color(s->value())); // copy
-      c->pstate(s->pstate());
-      c->disp(s->value());
-      c->is_delayed(true);
-      return c;
-    }
-    return s;
-  }
-
-  Expression_Ptr Eval::operator()(String_Quoted_Ptr s)
-  {
-    String_Quoted_Ptr str = SASS_MEMORY_NEW(String_Quoted, s->pstate(), "");
-    str->value(s->value());
-    str->quote_mark(s->quote_mark());
-    str->is_interpolant(s->is_interpolant());
-    return str;
-  }
-
-  Expression_Ptr Eval::operator()(Supports_Operator_Ptr c)
-  {
-    Expression_Ptr left = c->left()->perform(this);
-    Expression_Ptr right = c->right()->perform(this);
-    Supports_Operator_Ptr cc = SASS_MEMORY_NEW(Supports_Operator,
-                                 c->pstate(),
-                                 dynamic_cast<Supports_Condition_Ptr>(left),
-                                 dynamic_cast<Supports_Condition_Ptr>(right),
-                                 c->operand());
-    return cc;
-  }
-
-  Expression_Ptr Eval::operator()(Supports_Negation_Ptr c)
-  {
-    Expression_Ptr condition = c->condition()->perform(this);
-    Supports_Negation_Ptr cc = SASS_MEMORY_NEW(Supports_Negation,
-                                 c->pstate(),
-                                 dynamic_cast<Supports_Condition_Ptr>(condition));
-    return cc;
-  }
-
-  Expression_Ptr Eval::operator()(Supports_Declaration_Ptr c)
-  {
-    Expression_Ptr feature = c->feature()->perform(this);
-    Expression_Ptr value = c->value()->perform(this);
-    Supports_Declaration_Ptr cc = SASS_MEMORY_NEW(Supports_Declaration,
-                              c->pstate(),
-                              feature,
-                              value);
-    return cc;
-  }
-
-  Expression_Ptr Eval::operator()(Supports_Interpolation_Ptr c)
-  {
-    Expression_Ptr value = c->value()->perform(this);
-    Supports_Interpolation_Ptr cc = SASS_MEMORY_NEW(Supports_Interpolation,
-                            c->pstate(),
-                            value);
-    return cc;
-  }
-
-  Expression_Ptr Eval::operator()(At_Root_Query_Ptr e)
-  {
-    Expression_Obj feature = e->feature();
-    feature = (feature ? feature->perform(this) : 0);
-    Expression_Obj value = e->value();
-    value = (value ? value->perform(this) : 0);
-    Expression_Ptr ee = SASS_MEMORY_NEW(At_Root_Query,
-                                     e->pstate(),
-                                     dynamic_cast<String_Ptr>(&feature),
-                                     value);
-    return ee;
-  }
-
-  Expression_Ptr Eval::operator()(Media_Query_Ptr q)
-  {
-    String_Obj t = q->media_type();
-    t = static_cast<String_Ptr>(&t ? t->perform(this) : 0);
-    Media_Query_Obj qq = SASS_MEMORY_NEW(Media_Query,
-                                      q->pstate(),
-                                      &t,
-                                      q->length(),
-                                      q->is_negated(),
-                                      q->is_restricted());
-    for (size_t i = 0, L = q->length(); i < L; ++i) {
-      qq->append(static_cast<Media_Query_Expression_Ptr>((*q)[i]->perform(this)));
-    }
-    return qq.detach();
-  }
-
-  Expression_Ptr Eval::operator()(Media_Query_Expression_Ptr e)
-  {
-    Expression_Obj feature = e->feature();
-    feature = (feature ? feature->perform(this) : 0);
-    if (feature && SASS_MEMORY_CAST(String_Quoted, feature)) {
-      feature = SASS_MEMORY_NEW(String_Quoted,
-                                  feature->pstate(),
-                                  SASS_MEMORY_CAST(String_Quoted, feature)->value());
-    }
-    Expression_Obj value = e->value();
-    value = (value ? value->perform(this) : 0);
-    if (value && SASS_MEMORY_CAST(String_Quoted, value)) {
-      // XXX: this is never hit via spec tests
-      value = SASS_MEMORY_NEW(String_Quoted,
-                                value->pstate(),
-                                SASS_MEMORY_CAST(String_Quoted, value)->value());
-    }
-    return SASS_MEMORY_NEW(Media_Query_Expression,
-                           e->pstate(),
-                           feature,
-                           value,
-                           e->is_interpolated());
-  }
-
-  Expression_Ptr Eval::operator()(Null_Ptr n)
-  {
-    return n;
-  }
-
-  Expression_Ptr Eval::operator()(Argument_Ptr a)
-  {
-    Expression_Obj val = a->value()->perform(this);
-    bool is_rest_argument = a->is_rest_argument();
-    bool is_keyword_argument = a->is_keyword_argument();
-
-    if (a->is_rest_argument()) {
-      if (val->concrete_type() == Expression::MAP) {
-        is_rest_argument = false;
-        is_keyword_argument = true;
-      }
-      else if(val->concrete_type() != Expression::LIST) {
-        List_Obj wrapper = SASS_MEMORY_NEW(List,
-                                        val->pstate(),
-                                        0,
-                                        SASS_COMMA,
-                                        true);
-        wrapper->append(val);
-        val = &wrapper;
-      }
-    }
-    return SASS_MEMORY_NEW(Argument,
-                           a->pstate(),
-                           val,
-                           a->name(),
-                           is_rest_argument,
-                           is_keyword_argument);
-  }
-
-  Expression_Ptr Eval::operator()(Arguments_Ptr a)
-  {
-    Arguments_Obj aa = SASS_MEMORY_NEW(Arguments, a->pstate());
-    if (a->length() == 0) return aa.detach();
-    for (size_t i = 0, L = a->length(); i < L; ++i) {
-      Expression_Obj rv = (*a)[i]->perform(this);
-      Argument_Ptr arg = SASS_MEMORY_CAST(Argument, rv);
-      if (!(arg->is_rest_argument() || arg->is_keyword_argument())) {
-        aa->append(arg);
-      }
-    }
-
-    if (a->has_rest_argument()) {
-      Expression_Obj rest = a->get_rest_argument()->perform(this);
-      Expression_Obj splat = SASS_MEMORY_CAST(Argument, rest)->value()->perform(this);
-
-      Sass_Separator separator = SASS_COMMA;
-      List_Ptr ls = SASS_MEMORY_CAST(List, splat);
-      Map_Ptr ms = SASS_MEMORY_CAST(Map, splat);
-
-      List_Obj arglist = SASS_MEMORY_NEW(List,
-                                      splat->pstate(),
-                                      0,
-                                      ls ? ls->separator() : separator,
-                                      true);
-
-      if (ls && ls->is_arglist()) {
-        arglist->concat(ls);
-      } else if (ms) {
-        aa->append(SASS_MEMORY_NEW(Argument, splat->pstate(), ms, "", false, true));
-      } else if (ls) {
-        arglist->concat(ls);
-      } else {
-        arglist->append(splat);
-      }
-      if (arglist->length()) {
-        aa->append(SASS_MEMORY_NEW(Argument, splat->pstate(), &arglist, "", true));
-      }
-    }
-
-    if (a->has_keyword_argument()) {
-      Expression_Obj rv = a->get_keyword_argument()->perform(this);
-      Argument_Ptr rvarg = SASS_MEMORY_CAST(Argument, rv);
-      Expression_Obj kwarg = rvarg->value()->perform(this);
-
-      aa->append(SASS_MEMORY_NEW(Argument, kwarg->pstate(), kwarg, "", false, true));
-    }
-    return aa.detach();
-  }
-
-  Expression_Ptr Eval::operator()(Comment_Ptr c)
-  {
-    return 0;
-  }
-
-  inline Expression_Ptr Eval::fallback_impl(AST_Node_Ptr n)
-  {
-    return static_cast<Expression_Ptr>(n);
-  }
-
-  // All the binary helpers.
-
-  bool Eval::eq(Expression_Obj lhs, Expression_Obj rhs)
-  {
-    // use compare operator from ast node
-    return lhs && rhs && *lhs == *rhs;
-  }
-
-  bool Eval::lt(Expression_Obj lhs, Expression_Obj rhs, std::string op)
-  {
-    Number_Obj l = SASS_MEMORY_CAST(Number, lhs);
-    Number_Obj r = SASS_MEMORY_CAST(Number, rhs);
-    // use compare operator from ast node
-    if (!l || !r) throw Exception::UndefinedOperation(&lhs, &rhs, op);
-    // use compare operator from ast node
-    return *l < *r;
-  }
-
-  Value_Ptr Eval::op_numbers(enum Sass_OP op, const Number& l, const Number& r, struct Sass_Inspect_Options opt, ParserState* pstate)
-  {
-    double lv = l.value();
-    double rv = r.value();
-    if (op == Sass_OP::DIV && rv == 0) {
-      // XXX: this is never hit via spec tests
-      return SASS_MEMORY_NEW(String_Quoted, pstate ? *pstate : l.pstate(), lv ? "Infinity" : "NaN");
-    }
-    if (op == Sass_OP::MOD && !rv) {
-      // XXX: this is never hit via spec tests
-      throw Exception::ZeroDivisionError(l, r);
-    }
-
-    Number tmp(&r); // copy
-    bool strict = op != Sass_OP::MUL && op != Sass_OP::DIV;
-    tmp.normalize(l.find_convertible_unit(), strict);
-    std::string l_unit(l.unit());
-    std::string r_unit(tmp.unit());
-    Number_Obj v = SASS_MEMORY_COPY(&l); // copy
-    v->pstate(pstate ? *pstate : l.pstate());
-    if (l_unit.empty() && (op == Sass_OP::ADD || op == Sass_OP::SUB || op == Sass_OP::MOD)) {
-      v->numerator_units() = r.numerator_units();
-      v->denominator_units() = r.denominator_units();
-    }
-
-    if (op == Sass_OP::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]);
-      }
-      for (size_t i = 0, S = r.denominator_units().size(); i < S; ++i) {
-        v->denominator_units().push_back(r.denominator_units()[i]);
-      }
-    }
-    else if (op == Sass_OP::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, r.value() * r.convert_factor(l)));
-      // v->normalize();
-      return v.detach();
-
-      v->value(ops[op](lv, tmp.value()));
-    }
-    v->normalize();
-    return v.detach();
-  }
-
-  Value_Ptr Eval::op_number_color(enum Sass_OP op, const Number& l, const Color& r, struct Sass_Inspect_Options opt, ParserState* pstate)
-  {
-    double lv = l.value();
-    switch (op) {
-      case Sass_OP::ADD:
-      case Sass_OP::MUL: {
-        return SASS_MEMORY_NEW(Color,
-                               pstate ? *pstate : l.pstate(),
-                               ops[op](lv, r.r()),
-                               ops[op](lv, r.g()),
-                               ops[op](lv, r.b()),
-                               r.a());
-      } break;
-      case Sass_OP::SUB:
-      case Sass_OP::DIV: {
-        std::string sep(op == Sass_OP::SUB ? "-" : "/");
-        std::string color(r.to_string(opt));
-        return SASS_MEMORY_NEW(String_Quoted,
-                               pstate ? *pstate : l.pstate(),
-                               l.to_string(opt)
-                               + sep
-                               + color);
-      } break;
-      case Sass_OP::MOD: {
-        throw Exception::UndefinedOperation(&l, &r, sass_op_to_name(op));
-      } break;
-      default: break; // caller should ensure that we don't get here
-    }
-    // unreachable
-    return NULL;
-  }
-
-  Value_Ptr Eval::op_color_number(enum Sass_OP op, const Color& l, const Number& r, struct Sass_Inspect_Options opt, ParserState* pstate)
-  {
-    double rv = r.value();
-    if (op == Sass_OP::DIV && !rv) {
-      // comparison of Fixnum with Float failed?
-      throw Exception::ZeroDivisionError(l, r);
-    }
-    return SASS_MEMORY_NEW(Color,
-                           pstate ? *pstate : l.pstate(),
-                           ops[op](l.r(), rv),
-                           ops[op](l.g(), rv),
-                           ops[op](l.b(), rv),
-                           l.a());
-  }
-
-  Value_Ptr Eval::op_colors(enum Sass_OP op, const Color& l, const Color& r, struct Sass_Inspect_Options opt, ParserState* pstate)
-  {
-    if (l.a() != r.a()) {
-      throw Exception::AlphaChannelsNotEqual(&l, &r, "+");
-    }
-    if (op == Sass_OP::DIV && (!r.r() || !r.g() ||!r.b())) {
-      // comparison of Fixnum with Float failed?
-      throw Exception::ZeroDivisionError(l, r);
-    }
-    return SASS_MEMORY_NEW(Color,
-                           pstate ? *pstate : l.pstate(),
-                           ops[op](l.r(), r.r()),
-                           ops[op](l.g(), r.g()),
-                           ops[op](l.b(), r.b()),
-                           l.a());
-  }
-
-  Value_Ptr Eval::op_strings(Sass::Operand operand, Value& lhs, Value& rhs, struct Sass_Inspect_Options opt, ParserState* pstate, bool delayed)
-  {
-    Expression::Concrete_Type ltype = lhs.concrete_type();
-    Expression::Concrete_Type rtype = rhs.concrete_type();
-    enum Sass_OP op = operand.operand;
-
-    String_Quoted_Ptr lqstr = dynamic_cast<String_Quoted_Ptr>(&lhs);
-    String_Quoted_Ptr rqstr = dynamic_cast<String_Quoted_Ptr>(&rhs);
-
-    std::string lstr(lqstr ? lqstr->value() : lhs.to_string(opt));
-    std::string rstr(rqstr ? rqstr->value() : rhs.to_string(opt));
-
-    if (ltype == Expression::NULL_VAL) throw Exception::InvalidNullOperation(&lhs, &rhs, sass_op_to_name(op));
-    if (rtype == Expression::NULL_VAL) throw Exception::InvalidNullOperation(&lhs, &rhs, sass_op_to_name(op));
-    if (op == Sass_OP::MOD) throw Exception::UndefinedOperation(&lhs, &rhs, sass_op_to_name(op));
-    if (op == Sass_OP::MUL) throw Exception::UndefinedOperation(&lhs, &rhs, sass_op_to_name(op));
-    std::string sep;
-    switch (op) {
-      case Sass_OP::SUB: sep = "-"; break;
-      case Sass_OP::DIV: sep = "/"; break;
-      case Sass_OP::MUL: sep = "*"; break;
-      case Sass_OP::MOD: sep = "%"; break;
-      case Sass_OP::EQ:  sep = "=="; break;
-      case Sass_OP::NEQ:  sep = "!="; break;
-      case Sass_OP::LT:  sep = "<"; break;
-      case Sass_OP::GT:  sep = ">"; break;
-      case Sass_OP::LTE:  sep = "<="; break;
-      case Sass_OP::GTE:  sep = ">="; break;
-      default:                      break;
-    }
-
-    if ( (sep == "") /* &&
-         (sep != "/" || !rqstr || !rqstr->quote_mark()) */
-    ) {
-      // create a new string that might be quoted on output (but do not unquote what we pass)
-      return SASS_MEMORY_NEW(String_Quoted, pstate ? *pstate : lhs.pstate(), lstr + rstr, 0, false, true);
-    }
-
-    if (sep != "" && !delayed) {
-      if (operand.ws_before) sep = " " + sep;
-      if (operand.ws_after) sep = sep + " ";
-    }
-
-    if (op == Sass_OP::SUB || op == Sass_OP::DIV) {
-      if (lqstr && lqstr->quote_mark()) lstr = quote(lstr);
-      if (rqstr && rqstr->quote_mark()) rstr = quote(rstr);
-    }
-
-    return SASS_MEMORY_NEW(String_Constant, pstate ? *pstate : lhs.pstate(), lstr + sep + rstr);
-  }
-
-  Expression_Ptr cval_to_astnode(union Sass_Value* v, Backtrace* backtrace, ParserState pstate)
-  {
-    using std::strlen;
-    using std::strcpy;
-    Expression_Ptr e = NULL;
-    switch (sass_value_get_tag(v)) {
-      case SASS_BOOLEAN: {
-        e = SASS_MEMORY_NEW(Boolean, pstate, !!sass_boolean_get_value(v));
-      } break;
-      case SASS_NUMBER: {
-        e = SASS_MEMORY_NEW(Number, pstate, sass_number_get_value(v), sass_number_get_unit(v));
-      } break;
-      case SASS_COLOR: {
-        e = SASS_MEMORY_NEW(Color, pstate, sass_color_get_r(v), sass_color_get_g(v), sass_color_get_b(v), sass_color_get_a(v));
-      } break;
-      case SASS_STRING: {
-        if (sass_string_is_quoted(v))
-          e = SASS_MEMORY_NEW(String_Quoted, pstate, sass_string_get_value(v));
-        else {
-          e = SASS_MEMORY_NEW(String_Constant, pstate, sass_string_get_value(v));
-        }
-      } break;
-      case SASS_LIST: {
-        List_Ptr l = SASS_MEMORY_NEW(List, pstate, sass_list_get_length(v), sass_list_get_separator(v));
-        for (size_t i = 0, L = sass_list_get_length(v); i < L; ++i) {
-          l->append(cval_to_astnode(sass_list_get_value(v, i), backtrace, pstate));
-        }
-        e = l;
-      } break;
-      case SASS_MAP: {
-        Map_Ptr m = SASS_MEMORY_NEW(Map, pstate);
-        for (size_t i = 0, L = sass_map_get_length(v); i < L; ++i) {
-          *m << std::make_pair(
-            cval_to_astnode(sass_map_get_key(v, i), backtrace, pstate),
-            cval_to_astnode(sass_map_get_value(v, i), backtrace, pstate));
-        }
-        e = m;
-      } break;
-      case SASS_NULL: {
-        e = SASS_MEMORY_NEW(Null, pstate);
-      } break;
-      case SASS_ERROR: {
-        error("Error in C function: " + std::string(sass_error_get_message(v)), pstate, backtrace);
-      } break;
-      case SASS_WARNING: {
-        error("Warning in C function: " + std::string(sass_warning_get_message(v)), pstate, backtrace);
-      } break;
-    }
-    return e;
-  }
-
-  Selector_List_Ptr Eval::operator()(Selector_List_Ptr s)
-  {
-    std::vector<Selector_List_Obj> rv;
-    Selector_List_Obj sl = SASS_MEMORY_NEW(Selector_List, s->pstate());
-    sl->is_optional(s->is_optional());
-    sl->media_block(s->media_block());
-    sl->is_optional(s->is_optional());
-    for (size_t i = 0, iL = s->length(); i < iL; ++i) {
-      rv.push_back(operator()(&(*s)[i]));
-    }
-
-    // we should actually permutate parent first
-    // but here we have permutated the selector first
-    size_t round = 0;
-    while (round != std::string::npos) {
-      bool abort = true;
-      for (size_t i = 0, iL = rv.size(); i < iL; ++i) {
-        if (rv[i]->length() > round) {
-          sl->append((*rv[i])[round]);
-          abort = false;
-        }
-      }
-      if (abort) {
-        round = std::string::npos;
-      } else {
-        ++ round;
-      }
-
-    }
-    return sl.detach();
-  }
-
-
-  Selector_List_Ptr Eval::operator()(Complex_Selector_Ptr s)
-  {
-    bool implicit_parent = !exp.old_at_root_without_rule;
-    return s->resolve_parent_refs(ctx, exp.selector_stack, implicit_parent);
-  }
-
-  // XXX: this is never hit via spec tests
-  Attribute_Selector_Ptr Eval::operator()(Attribute_Selector_Ptr s)
-  {
-    String_Obj attr = s->value();
-    if (attr) { attr = static_cast<String_Ptr>(attr->perform(this)); }
-    Attribute_Selector_Ptr ss = SASS_MEMORY_COPY(s);
-    ss->value(attr);
-    return ss;
-  }
-
-  Selector_List_Ptr Eval::operator()(Selector_Schema_Ptr s)
-  {
-    // the parser will look for a brace to end the selector
-    Expression_Obj sel = s->contents()->perform(this);
-    std::string result_str(sel->to_string(ctx.c_options));
-    result_str = unquote(Util::rtrim(result_str)) + "\n{";
-    Parser p = Parser::from_c_str(result_str.c_str(), ctx, s->pstate());
-    p.last_media_block = s->media_block();
-    Selector_List_Obj sl = p.parse_selector_list(exp.block_stack.back()->is_root());
-    if (s->has_parent_ref()) sl->remove_parent_selectors();
-    return operator()(&sl);
-  }
-
-  Expression_Ptr Eval::operator()(Parent_Selector_Ptr p)
-  {
-    if (Selector_List_Obj pr = selector()) {
-      exp.selector_stack.pop_back();
-      Selector_List_Obj rv = operator()(&pr);
-      exp.selector_stack.push_back(rv);
-      return rv.detach();
-    } else {
-      return SASS_MEMORY_NEW(Null, p->pstate());
-    }
-  }
+#include "operators.hpp"
+#include "environment.hpp"
+#include "position.hpp"
+#include "sass/values.h"
+#include "to_value.hpp"
+#include "to_c.hpp"
+#include "context.hpp"
+#include "backtrace.hpp"
+#include "lexer.hpp"
+#include "prelexer.hpp"
+#include "parser.hpp"
+#include "expand.hpp"
+#include "color_maps.hpp"
+#include "sass_functions.hpp"
+
+namespace Sass {
+
+  Eval::Eval(Expand& exp)
+  : exp(exp),
+    ctx(exp.ctx),
+    traces(exp.traces),
+    force(false),
+    is_in_comment(false),
+    is_in_selector_schema(false)
+  {
+    bool_true = SASS_MEMORY_NEW(Boolean, "[NA]", true);
+    bool_false = SASS_MEMORY_NEW(Boolean, "[NA]", false);
+  }
+  Eval::~Eval() { }
+
+  Env* Eval::environment()
+  {
+    return exp.environment();
+  }
+
+  Selector_List_Obj Eval::selector()
+  {
+    return exp.selector();
+  }
+
+  Expression_Ptr Eval::operator()(Block_Ptr b)
+  {
+    Expression_Ptr val = 0;
+    for (size_t i = 0, L = b->length(); i < L; ++i) {
+      val = b->at(i)->perform(this);
+      if (val) return val;
+    }
+    return val;
+  }
+
+  Expression_Ptr Eval::operator()(Assignment_Ptr a)
+  {
+    Env* env = exp.environment();
+    std::string var(a->variable());
+    if (a->is_global()) {
+      if (a->is_default()) {
+        if (env->has_global(var)) {
+          Expression_Ptr e = 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 {
+        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_Obj node = cur->get_local(var)) {
+              Expression_Ptr e = Cast<Expression>(node);
+              if (!e || e->concrete_type() == Expression::NULL_VAL) {
+                cur->set_local(var, a->value()->perform(this));
+              }
+            }
+            else {
+              throw std::runtime_error("Env not in sync");
+            }
+            return 0;
+          }
+          cur = cur->parent();
+        }
+        throw std::runtime_error("Env not in sync");
+      }
+      else if (env->has_global(var)) {
+        if (AST_Node_Obj node = env->get_global(var)) {
+          Expression_Ptr e = 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));
+    }
+    return 0;
+  }
+
+  Expression_Ptr Eval::operator()(If_Ptr i)
+  {
+    Expression_Obj rv = 0;
+    Env env(exp.environment());
+    exp.env_stack.push_back(&env);
+    Expression_Obj cond = i->predicate()->perform(this);
+    if (!cond->is_false()) {
+      rv = i->block()->perform(this);
+    }
+    else {
+      Block_Obj alt = i->alternative();
+      if (alt) rv = alt->perform(this);
+    }
+    exp.env_stack.pop_back();
+    return rv.detach();
+  }
+
+  // For does not create a new env scope
+  // But iteration vars are reset afterwards
+  Expression_Ptr Eval::operator()(For_Ptr f)
+  {
+    std::string variable(f->variable());
+    Expression_Obj low = f->lower_bound()->perform(this);
+    if (low->concrete_type() != Expression::NUMBER) {
+      traces.push_back(Backtrace(low->pstate()));
+      throw Exception::TypeMismatch(traces, *low, "integer");
+    }
+    Expression_Obj high = f->upper_bound()->perform(this);
+    if (high->concrete_type() != Expression::NUMBER) {
+      traces.push_back(Backtrace(high->pstate()));
+      throw Exception::TypeMismatch(traces, *high, "integer");
+    }
+    Number_Obj sass_start = Cast<Number>(low);
+    Number_Obj sass_end = Cast<Number>(high);
+    // check if units are valid for sequence
+    if (sass_start->unit() != sass_end->unit()) {
+      std::stringstream msg; msg << "Incompatible units: '"
+        << sass_end->unit() << "' and '"
+        << sass_start->unit() << "'.";
+      error(msg.str(), low->pstate(), traces);
+    }
+    double start = sass_start->value();
+    double end = sass_end->value();
+    // only create iterator once in this environment
+    Env env(environment(), true);
+    exp.env_stack.push_back(&env);
+    Block_Obj body = f->block();
+    Expression_Ptr val = 0;
+    if (start < end) {
+      if (f->is_inclusive()) ++end;
+      for (double i = start;
+           i < end;
+           ++i) {
+        Number_Obj it = SASS_MEMORY_NEW(Number, low->pstate(), i, sass_end->unit());
+        env.set_local(variable, it);
+        val = body->perform(this);
+        if (val) break;
+      }
+    } else {
+      if (f->is_inclusive()) --end;
+      for (double i = start;
+           i > end;
+           --i) {
+        Number_Obj it = SASS_MEMORY_NEW(Number, low->pstate(), i, sass_end->unit());
+        env.set_local(variable, it);
+        val = body->perform(this);
+        if (val) break;
+      }
+    }
+    exp.env_stack.pop_back();
+    return val;
+  }
+
+  // Eval does not create a new env scope
+  // But iteration vars are reset afterwards
+  Expression_Ptr Eval::operator()(Each_Ptr e)
+  {
+    std::vector<std::string> variables(e->variables());
+    Expression_Obj expr = e->list()->perform(this);
+    Env env(environment(), true);
+    exp.env_stack.push_back(&env);
+    List_Obj list = 0;
+    Map_Ptr map = 0;
+    if (expr->concrete_type() == Expression::MAP) {
+      map = Cast<Map>(expr);
+    }
+    else if (Selector_List_Ptr ls = Cast<Selector_List>(expr)) {
+      Listize listize;
+      Expression_Obj rv = ls->perform(&listize);
+      list = Cast<List>(rv);
+    }
+    else if (expr->concrete_type() != Expression::LIST) {
+      list = SASS_MEMORY_NEW(List, expr->pstate(), 1, SASS_COMMA);
+      list->append(expr);
+    }
+    else {
+      list = Cast<List>(expr);
+    }
+
+    Block_Obj body = e->block();
+    Expression_Obj val = 0;
+
+    if (map) {
+      for (Expression_Obj key : map->keys()) {
+        Expression_Obj value = map->at(key);
+
+        if (variables.size() == 1) {
+          List_Ptr variable = SASS_MEMORY_NEW(List, map->pstate(), 2, SASS_SPACE);
+          variable->append(key);
+          variable->append(value);
+          env.set_local(variables[0], variable);
+        } else {
+          env.set_local(variables[0], key);
+          env.set_local(variables[1], value);
+        }
+
+        val = body->perform(this);
+        if (val) break;
+      }
+    }
+    else {
+      if (list->length() == 1 && Cast<Selector_List>(list)) {
+        list = Cast<List>(list);
+      }
+      for (size_t i = 0, L = list->length(); i < L; ++i) {
+        Expression_Ptr item = list->at(i);
+        // unwrap value if the expression is an argument
+        if (Argument_Ptr arg = Cast<Argument>(item)) item = arg->value();
+        // check if we got passed a list of args (investigate)
+        if (List_Ptr scalars = Cast<List>(item)) {
+          if (variables.size() == 1) {
+            Expression_Ptr var = scalars;
+            env.set_local(variables[0], var);
+          } else {
+            // XXX: this is never hit via spec tests
+            for (size_t j = 0, K = variables.size(); j < K; ++j) {
+              Expression_Ptr res = j >= scalars->length()
+                ? SASS_MEMORY_NEW(Null, expr->pstate())
+                : scalars->at(j);
+              env.set_local(variables[j], res);
+            }
+          }
+        } else {
+          if (variables.size() > 0) {
+            env.set_local(variables.at(0), item);
+            for (size_t j = 1, K = variables.size(); j < K; ++j) {
+              // XXX: this is never hit via spec tests
+              Expression_Ptr res = SASS_MEMORY_NEW(Null, expr->pstate());
+              env.set_local(variables[j], res);
+            }
+          }
+        }
+        val = body->perform(this);
+        if (val) break;
+      }
+    }
+    exp.env_stack.pop_back();
+    return val.detach();
+  }
+
+  Expression_Ptr Eval::operator()(While_Ptr w)
+  {
+    Expression_Obj pred = w->predicate();
+    Block_Obj body = w->block();
+    Env env(environment(), true);
+    exp.env_stack.push_back(&env);
+    Expression_Obj cond = pred->perform(this);
+    while (!cond->is_false()) {
+      Expression_Obj val = body->perform(this);
+      if (val) {
+        exp.env_stack.pop_back();
+        return val.detach();
+      }
+      cond = pred->perform(this);
+    }
+    exp.env_stack.pop_back();
+    return 0;
+  }
+
+  Expression_Ptr Eval::operator()(Return_Ptr r)
+  {
+    return r->value()->perform(this);
+  }
+
+  Expression_Ptr Eval::operator()(Warning_Ptr w)
+  {
+    Sass_Output_Style outstyle = ctx.c_options.output_style;
+    ctx.c_options.output_style = NESTED;
+    Expression_Obj message = w->message()->perform(this);
+    Env* env = exp.environment();
+
+    // try to use generic function
+    if (env->has("@warn[f]")) {
+
+      // add call stack entry
+      ctx.callee_stack.push_back({
+        "@warn",
+        w->pstate().path,
+        w->pstate().line + 1,
+        w->pstate().column + 1,
+        SASS_CALLEE_FUNCTION,
+        { env }
+      });
+
+      Definition_Ptr def = Cast<Definition>((*env)["@warn[f]"]);
+      // Block_Obj          body   = def->block();
+      // Native_Function func   = def->native_function();
+      Sass_Function_Entry c_function = def->c_function();
+      Sass_Function_Fn c_func = sass_function_get_function(c_function);
+
+      To_C to_c;
+      union Sass_Value* c_args = sass_make_list(1, SASS_COMMA, false);
+      sass_list_set_value(c_args, 0, message->perform(&to_c));
+      union Sass_Value* c_val = c_func(c_args, c_function, ctx.c_compiler);
+      ctx.c_options.output_style = outstyle;
+      ctx.callee_stack.pop_back();
+      sass_delete_value(c_args);
+      sass_delete_value(c_val);
+      return 0;
+
+    }
+
+    std::string result(unquote(message->to_sass()));
+    std::cerr << "WARNING: " << result << std::endl;
+    traces.push_back(Backtrace(w->pstate()));
+    std::cerr << traces_to_string(traces, "         ");
+    std::cerr << std::endl;
+    ctx.c_options.output_style = outstyle;
+    traces.pop_back();
+    return 0;
+  }
+
+  Expression_Ptr Eval::operator()(Error_Ptr e)
+  {
+    Sass_Output_Style outstyle = ctx.c_options.output_style;
+    ctx.c_options.output_style = NESTED;
+    Expression_Obj message = e->message()->perform(this);
+    Env* env = exp.environment();
+
+    // try to use generic function
+    if (env->has("@error[f]")) {
+
+      // add call stack entry
+      ctx.callee_stack.push_back({
+        "@error",
+        e->pstate().path,
+        e->pstate().line + 1,
+        e->pstate().column + 1,
+        SASS_CALLEE_FUNCTION,
+        { env }
+      });
+
+      Definition_Ptr def = Cast<Definition>((*env)["@error[f]"]);
+      // Block_Obj          body   = def->block();
+      // Native_Function func   = def->native_function();
+      Sass_Function_Entry c_function = def->c_function();
+      Sass_Function_Fn c_func = sass_function_get_function(c_function);
+
+      To_C to_c;
+      union Sass_Value* c_args = sass_make_list(1, SASS_COMMA, false);
+      sass_list_set_value(c_args, 0, message->perform(&to_c));
+      union Sass_Value* c_val = c_func(c_args, c_function, ctx.c_compiler);
+      ctx.c_options.output_style = outstyle;
+      ctx.callee_stack.pop_back();
+      sass_delete_value(c_args);
+      sass_delete_value(c_val);
+      return 0;
+
+    }
+
+    std::string result(unquote(message->to_sass()));
+    ctx.c_options.output_style = outstyle;
+    error(result, e->pstate(), traces);
+    return 0;
+  }
+
+  Expression_Ptr Eval::operator()(Debug_Ptr d)
+  {
+    Sass_Output_Style outstyle = ctx.c_options.output_style;
+    ctx.c_options.output_style = NESTED;
+    Expression_Obj message = d->value()->perform(this);
+    Env* env = exp.environment();
+
+    // try to use generic function
+    if (env->has("@debug[f]")) {
+
+      // add call stack entry
+      ctx.callee_stack.push_back({
+        "@debug",
+        d->pstate().path,
+        d->pstate().line + 1,
+        d->pstate().column + 1,
+        SASS_CALLEE_FUNCTION,
+        { env }
+      });
+
+      Definition_Ptr def = Cast<Definition>((*env)["@debug[f]"]);
+      // Block_Obj          body   = def->block();
+      // Native_Function func   = def->native_function();
+      Sass_Function_Entry c_function = def->c_function();
+      Sass_Function_Fn c_func = sass_function_get_function(c_function);
+
+      To_C to_c;
+      union Sass_Value* c_args = sass_make_list(1, SASS_COMMA, false);
+      sass_list_set_value(c_args, 0, message->perform(&to_c));
+      union Sass_Value* c_val = c_func(c_args, c_function, ctx.c_compiler);
+      ctx.c_options.output_style = outstyle;
+      ctx.callee_stack.pop_back();
+      sass_delete_value(c_args);
+      sass_delete_value(c_val);
+      return 0;
+
+    }
+
+    std::string cwd(ctx.cwd());
+    std::string result(unquote(message->to_sass()));
+    std::string abs_path(Sass::File::rel2abs(d->pstate().path, cwd, cwd));
+    std::string rel_path(Sass::File::abs2rel(d->pstate().path, cwd, cwd));
+    std::string output_path(Sass::File::path_for_console(rel_path, abs_path, d->pstate().path));
+    ctx.c_options.output_style = outstyle;
+
+    std::cerr << output_path << ":" << d->pstate().line+1 << " DEBUG: " << result;
+    std::cerr << std::endl;
+    return 0;
+  }
+
+  Expression_Ptr Eval::operator()(List_Ptr l)
+  {
+    // special case for unevaluated map
+    if (l->separator() == SASS_HASH) {
+      Map_Obj lm = SASS_MEMORY_NEW(Map,
+                                l->pstate(),
+                                l->length() / 2);
+      for (size_t i = 0, L = l->length(); i < L; i += 2)
+      {
+        Expression_Obj key = (*l)[i+0]->perform(this);
+        Expression_Obj val = (*l)[i+1]->perform(this);
+        // make sure the color key never displays its real name
+        key->is_delayed(true); // verified
+        *lm << std::make_pair(key, val);
+      }
+      if (lm->has_duplicate_key()) {
+        traces.push_back(Backtrace(l->pstate()));
+        throw Exception::DuplicateKeyError(traces, *lm, *l);
+      }
+
+      lm->is_interpolant(l->is_interpolant());
+      return lm->perform(this);
+    }
+    // check if we should expand it
+    if (l->is_expanded()) return l;
+    // regular case for unevaluated lists
+    List_Obj ll = SASS_MEMORY_NEW(List,
+                               l->pstate(),
+                               l->length(),
+                               l->separator(),
+                               l->is_arglist(),
+                               l->is_bracketed());
+    for (size_t i = 0, L = l->length(); i < L; ++i) {
+      ll->append((*l)[i]->perform(this));
+    }
+    ll->is_interpolant(l->is_interpolant());
+    ll->from_selector(l->from_selector());
+    ll->is_expanded(true);
+    return ll.detach();
+  }
+
+  Expression_Ptr Eval::operator()(Map_Ptr m)
+  {
+    if (m->is_expanded()) return m;
+
+    // make sure we're not starting with duplicate keys.
+    // the duplicate key state will have been set in the parser phase.
+    if (m->has_duplicate_key()) {
+      traces.push_back(Backtrace(m->pstate()));
+      throw Exception::DuplicateKeyError(traces, *m, *m);
+    }
+
+    Map_Obj mm = SASS_MEMORY_NEW(Map,
+                                m->pstate(),
+                                m->length());
+    for (auto key : m->keys()) {
+      Expression_Ptr ex_key = key->perform(this);
+      Expression_Ptr ex_val = m->at(key);
+      if (ex_val == NULL) continue;
+      ex_val = ex_val->perform(this);
+      *mm << std::make_pair(ex_key, ex_val);
+    }
+
+    // check the evaluated keys aren't duplicates.
+    if (mm->has_duplicate_key()) {
+      traces.push_back(Backtrace(m->pstate()));
+      throw Exception::DuplicateKeyError(traces, *mm, *m);
+    }
+
+    mm->is_expanded(true);
+    return mm.detach();
+  }
+
+  Expression_Ptr Eval::operator()(Binary_Expression_Ptr b_in)
+  {
+
+    Expression_Obj lhs = b_in->left();
+    Expression_Obj rhs = b_in->right();
+    enum Sass_OP op_type = b_in->optype();
+
+    if (op_type == Sass_OP::AND) {
+      // LOCAL_FLAG(force, true);
+      lhs = lhs->perform(this);
+      if (!*lhs) return lhs.detach();
+      return rhs->perform(this);
+    }
+    else if (op_type == Sass_OP::OR) {
+      // LOCAL_FLAG(force, true);
+      lhs = lhs->perform(this);
+      if (*lhs) return lhs.detach();
+      return rhs->perform(this);
+    }
+
+    // Evaluate variables as early o
+    while (Variable_Ptr l_v = Cast<Variable>(lhs)) {
+      lhs = operator()(l_v);
+    }
+    while (Variable_Ptr r_v = Cast<Variable>(rhs)) {
+      rhs = operator()(r_v);
+    }
+
+    Binary_Expression_Obj b = b_in;
+
+    // Evaluate sub-expressions early on
+    while (Binary_Expression_Ptr l_b = Cast<Binary_Expression>(lhs)) {
+      if (!force && l_b->is_delayed()) break;
+      lhs = operator()(l_b);
+    }
+    while (Binary_Expression_Ptr r_b = Cast<Binary_Expression>(rhs)) {
+      if (!force && r_b->is_delayed()) break;
+      rhs = operator()(r_b);
+    }
+
+    // don't eval delayed expressions (the '/' when used as a separator)
+    if (!force && op_type == Sass_OP::DIV && b->is_delayed()) {
+      b->right(b->right()->perform(this));
+      b->left(b->left()->perform(this));
+      return b.detach();
+    }
+
+    // specific types we know are final
+    // handle them early to avoid overhead
+    if (Number_Ptr l_n = Cast<Number>(lhs)) {
+      // lhs is number and rhs is number
+      if (Number_Ptr r_n = Cast<Number>(rhs)) {
+        try {
+          switch (op_type) {
+            case Sass_OP::EQ: return *l_n == *r_n ? bool_true : bool_false;
+            case Sass_OP::NEQ: return *l_n == *r_n ? bool_false : bool_true;
+            case Sass_OP::LT: return *l_n < *r_n ? bool_true : bool_false;
+            case Sass_OP::GTE: return *l_n < *r_n ? bool_false : bool_true;
+            case Sass_OP::LTE: return *l_n < *r_n || *l_n == *r_n ? bool_true : bool_false;
+            case Sass_OP::GT: return *l_n < *r_n || *l_n == *r_n ? bool_false : bool_true;
+            case Sass_OP::ADD: case Sass_OP::SUB: case Sass_OP::MUL: case Sass_OP::DIV: case Sass_OP::MOD:
+              return Operators::op_numbers(op_type, *l_n, *r_n, ctx.c_options, b_in->pstate());
+            default: break;
+          }
+        }
+        catch (Exception::OperationError& err)
+        {
+          traces.push_back(Backtrace(b_in->pstate()));
+          throw Exception::SassValueError(traces, b_in->pstate(), err);
+        }
+      }
+      // lhs is number and rhs is color
+      else if (Color_Ptr r_c = Cast<Color>(rhs)) {
+        try {
+          switch (op_type) {
+            case Sass_OP::EQ: return *l_n == *r_c ? bool_true : bool_false;
+            case Sass_OP::NEQ: return *l_n == *r_c ? bool_false : bool_true;
+            case Sass_OP::LT: return *l_n < *r_c ? bool_true : bool_false;
+            case Sass_OP::GTE: return *l_n < *r_c ? bool_false : bool_true;
+            case Sass_OP::LTE: return *l_n < *r_c || *l_n == *r_c ? bool_true : bool_false;
+            case Sass_OP::GT: return *l_n < *r_c || *l_n == *r_c ? bool_false : bool_true;
+            case Sass_OP::ADD: case Sass_OP::SUB: case Sass_OP::MUL: case Sass_OP::DIV: case Sass_OP::MOD:
+              return Operators::op_number_color(op_type, *l_n, *r_c, ctx.c_options, b_in->pstate());
+            default: break;
+          }
+        }
+        catch (Exception::OperationError& err)
+        {
+          traces.push_back(Backtrace(b_in->pstate()));
+          throw Exception::SassValueError(traces, b_in->pstate(), err);
+        }
+      }
+    }
+    else if (Color_Ptr l_c = Cast<Color>(lhs)) {
+      // lhs is color and rhs is color
+      if (Color_Ptr r_c = Cast<Color>(rhs)) {
+        try {
+          switch (op_type) {
+            case Sass_OP::EQ: return *l_c == *r_c ? bool_true : bool_false;
+            case Sass_OP::NEQ: return *l_c == *r_c ? bool_false : bool_true;
+            case Sass_OP::LT: return *l_c < *r_c ? bool_true : bool_false;
+            case Sass_OP::GTE: return *l_c < *r_c ? bool_false : bool_true;
+            case Sass_OP::LTE: return *l_c < *r_c || *l_c == *r_c ? bool_true : bool_false;
+            case Sass_OP::GT: return *l_c < *r_c || *l_c == *r_c ? bool_false : bool_true;
+            case Sass_OP::ADD: case Sass_OP::SUB: case Sass_OP::MUL: case Sass_OP::DIV: case Sass_OP::MOD:
+              return Operators::op_colors(op_type, *l_c, *r_c, ctx.c_options, b_in->pstate());
+            default: break;
+          }
+        }
+        catch (Exception::OperationError& err)
+        {
+          traces.push_back(Backtrace(b_in->pstate()));
+          throw Exception::SassValueError(traces, b_in->pstate(), err);
+        }
+      }
+      // lhs is color and rhs is number
+      else if (Number_Ptr r_n = Cast<Number>(rhs)) {
+        try {
+          switch (op_type) {
+            case Sass_OP::EQ: return *l_c == *r_n ? bool_true : bool_false;
+            case Sass_OP::NEQ: return *l_c == *r_n ? bool_false : bool_true;
+            case Sass_OP::LT: return *l_c < *r_n ? bool_true : bool_false;
+            case Sass_OP::GTE: return *l_c < *r_n ? bool_false : bool_true;
+            case Sass_OP::LTE: return *l_c < *r_n || *l_c == *r_n ? bool_true : bool_false;
+            case Sass_OP::GT: return *l_c < *r_n || *l_c == *r_n ? bool_false : bool_true;
+            case Sass_OP::ADD: case Sass_OP::SUB: case Sass_OP::MUL: case Sass_OP::DIV: case Sass_OP::MOD:
+              return Operators::op_color_number(op_type, *l_c, *r_n, ctx.c_options, b_in->pstate());
+            default: break;
+          }
+        }
+        catch (Exception::OperationError& err)
+        {
+          traces.push_back(Backtrace(b_in->pstate()));
+          throw Exception::SassValueError(traces, b_in->pstate(), err);
+        }
+      }
+    }
+
+    String_Schema_Obj ret_schema;
+
+    // only the last item will be used to eval the binary expression
+    if (String_Schema_Ptr s_l = Cast<String_Schema>(b->left())) {
+      if (!s_l->has_interpolant() && (!s_l->is_right_interpolant())) {
+        ret_schema = SASS_MEMORY_NEW(String_Schema, b->pstate());
+        Binary_Expression_Obj bin_ex = SASS_MEMORY_NEW(Binary_Expression, b->pstate(),
+                                                    b->op(), s_l->last(), b->right());
+        bin_ex->is_delayed(b->left()->is_delayed() || b->right()->is_delayed()); // unverified
+        for (size_t i = 0; i < s_l->length() - 1; ++i) {
+          ret_schema->append(s_l->at(i)->perform(this));
+        }
+        ret_schema->append(bin_ex->perform(this));
+        return ret_schema->perform(this);
+      }
+    }
+    if (String_Schema_Ptr s_r = Cast<String_Schema>(b->right())) {
+
+      if (!s_r->has_interpolant() && (!s_r->is_left_interpolant() || op_type == Sass_OP::DIV)) {
+        ret_schema = SASS_MEMORY_NEW(String_Schema, b->pstate());
+        Binary_Expression_Obj bin_ex = SASS_MEMORY_NEW(Binary_Expression, b->pstate(),
+                                                    b->op(), b->left(), s_r->first());
+        bin_ex->is_delayed(b->left()->is_delayed() || b->right()->is_delayed()); // verified
+        ret_schema->append(bin_ex->perform(this));
+        for (size_t i = 1; i < s_r->length(); ++i) {
+          ret_schema->append(s_r->at(i)->perform(this));
+        }
+        return ret_schema->perform(this);
+      }
+    }
+
+    // fully evaluate their values
+    if (op_type == Sass_OP::EQ ||
+        op_type == Sass_OP::NEQ ||
+        op_type == Sass_OP::GT ||
+        op_type == Sass_OP::GTE ||
+        op_type == Sass_OP::LT ||
+        op_type == Sass_OP::LTE)
+    {
+      LOCAL_FLAG(force, true);
+      lhs->is_expanded(false);
+      lhs->set_delayed(false);
+      lhs = lhs->perform(this);
+      rhs->is_expanded(false);
+      rhs->set_delayed(false);
+      rhs = rhs->perform(this);
+    }
+    else {
+      lhs = lhs->perform(this);
+    }
+
+    // not a logical connective, so go ahead and eval the rhs
+    rhs = rhs->perform(this);
+    AST_Node_Obj lu = lhs;
+    AST_Node_Obj ru = rhs;
+
+    Expression::Concrete_Type l_type;
+    Expression::Concrete_Type r_type;
+
+    // Is one of the operands an interpolant?
+    String_Schema_Obj s1 = Cast<String_Schema>(b->left());
+    String_Schema_Obj s2 = Cast<String_Schema>(b->right());
+    Binary_Expression_Obj b1 = Cast<Binary_Expression>(b->left());
+    Binary_Expression_Obj b2 = Cast<Binary_Expression>(b->right());
+
+    bool schema_op = false;
+
+    bool force_delay = (s2 && s2->is_left_interpolant()) ||
+                       (s1 && s1->is_right_interpolant()) ||
+                       (b1 && b1->is_right_interpolant()) ||
+                       (b2 && b2->is_left_interpolant());
+
+    if ((s1 && s1->has_interpolants()) || (s2 && s2->has_interpolants()) || force_delay)
+    {
+      if (op_type == Sass_OP::DIV || op_type == Sass_OP::MUL || op_type == Sass_OP::MOD || op_type == Sass_OP::ADD || op_type == Sass_OP::SUB ||
+          op_type == Sass_OP::EQ) {
+        // If possible upgrade LHS to a number (for number to string compare)
+        if (String_Constant_Ptr str = Cast<String_Constant>(lhs)) {
+          std::string value(str->value());
+          const char* start = value.c_str();
+          if (Prelexer::sequence < Prelexer::dimension, Prelexer::end_of_file >(start) != 0) {
+            lhs = Parser::lexed_dimension(b->pstate(), str->value());
+          }
+        }
+        // If possible upgrade RHS to a number (for string to number compare)
+        if (String_Constant_Ptr str = Cast<String_Constant>(rhs)) {
+          std::string value(str->value());
+          const char* start = value.c_str();
+          if (Prelexer::sequence < Prelexer::dimension, Prelexer::number >(start) != 0) {
+            rhs = Parser::lexed_dimension(b->pstate(), str->value());
+          }
+        }
+      }
+
+      To_Value to_value(ctx);
+      Value_Obj v_l = Cast<Value>(lhs->perform(&to_value));
+      Value_Obj v_r = Cast<Value>(rhs->perform(&to_value));
+
+      if (force_delay) {
+        std::string str("");
+        str += v_l->to_string(ctx.c_options);
+        if (b->op().ws_before) str += " ";
+        str += b->separator();
+        if (b->op().ws_after) str += " ";
+        str += v_r->to_string(ctx.c_options);
+        String_Constant_Ptr val = SASS_MEMORY_NEW(String_Constant, b->pstate(), str);
+        val->is_interpolant(b->left()->has_interpolant());
+        return val;
+      }
+    }
+
+    // see if it's a relational expression
+    try {
+      switch(op_type) {
+        case Sass_OP::EQ:  return SASS_MEMORY_NEW(Boolean, b->pstate(), Operators::eq(lhs, rhs));
+        case Sass_OP::NEQ: return SASS_MEMORY_NEW(Boolean, b->pstate(), Operators::neq(lhs, rhs));
+        case Sass_OP::GT:  return SASS_MEMORY_NEW(Boolean, b->pstate(), Operators::gt(lhs, rhs));
+        case Sass_OP::GTE: return SASS_MEMORY_NEW(Boolean, b->pstate(), Operators::gte(lhs, rhs));
+        case Sass_OP::LT:  return SASS_MEMORY_NEW(Boolean, b->pstate(), Operators::lt(lhs, rhs));
+        case Sass_OP::LTE: return SASS_MEMORY_NEW(Boolean, b->pstate(), Operators::lte(lhs, rhs));
+        default: break;
+      }
+    }
+    catch (Exception::OperationError& err)
+    {
+      // throw Exception::Base(b->pstate(), err.what());
+      traces.push_back(Backtrace(b->pstate()));
+      throw Exception::SassValueError(traces, b->pstate(), err);
+    }
+
+    l_type = lhs->concrete_type();
+    r_type = rhs->concrete_type();
+
+    // ToDo: throw error in op functions
+    // ToDo: then catch and re-throw them
+    Expression_Obj rv;
+    try {
+      ParserState pstate(b->pstate());
+      if (l_type == Expression::NUMBER && r_type == Expression::NUMBER) {
+        Number_Ptr l_n = Cast<Number>(lhs);
+        Number_Ptr r_n = Cast<Number>(rhs);
+        l_n->reduce(); r_n->reduce();
+        rv = Operators::op_numbers(op_type, *l_n, *r_n, ctx.c_options, pstate);
+      }
+      else if (l_type == Expression::NUMBER && r_type == Expression::COLOR) {
+        Number_Ptr l_n = Cast<Number>(lhs);
+        Color_Ptr r_c = Cast<Color>(rhs);
+        rv = Operators::op_number_color(op_type, *l_n, *r_c, ctx.c_options, pstate);
+      }
+      else if (l_type == Expression::COLOR && r_type == Expression::NUMBER) {
+        Color_Ptr l_c = Cast<Color>(lhs);
+        Number_Ptr r_n = Cast<Number>(rhs);
+        rv = Operators::op_color_number(op_type, *l_c, *r_n, ctx.c_options, pstate);
+      }
+      else if (l_type == Expression::COLOR && r_type == Expression::COLOR) {
+        Color_Ptr l_c = Cast<Color>(lhs);
+        Color_Ptr r_c = Cast<Color>(rhs);
+        rv = Operators::op_colors(op_type, *l_c, *r_c, ctx.c_options, pstate);
+      }
+      else {
+        To_Value to_value(ctx);
+        // this will leak if perform does not return a value!
+        Value_Obj v_l = Cast<Value>(lhs->perform(&to_value));
+        Value_Obj v_r = Cast<Value>(rhs->perform(&to_value));
+        bool interpolant = b->is_right_interpolant() ||
+                           b->is_left_interpolant() ||
+                           b->is_interpolant();
+        if (op_type == Sass_OP::SUB) interpolant = false;
+        // if (op_type == Sass_OP::DIV) interpolant = true;
+        // check for type violations
+        if (l_type == Expression::MAP || l_type == Expression::FUNCTION_VAL) {
+          traces.push_back(Backtrace(v_l->pstate()));
+          throw Exception::InvalidValue(traces, *v_l);
+        }
+        if (r_type == Expression::MAP || l_type == Expression::FUNCTION_VAL) {
+          traces.push_back(Backtrace(v_r->pstate()));
+          throw Exception::InvalidValue(traces, *v_r);
+        }
+        Value_Ptr ex = Operators::op_strings(b->op(), *v_l, *v_r, ctx.c_options, pstate, !interpolant); // pass true to compress
+        if (String_Constant_Ptr str = Cast<String_Constant>(ex))
+        {
+          if (str->concrete_type() == Expression::STRING)
+          {
+            String_Constant_Ptr lstr = Cast<String_Constant>(lhs);
+            String_Constant_Ptr rstr = Cast<String_Constant>(rhs);
+            if (op_type != Sass_OP::SUB) {
+              if (String_Constant_Ptr org = lstr ? lstr : rstr)
+              { str->quote_mark(org->quote_mark()); }
+            }
+          }
+        }
+        ex->is_interpolant(b->is_interpolant());
+        rv = ex;
+      }
+    }
+    catch (Exception::OperationError& err)
+    {
+      traces.push_back(Backtrace(b->pstate()));
+      // throw Exception::Base(b->pstate(), err.what());
+      throw Exception::SassValueError(traces, b->pstate(), err);
+    }
+
+    if (rv) {
+      if (schema_op) {
+        // XXX: this is never hit via spec tests
+        (*s2)[0] = rv;
+        rv = s2->perform(this);
+      }
+    }
+
+    return rv.detach();
+
+  }
+
+  Expression_Ptr Eval::operator()(Unary_Expression_Ptr u)
+  {
+    Expression_Obj operand = u->operand()->perform(this);
+    if (u->optype() == Unary_Expression::NOT) {
+      Boolean_Ptr result = SASS_MEMORY_NEW(Boolean, u->pstate(), (bool)*operand);
+      result->value(!result->value());
+      return result;
+    }
+    else if (Number_Obj nr = Cast<Number>(operand)) {
+      // negate value for minus unary expression
+      if (u->optype() == Unary_Expression::MINUS) {
+        Number_Obj cpy = SASS_MEMORY_COPY(nr);
+        cpy->value( - cpy->value() ); // negate value
+        return cpy.detach(); // return the copy
+      }
+      else if (u->optype() == Unary_Expression::SLASH) {
+        std::string str = '/' + nr->to_string(ctx.c_options);
+        return SASS_MEMORY_NEW(String_Constant, u->pstate(), str);
+      }
+      // nothing for positive
+      return nr.detach();
+    }
+    else {
+      // Special cases: +/- variables which evaluate to null ouput just +/-,
+      // but +/- null itself outputs the string
+      if (operand->concrete_type() == Expression::NULL_VAL && Cast<Variable>(u->operand())) {
+        u->operand(SASS_MEMORY_NEW(String_Quoted, u->pstate(), ""));
+      }
+      // Never apply unary opertions on colors @see #2140
+      else if (Color_Ptr color = Cast<Color>(operand)) {
+        // Use the color name if this was eval with one
+        if (color->disp().length() > 0) {
+          operand = SASS_MEMORY_NEW(String_Constant, operand->pstate(), color->disp());
+          u->operand(operand);
+        }
+      }
+      else {
+        u->operand(operand);
+      }
+
+      return SASS_MEMORY_NEW(String_Quoted,
+                             u->pstate(),
+                             u->inspect());
+    }
+    // unreachable
+    return u;
+  }
+
+  Expression_Ptr Eval::operator()(Function_Call_Ptr c)
+  {
+    if (traces.size() > Constants::MaxCallStack) {
+        // XXX: this is never hit via spec tests
+        std::ostringstream stm;
+        stm << "Stack depth exceeded max of " << Constants::MaxCallStack;
+        error(stm.str(), c->pstate(), traces);
+    }
+    std::string name(Util::normalize_underscores(c->name()));
+    std::string full_name(name + "[f]");
+    // we make a clone here, need to implement that further
+    Arguments_Obj args = c->arguments();
+
+    Env* env = environment();
+    if (!env->has(full_name) || (!c->via_call() && Prelexer::re_special_fun(name.c_str()))) {
+      if (!env->has("*[f]")) {
+        for (Argument_Obj arg : args->elements()) {
+          if (List_Obj ls = Cast<List>(arg->value())) {
+            if (ls->size() == 0) error("() isn't a valid CSS value.", c->pstate(), traces);
+          }
+        }
+        args = Cast<Arguments>(args->perform(this));
+        Function_Call_Obj lit = SASS_MEMORY_NEW(Function_Call,
+                                             c->pstate(),
+                                             c->name(),
+                                             args);
+        if (args->has_named_arguments()) {
+          error("Function " + c->name() + " doesn't support keyword arguments", c->pstate(), traces);
+        }
+        String_Quoted_Ptr str = SASS_MEMORY_NEW(String_Quoted,
+                                             c->pstate(),
+                                             lit->to_string(ctx.c_options));
+        str->is_interpolant(c->is_interpolant());
+        return str;
+      } else {
+        // call generic function
+        full_name = "*[f]";
+      }
+    }
+
+    // further delay for calls
+    if (full_name != "call[f]") {
+      args->set_delayed(false); // verified
+    }
+    if (full_name != "if[f]") {
+      args = Cast<Arguments>(args->perform(this));
+    }
+    Definition_Ptr def = Cast<Definition>((*env)[full_name]);
+
+    if (c->func()) def = c->func()->definition();
+
+    if (def->is_overload_stub()) {
+      std::stringstream ss;
+      size_t L = args->length();
+      // account for rest arguments
+      if (args->has_rest_argument() && args->length() > 0) {
+        // get the rest arguments list
+        List_Ptr rest = Cast<List>(args->last()->value());
+        // arguments before rest argument plus rest
+        if (rest) L += rest->length() - 1;
+      }
+      ss << full_name << L;
+      full_name = ss.str();
+      std::string resolved_name(full_name);
+      if (!env->has(resolved_name)) error("overloaded function `" + std::string(c->name()) + "` given wrong number of arguments", c->pstate(), traces);
+      def = Cast<Definition>((*env)[resolved_name]);
+    }
+
+    Expression_Obj     result = c;
+    Block_Obj          body   = def->block();
+    Native_Function func   = def->native_function();
+    Sass_Function_Entry c_function = def->c_function();
+
+    if (c->is_css()) return result.detach();
+
+    Parameters_Obj params = def->parameters();
+    Env fn_env(def->environment());
+    exp.env_stack.push_back(&fn_env);
+
+    if (func || body) {
+      bind(std::string("Function"), c->name(), params, args, &ctx, &fn_env, this);
+      std::string msg(", in function `" + c->name() + "`");
+      traces.push_back(Backtrace(c->pstate(), msg));
+      ctx.callee_stack.push_back({
+        c->name().c_str(),
+        c->pstate().path,
+        c->pstate().line + 1,
+        c->pstate().column + 1,
+        SASS_CALLEE_FUNCTION,
+        { env }
+      });
+
+      // eval the body if user-defined or special, invoke underlying CPP function if native
+      if (body /* && !Prelexer::re_special_fun(name.c_str()) */) {
+        result = body->perform(this);
+      }
+      else if (func) {
+        result = func(fn_env, *env, ctx, def->signature(), c->pstate(), traces, exp.selector_stack);
+      }
+      if (!result) {
+        error(std::string("Function ") + c->name() + " finished without @return", c->pstate(), traces);
+      }
+      ctx.callee_stack.pop_back();
+      traces.pop_back();
+    }
+
+    // else if it's a user-defined c function
+    // convert call into C-API compatible form
+    else if (c_function) {
+      Sass_Function_Fn c_func = sass_function_get_function(c_function);
+      if (full_name == "*[f]") {
+        String_Quoted_Obj str = SASS_MEMORY_NEW(String_Quoted, c->pstate(), c->name());
+        Arguments_Obj new_args = SASS_MEMORY_NEW(Arguments, c->pstate());
+        new_args->append(SASS_MEMORY_NEW(Argument, c->pstate(), str));
+        new_args->concat(args);
+        args = new_args;
+      }
+
+      // populates env with default values for params
+      std::string ff(c->name());
+      bind(std::string("Function"), c->name(), params, args, &ctx, &fn_env, this);
+      std::string msg(", in function `" + c->name() + "`");
+      traces.push_back(Backtrace(c->pstate(), msg));
+      ctx.callee_stack.push_back({
+        c->name().c_str(),
+        c->pstate().path,
+        c->pstate().line + 1,
+        c->pstate().column + 1,
+        SASS_CALLEE_C_FUNCTION,
+        { env }
+      });
+
+      To_C to_c;
+      union Sass_Value* c_args = sass_make_list(params->length(), SASS_COMMA, false);
+      for(size_t i = 0; i < params->length(); i++) {
+        Parameter_Obj param = params->at(i);
+        std::string key = param->name();
+        AST_Node_Obj node = fn_env.get_local(key);
+        Expression_Obj arg = Cast<Expression>(node);
+        sass_list_set_value(c_args, i, arg->perform(&to_c));
+      }
+      union Sass_Value* c_val = c_func(c_args, c_function, ctx.c_compiler);
+      if (sass_value_get_tag(c_val) == SASS_ERROR) {
+        error("error in C function " + c->name() + ": " + sass_error_get_message(c_val), c->pstate(), traces);
+      } else if (sass_value_get_tag(c_val) == SASS_WARNING) {
+        error("warning in C function " + c->name() + ": " + sass_warning_get_message(c_val), c->pstate(), traces);
+      }
+      result = cval_to_astnode(c_val, traces, c->pstate());
+
+      ctx.callee_stack.pop_back();
+      traces.pop_back();
+      sass_delete_value(c_args);
+      if (c_val != c_args)
+        sass_delete_value(c_val);
+    }
+
+    // link back to function definition
+    // only do this for custom functions
+    if (result->pstate().file == std::string::npos)
+      result->pstate(c->pstate());
+
+    result = result->perform(this);
+    result->is_interpolant(c->is_interpolant());
+    exp.env_stack.pop_back();
+    return result.detach();
+  }
+
+  Expression_Ptr Eval::operator()(Function_Call_Schema_Ptr s)
+  {
+    Expression_Ptr evaluated_name = s->name()->perform(this);
+    Expression_Ptr evaluated_args = s->arguments()->perform(this);
+    String_Schema_Obj ss = SASS_MEMORY_NEW(String_Schema, s->pstate(), 2);
+    ss->append(evaluated_name);
+    ss->append(evaluated_args);
+    return ss->perform(this);
+  }
+
+  Expression_Ptr Eval::operator()(Variable_Ptr v)
+  {
+    Expression_Obj value = 0;
+    Env* env = environment();
+    const std::string& name(v->name());
+    EnvResult rv(env->find(name));
+    if (rv.found) value = static_cast<Expression*>(rv.it->second.ptr());
+    else error("Undefined variable: \"" + v->name() + "\".", v->pstate(), traces);
+    if (Argument_Ptr arg = Cast<Argument>(value)) value = arg->value();
+    if (Number_Ptr nr = Cast<Number>(value)) nr->zero(true); // force flag
+    value->is_interpolant(v->is_interpolant());
+    if (force) value->is_expanded(false);
+    value->set_delayed(false); // verified
+    value = value->perform(this);
+    if(!force) rv.it->second = value;
+    return value.detach();
+  }
+
+  Expression_Ptr Eval::operator()(Color_Ptr c)
+  {
+    return c;
+  }
+
+  Expression_Ptr Eval::operator()(Number_Ptr n)
+  {
+    return n;
+  }
+
+  Expression_Ptr Eval::operator()(Boolean_Ptr b)
+  {
+    return b;
+  }
+
+  void Eval::interpolation(Context& ctx, std::string& res, Expression_Obj ex, bool into_quotes, bool was_itpl) {
+
+    bool needs_closing_brace = false;
+
+    if (Arguments_Ptr args = Cast<Arguments>(ex)) {
+      List_Ptr ll = SASS_MEMORY_NEW(List, args->pstate(), 0, SASS_COMMA);
+      for(auto arg : args->elements()) {
+        ll->append(arg->value());
+      }
+      ll->is_interpolant(args->is_interpolant());
+      needs_closing_brace = true;
+      res += "(";
+      ex = ll;
+    }
+    if (Number_Ptr nr = Cast<Number>(ex)) {
+      Number reduced(nr);
+      reduced.reduce();
+      if (!reduced.is_valid_css_unit()) {
+        traces.push_back(Backtrace(nr->pstate()));
+        throw Exception::InvalidValue(traces, *nr);
+      }
+    }
+    if (Argument_Ptr arg = Cast<Argument>(ex)) {
+      ex = arg->value();
+    }
+    if (String_Quoted_Ptr sq = Cast<String_Quoted>(ex)) {
+      if (was_itpl) {
+        bool was_interpolant = ex->is_interpolant();
+        ex = SASS_MEMORY_NEW(String_Constant, sq->pstate(), sq->value());
+        ex->is_interpolant(was_interpolant);
+      }
+    }
+
+    if (Cast<Null>(ex)) { return; }
+
+    // parent selector needs another go
+    if (Cast<Parent_Selector>(ex)) {
+      // XXX: this is never hit via spec tests
+      ex = ex->perform(this);
+    }
+
+    if (List_Ptr l = Cast<List>(ex)) {
+      List_Obj ll = SASS_MEMORY_NEW(List, l->pstate(), 0, l->separator());
+      // this fixes an issue with bourbon sample, not really sure why
+      // if (l->size() && Cast<Null>((*l)[0])) { res += ""; }
+      for(Expression_Obj item : *l) {
+        item->is_interpolant(l->is_interpolant());
+        std::string rl(""); interpolation(ctx, rl, item, into_quotes, l->is_interpolant());
+        bool is_null = Cast<Null>(item) != 0; // rl != ""
+        if (!is_null) ll->append(SASS_MEMORY_NEW(String_Quoted, item->pstate(), rl));
+      }
+      // Check indicates that we probably should not get a list
+      // here. Normally single list items are already unwrapped.
+      if (l->size() > 1) {
+        // string_to_output would fail "#{'_\a' '_\a'}";
+        std::string str(ll->to_string(ctx.c_options));
+        str = read_hex_escapes(str); // read escapes
+        newline_to_space(str); // replace directly
+        res += str; // append to result string
+      } else {
+        res += (ll->to_string(ctx.c_options));
+      }
+      ll->is_interpolant(l->is_interpolant());
+    }
+
+    // Value
+    // Function_Call
+    // Selector_List
+    // String_Quoted
+    // String_Constant
+    // Parent_Selector
+    // Binary_Expression
+    else {
+      // ex = ex->perform(this);
+      if (into_quotes && ex->is_interpolant()) {
+        res += evacuate_escapes(ex ? ex->to_string(ctx.c_options) : "");
+      } else {
+        std::string str(ex ? ex->to_string(ctx.c_options) : "");
+        if (into_quotes) str = read_hex_escapes(str);
+        res += str; // append to result string
+      }
+    }
+
+    if (needs_closing_brace) res += ")";
+
+  }
+
+  Expression_Ptr Eval::operator()(String_Schema_Ptr s)
+  {
+    size_t L = s->length();
+    bool into_quotes = false;
+    if (L > 1) {
+      if (!Cast<String_Quoted>((*s)[0]) && !Cast<String_Quoted>((*s)[L - 1])) {
+      if (String_Constant_Ptr l = Cast<String_Constant>((*s)[0])) {
+        if (String_Constant_Ptr r = Cast<String_Constant>((*s)[L - 1])) {
+          if (r->value().size() > 0) {
+            if (l->value()[0] == '"' && r->value()[r->value().size() - 1] == '"') into_quotes = true;
+            if (l->value()[0] == '\'' && r->value()[r->value().size() - 1] == '\'') into_quotes = true;
+          }
+        }
+      }
+      }
+    }
+    bool was_quoted = false;
+    bool was_interpolant = false;
+    std::string res("");
+    for (size_t i = 0; i < L; ++i) {
+      bool is_quoted = Cast<String_Quoted>((*s)[i]) != NULL;
+      if (was_quoted && !(*s)[i]->is_interpolant() && !was_interpolant) { res += " "; }
+      else if (i > 0 && is_quoted && !(*s)[i]->is_interpolant() && !was_interpolant) { res += " "; }
+      Expression_Obj ex = (*s)[i]->perform(this);
+      interpolation(ctx, res, ex, into_quotes, ex->is_interpolant());
+      was_quoted = Cast<String_Quoted>((*s)[i]) != NULL;
+      was_interpolant = (*s)[i]->is_interpolant();
+
+    }
+    if (!s->is_interpolant()) {
+      if (s->length() > 1 && res == "") return SASS_MEMORY_NEW(Null, s->pstate());
+      return SASS_MEMORY_NEW(String_Constant, s->pstate(), res, s->css());
+    }
+    // string schema seems to have a special unquoting behavior (also handles "nested" quotes)
+    String_Quoted_Obj str = SASS_MEMORY_NEW(String_Quoted, s->pstate(), res, 0, false, false, false, s->css());
+    // if (s->is_interpolant()) str->quote_mark(0);
+    // String_Constant_Ptr str = SASS_MEMORY_NEW(String_Constant, s->pstate(), res);
+    if (str->quote_mark()) str->quote_mark('*');
+    else if (!is_in_comment) str->value(string_to_output(str->value()));
+    str->is_interpolant(s->is_interpolant());
+    return str.detach();
+  }
+
+
+  Expression_Ptr Eval::operator()(String_Constant_Ptr s)
+  {
+    if (!s->is_delayed() && name_to_color(s->value())) {
+      Color_Ptr c = SASS_MEMORY_COPY(name_to_color(s->value())); // copy
+      c->pstate(s->pstate());
+      c->disp(s->value());
+      c->is_delayed(true);
+      return c;
+    }
+    return s;
+  }
+
+  Expression_Ptr Eval::operator()(String_Quoted_Ptr s)
+  {
+    String_Quoted_Ptr str = SASS_MEMORY_NEW(String_Quoted, s->pstate(), "");
+    str->value(s->value());
+    str->quote_mark(s->quote_mark());
+    str->is_interpolant(s->is_interpolant());
+    return str;
+  }
+
+  Expression_Ptr Eval::operator()(Supports_Operator_Ptr c)
+  {
+    Expression_Ptr left = c->left()->perform(this);
+    Expression_Ptr right = c->right()->perform(this);
+    Supports_Operator_Ptr cc = SASS_MEMORY_NEW(Supports_Operator,
+                                 c->pstate(),
+                                 Cast<Supports_Condition>(left),
+                                 Cast<Supports_Condition>(right),
+                                 c->operand());
+    return cc;
+  }
+
+  Expression_Ptr Eval::operator()(Supports_Negation_Ptr c)
+  {
+    Expression_Ptr condition = c->condition()->perform(this);
+    Supports_Negation_Ptr cc = SASS_MEMORY_NEW(Supports_Negation,
+                                 c->pstate(),
+                                 Cast<Supports_Condition>(condition));
+    return cc;
+  }
+
+  Expression_Ptr Eval::operator()(Supports_Declaration_Ptr c)
+  {
+    Expression_Ptr feature = c->feature()->perform(this);
+    Expression_Ptr value = c->value()->perform(this);
+    Supports_Declaration_Ptr cc = SASS_MEMORY_NEW(Supports_Declaration,
+                              c->pstate(),
+                              feature,
+                              value);
+    return cc;
+  }
+
+  Expression_Ptr Eval::operator()(Supports_Interpolation_Ptr c)
+  {
+    Expression_Ptr value = c->value()->perform(this);
+    Supports_Interpolation_Ptr cc = SASS_MEMORY_NEW(Supports_Interpolation,
+                            c->pstate(),
+                            value);
+    return cc;
+  }
+
+  Expression_Ptr Eval::operator()(At_Root_Query_Ptr e)
+  {
+    Expression_Obj feature = e->feature();
+    feature = (feature ? feature->perform(this) : 0);
+    Expression_Obj value = e->value();
+    value = (value ? value->perform(this) : 0);
+    Expression_Ptr ee = SASS_MEMORY_NEW(At_Root_Query,
+                                     e->pstate(),
+                                     Cast<String>(feature),
+                                     value);
+    return ee;
+  }
+
+  Media_Query_Ptr Eval::operator()(Media_Query_Ptr q)
+  {
+    String_Obj t = q->media_type();
+    t = static_cast<String_Ptr>(t.isNull() ? 0 : t->perform(this));
+    Media_Query_Obj qq = SASS_MEMORY_NEW(Media_Query,
+                                      q->pstate(),
+                                      t,
+                                      q->length(),
+                                      q->is_negated(),
+                                      q->is_restricted());
+    for (size_t i = 0, L = q->length(); i < L; ++i) {
+      qq->append(static_cast<Media_Query_Expression_Ptr>((*q)[i]->perform(this)));
+    }
+    return qq.detach();
+  }
+
+  Expression_Ptr Eval::operator()(Media_Query_Expression_Ptr e)
+  {
+    Expression_Obj feature = e->feature();
+    feature = (feature ? feature->perform(this) : 0);
+    if (feature && Cast<String_Quoted>(feature)) {
+      feature = SASS_MEMORY_NEW(String_Quoted,
+                                  feature->pstate(),
+                                  Cast<String_Quoted>(feature)->value());
+    }
+    Expression_Obj value = e->value();
+    value = (value ? value->perform(this) : 0);
+    if (value && Cast<String_Quoted>(value)) {
+      // XXX: this is never hit via spec tests
+      value = SASS_MEMORY_NEW(String_Quoted,
+                                value->pstate(),
+                                Cast<String_Quoted>(value)->value());
+    }
+    return SASS_MEMORY_NEW(Media_Query_Expression,
+                           e->pstate(),
+                           feature,
+                           value,
+                           e->is_interpolated());
+  }
+
+  Expression_Ptr Eval::operator()(Null_Ptr n)
+  {
+    return n;
+  }
+
+  Expression_Ptr Eval::operator()(Argument_Ptr a)
+  {
+    Expression_Obj val = a->value()->perform(this);
+    bool is_rest_argument = a->is_rest_argument();
+    bool is_keyword_argument = a->is_keyword_argument();
+
+    if (a->is_rest_argument()) {
+      if (val->concrete_type() == Expression::MAP) {
+        is_rest_argument = false;
+        is_keyword_argument = true;
+      }
+      else if(val->concrete_type() != Expression::LIST) {
+        List_Obj wrapper = SASS_MEMORY_NEW(List,
+                                        val->pstate(),
+                                        0,
+                                        SASS_COMMA,
+                                        true);
+        wrapper->append(val);
+        val = wrapper;
+      }
+    }
+    return SASS_MEMORY_NEW(Argument,
+                           a->pstate(),
+                           val,
+                           a->name(),
+                           is_rest_argument,
+                           is_keyword_argument);
+  }
+
+  Expression_Ptr Eval::operator()(Arguments_Ptr a)
+  {
+    Arguments_Obj aa = SASS_MEMORY_NEW(Arguments, a->pstate());
+    if (a->length() == 0) return aa.detach();
+    for (size_t i = 0, L = a->length(); i < L; ++i) {
+      Expression_Obj rv = (*a)[i]->perform(this);
+      Argument_Ptr arg = Cast<Argument>(rv);
+      if (!(arg->is_rest_argument() || arg->is_keyword_argument())) {
+        aa->append(arg);
+      }
+    }
+
+    if (a->has_rest_argument()) {
+      Expression_Obj rest = a->get_rest_argument()->perform(this);
+      Expression_Obj splat = Cast<Argument>(rest)->value()->perform(this);
+
+      Sass_Separator separator = SASS_COMMA;
+      List_Ptr ls = Cast<List>(splat);
+      Map_Ptr ms = Cast<Map>(splat);
+
+      List_Obj arglist = SASS_MEMORY_NEW(List,
+                                      splat->pstate(),
+                                      0,
+                                      ls ? ls->separator() : separator,
+                                      true);
+
+      if (ls && ls->is_arglist()) {
+        arglist->concat(ls);
+      } else if (ms) {
+        aa->append(SASS_MEMORY_NEW(Argument, splat->pstate(), ms, "", false, true));
+      } else if (ls) {
+        arglist->concat(ls);
+      } else {
+        arglist->append(splat);
+      }
+      if (arglist->length()) {
+        aa->append(SASS_MEMORY_NEW(Argument, splat->pstate(), arglist, "", true));
+      }
+    }
+
+    if (a->has_keyword_argument()) {
+      Expression_Obj rv = a->get_keyword_argument()->perform(this);
+      Argument_Ptr rvarg = Cast<Argument>(rv);
+      Expression_Obj kwarg = rvarg->value()->perform(this);
+
+      aa->append(SASS_MEMORY_NEW(Argument, kwarg->pstate(), kwarg, "", false, true));
+    }
+    return aa.detach();
+  }
+
+  Expression_Ptr Eval::operator()(Comment_Ptr c)
+  {
+    return 0;
+  }
+
+  inline Expression_Ptr Eval::fallback_impl(AST_Node_Ptr n)
+  {
+    return static_cast<Expression_Ptr>(n);
+  }
+
+  // All the binary helpers.
+
+  Expression_Ptr cval_to_astnode(union Sass_Value* v, Backtraces traces, ParserState pstate)
+  {
+    using std::strlen;
+    using std::strcpy;
+    Expression_Ptr e = NULL;
+    switch (sass_value_get_tag(v)) {
+      case SASS_BOOLEAN: {
+        e = SASS_MEMORY_NEW(Boolean, pstate, !!sass_boolean_get_value(v));
+      } break;
+      case SASS_NUMBER: {
+        e = SASS_MEMORY_NEW(Number, pstate, sass_number_get_value(v), sass_number_get_unit(v));
+      } break;
+      case SASS_COLOR: {
+        e = SASS_MEMORY_NEW(Color, pstate, sass_color_get_r(v), sass_color_get_g(v), sass_color_get_b(v), sass_color_get_a(v));
+      } break;
+      case SASS_STRING: {
+        if (sass_string_is_quoted(v))
+          e = SASS_MEMORY_NEW(String_Quoted, pstate, sass_string_get_value(v));
+        else {
+          e = SASS_MEMORY_NEW(String_Constant, pstate, sass_string_get_value(v));
+        }
+      } break;
+      case SASS_LIST: {
+        List_Ptr l = SASS_MEMORY_NEW(List, pstate, sass_list_get_length(v), sass_list_get_separator(v));
+        for (size_t i = 0, L = sass_list_get_length(v); i < L; ++i) {
+          l->append(cval_to_astnode(sass_list_get_value(v, i), traces, pstate));
+        }
+        l->is_bracketed(sass_list_get_is_bracketed(v));
+        e = l;
+      } break;
+      case SASS_MAP: {
+        Map_Ptr m = SASS_MEMORY_NEW(Map, pstate);
+        for (size_t i = 0, L = sass_map_get_length(v); i < L; ++i) {
+          *m << std::make_pair(
+            cval_to_astnode(sass_map_get_key(v, i), traces, pstate),
+            cval_to_astnode(sass_map_get_value(v, i), traces, pstate));
+        }
+        e = m;
+      } break;
+      case SASS_NULL: {
+        e = SASS_MEMORY_NEW(Null, pstate);
+      } break;
+      case SASS_ERROR: {
+        error("Error in C function: " + std::string(sass_error_get_message(v)), pstate, traces);
+      } break;
+      case SASS_WARNING: {
+        error("Warning in C function: " + std::string(sass_warning_get_message(v)), pstate, traces);
+      } break;
+      default: break;
+    }
+    return e;
+  }
+
+  Selector_List_Ptr Eval::operator()(Selector_List_Ptr s)
+  {
+    std::vector<Selector_List_Obj> rv;
+    Selector_List_Obj sl = SASS_MEMORY_NEW(Selector_List, s->pstate());
+    sl->is_optional(s->is_optional());
+    sl->media_block(s->media_block());
+    sl->is_optional(s->is_optional());
+    for (size_t i = 0, iL = s->length(); i < iL; ++i) {
+      rv.push_back(operator()((*s)[i]));
+    }
+
+    // we should actually permutate parent first
+    // but here we have permutated the selector first
+    size_t round = 0;
+    while (round != std::string::npos) {
+      bool abort = true;
+      for (size_t i = 0, iL = rv.size(); i < iL; ++i) {
+        if (rv[i]->length() > round) {
+          sl->append((*rv[i])[round]);
+          abort = false;
+        }
+      }
+      if (abort) {
+        round = std::string::npos;
+      } else {
+        ++ round;
+      }
+
+    }
+    return sl.detach();
+  }
+
+
+  Selector_List_Ptr Eval::operator()(Complex_Selector_Ptr s)
+  {
+    bool implicit_parent = !exp.old_at_root_without_rule;
+    if (is_in_selector_schema) exp.selector_stack.push_back(0);
+    Selector_List_Obj resolved = s->resolve_parent_refs(exp.selector_stack, traces, implicit_parent);
+    if (is_in_selector_schema) exp.selector_stack.pop_back();
+    for (size_t i = 0; i < resolved->length(); i++) {
+      Complex_Selector_Ptr is = resolved->at(i)->first();
+      while (is) {
+        if (is->head()) {
+          is->head(operator()(is->head()));
+        }
+        is = is->tail();
+      }
+    }
+    return resolved.detach();
+  }
+
+  Compound_Selector_Ptr Eval::operator()(Compound_Selector_Ptr s)
+  {
+    for (size_t i = 0; i < s->length(); i++) {
+      Simple_Selector_Ptr ss = s->at(i);
+      // skip parents here (called via resolve_parent_refs)
+      if (ss == NULL || Cast<Parent_Selector>(ss)) continue;
+      s->at(i) = Cast<Simple_Selector>(ss->perform(this));
+    }
+    return s;
+  }
+
+  Selector_List_Ptr Eval::operator()(Selector_Schema_Ptr s)
+  {
+    LOCAL_FLAG(is_in_selector_schema, true);
+    // the parser will look for a brace to end the selector
+    ctx.c_options.in_selector = true; // do not compress colors
+    Expression_Obj sel = s->contents()->perform(this);
+    std::string result_str(sel->to_string(ctx.c_options));
+    ctx.c_options.in_selector = false; // flag temporary only
+    result_str = unquote(Util::rtrim(result_str));
+    char* temp_cstr = sass_copy_c_string(result_str.c_str());
+    ctx.strings.push_back(temp_cstr); // attach to context
+    Parser p = Parser::from_c_str(temp_cstr, ctx, traces, s->pstate());
+    p.last_media_block = s->media_block();
+    // a selector schema may or may not connect to parent?
+    bool chroot = s->connect_parent() == false;
+    Selector_List_Obj sl = p.parse_selector_list(chroot);
+    auto vec_str_rend = ctx.strings.rend();
+    auto vec_str_rbegin = ctx.strings.rbegin();
+    // remove the first item searching from the back
+    // we cannot assume our item is still the last one
+    // order is not important, so we can optimize this
+    auto it = std::find(vec_str_rbegin, vec_str_rend, temp_cstr);
+    // undefined behavior if not found!
+    if (it != vec_str_rend) {
+      // overwrite with last item
+      *it = ctx.strings.back();
+      // remove last one from vector
+      ctx.strings.pop_back();
+      // free temporary copy
+      free(temp_cstr);
+    }
+    flag_is_in_selector_schema.reset();
+    return operator()(sl);
+  }
+
+  Expression_Ptr Eval::operator()(Parent_Selector_Ptr p)
+  {
+    if (Selector_List_Obj pr = selector()) {
+      exp.selector_stack.pop_back();
+      Selector_List_Obj rv = operator()(pr);
+      exp.selector_stack.push_back(rv);
+      return rv.detach();
+    } else {
+      return SASS_MEMORY_NEW(Null, p->pstate());
+    }
+  }
+
+  Simple_Selector_Ptr Eval::operator()(Simple_Selector_Ptr s)
+  {
+    return s;
+  }
+
+  // hotfix to avoid invalid nested `:not` selectors
+  // probably the wrong place, but this should ultimately
+  // be fixed by implement superselector correctly for `:not`
+  // first use of "find" (ATM only implemented for selectors)
+  bool hasNotSelector(AST_Node_Obj obj) {
+    if (Wrapped_Selector_Ptr w = Cast<Wrapped_Selector>(obj)) {
+      return w->name() == ":not";
+    }
+    return false;
+  }
+
+  Wrapped_Selector_Ptr Eval::operator()(Wrapped_Selector_Ptr s)
+  {
+
+    if (s->name() == ":not") {
+      if (exp.selector_stack.back()) {
+        if (s->selector()->find(hasNotSelector)) {
+          s->selector()->clear();
+          s->name(" ");
+        } else if (s->selector()->length() == 1) {
+          Complex_Selector_Ptr cs = s->selector()->at(0);
+          if (cs->tail()) {
+            s->selector()->clear();
+            s->name(" ");
+          }
+        } else if (s->selector()->length() > 1) {
+          s->selector()->clear();
+          s->name(" ");
+        }
+      }
+    }
+    return s;
+  };
 
 }
diff --git a/libsass/src/eval.hpp b/libsass/src/eval.hpp
--- a/libsass/src/eval.hpp
+++ b/libsass/src/eval.hpp
@@ -18,16 +18,20 @@
     Expression_Ptr fallback_impl(AST_Node_Ptr n);
 
    public:
-    Expand&  exp;
+    Expand& exp;
     Context& ctx;
+    Backtraces& traces;
     Eval(Expand& exp);
     ~Eval();
 
     bool force;
     bool is_in_comment;
+    bool is_in_selector_schema;
 
+    Boolean_Obj bool_true;
+    Boolean_Obj bool_false;
+
     Env* environment();
-    Backtrace* backtrace();
     Selector_List_Obj selector();
 
     // for evaluating function bodies
@@ -49,7 +53,6 @@
     Expression_Ptr operator()(Function_Call_Ptr);
     Expression_Ptr operator()(Function_Call_Schema_Ptr);
     Expression_Ptr operator()(Variable_Ptr);
-    Expression_Ptr operator()(Textual_Ptr);
     Expression_Ptr operator()(Number_Ptr);
     Expression_Ptr operator()(Color_Ptr);
     Expression_Ptr operator()(Boolean_Ptr);
@@ -57,7 +60,7 @@
     Expression_Ptr operator()(String_Quoted_Ptr);
     Expression_Ptr operator()(String_Constant_Ptr);
     // Expression_Ptr operator()(Selector_List_Ptr);
-    Expression_Ptr operator()(Media_Query_Ptr);
+    Media_Query_Ptr operator()(Media_Query_Ptr);
     Expression_Ptr operator()(Media_Query_Expression_Ptr);
     Expression_Ptr operator()(At_Root_Query_Ptr);
     Expression_Ptr operator()(Supports_Operator_Ptr);
@@ -72,14 +75,15 @@
     // these will return selectors
     Selector_List_Ptr operator()(Selector_List_Ptr);
     Selector_List_Ptr operator()(Complex_Selector_Ptr);
-    Attribute_Selector_Ptr operator()(Attribute_Selector_Ptr);
-    // they don't have any specific implementatio (yet)
-    Element_Selector_Ptr operator()(Element_Selector_Ptr s) { return s; };
-    Pseudo_Selector_Ptr operator()(Pseudo_Selector_Ptr s) { return s; };
-    Wrapped_Selector_Ptr operator()(Wrapped_Selector_Ptr s) { return s; };
-    Class_Selector_Ptr operator()(Class_Selector_Ptr s) { return s; };
-    Id_Selector_Ptr operator()(Id_Selector_Ptr s) { return s; };
-    Placeholder_Selector_Ptr operator()(Placeholder_Selector_Ptr s) { return s; };
+    Compound_Selector_Ptr operator()(Compound_Selector_Ptr);
+    Simple_Selector_Ptr operator()(Simple_Selector_Ptr s);
+    Wrapped_Selector_Ptr operator()(Wrapped_Selector_Ptr s);
+    // they don't have any specific implementation (yet)
+    // Element_Selector_Ptr operator()(Element_Selector_Ptr s) { return s; };
+    // Pseudo_Selector_Ptr operator()(Pseudo_Selector_Ptr s) { return s; };
+    // Class_Selector_Ptr operator()(Class_Selector_Ptr s) { return s; };
+    // Id_Selector_Ptr operator()(Id_Selector_Ptr s) { return s; };
+    // Placeholder_Selector_Ptr operator()(Placeholder_Selector_Ptr s) { return s; };
     // actual evaluated selectors
     Selector_List_Ptr operator()(Selector_Schema_Ptr);
     Expression_Ptr operator()(Parent_Selector_Ptr);
@@ -87,22 +91,12 @@
     template <typename U>
     Expression_Ptr fallback(U x) { return fallback_impl(x); }
 
-    // -- only need to define two comparisons, and the rest can be implemented in terms of them
-    static bool eq(Expression_Obj, Expression_Obj);
-    static bool lt(Expression_Obj, Expression_Obj, std::string op);
-    // -- arithmetic on the combinations that matter
-    static Value_Ptr op_numbers(enum Sass_OP, const Number&, const Number&, struct Sass_Inspect_Options opt, ParserState* pstate = 0);
-    static Value_Ptr op_number_color(enum Sass_OP, const Number&, const Color&, struct Sass_Inspect_Options opt, ParserState* pstate = 0);
-    static Value_Ptr op_color_number(enum Sass_OP, const Color&, const Number&, struct Sass_Inspect_Options opt, ParserState* pstate = 0);
-    static Value_Ptr op_colors(enum Sass_OP, const Color&, const Color&, struct Sass_Inspect_Options opt, ParserState* pstate = 0);
-    static Value_Ptr op_strings(Sass::Operand, Value&, Value&, struct Sass_Inspect_Options opt, ParserState* pstate = 0, bool interpolant = false);
-
   private:
     void interpolation(Context& ctx, std::string& res, Expression_Obj ex, bool into_quotes, bool was_itpl = false);
 
   };
 
-  Expression_Ptr cval_to_astnode(union Sass_Value* v, Backtrace* backtrace, ParserState pstate = ParserState("[AST]"));
+  Expression_Ptr cval_to_astnode(union Sass_Value* v, Backtraces traces, ParserState pstate = ParserState("[AST]"));
 
 }
 
diff --git a/libsass/src/expand.cpp b/libsass/src/expand.cpp
--- a/libsass/src/expand.cpp
+++ b/libsass/src/expand.cpp
@@ -9,14 +9,16 @@
 #include "backtrace.hpp"
 #include "context.hpp"
 #include "parser.hpp"
+#include "sass_functions.hpp"
 
 namespace Sass {
 
   // simple endless recursion protection
   const size_t maxRecursion = 500;
 
-  Expand::Expand(Context& ctx, Env* env, Backtrace* bt, std::vector<Selector_List_Obj>* stack)
+  Expand::Expand(Context& ctx, Env* env, std::vector<Selector_List_Obj>* stack)
   : ctx(ctx),
+    traces(ctx.traces),
     eval(Eval(*this)),
     recursions(0),
     in_keyframes(false),
@@ -26,8 +28,7 @@
     block_stack(std::vector<Block_Ptr>()),
     call_stack(std::vector<AST_Node_Obj>()),
     selector_stack(std::vector<Selector_List_Obj>()),
-    media_block_stack(std::vector<Media_Block_Ptr>()),
-    backtrace_stack(std::vector<Backtrace*>())
+    media_block_stack(std::vector<Media_Block_Ptr>())
   {
     env_stack.push_back(0);
     env_stack.push_back(env);
@@ -36,15 +37,8 @@
     if (stack == NULL) { selector_stack.push_back(0); }
     else { selector_stack.insert(selector_stack.end(), stack->begin(), stack->end()); }
     media_block_stack.push_back(0);
-    backtrace_stack.push_back(0);
-    backtrace_stack.push_back(bt);
   }
 
-  Context& Expand::context()
-  {
-    return ctx;
-  }
-
   Env* Expand::environment()
   {
     if (env_stack.size() > 0)
@@ -59,13 +53,6 @@
     return 0;
   }
 
-  Backtrace* Expand::backtrace()
-  {
-    if (backtrace_stack.size() > 0)
-      return backtrace_stack.back();
-    return 0;
-  }
-
   // blocks create new variable scopes
   Block_Ptr Expand::operator()(Block_Ptr b)
   {
@@ -78,7 +65,7 @@
                                 b->length(),
                                 b->is_root());
     // setup block and env stack
-    this->block_stack.push_back(&bb);
+    this->block_stack.push_back(bb);
     this->env_stack.push_back(&env);
     // operate on block
     // this may throw up!
@@ -95,12 +82,14 @@
     LOCAL_FLAG(old_at_root_without_rule, at_root_without_rule);
 
     if (in_keyframes) {
-      Block_Ptr bb = operator()(&r->block());
+      Block_Ptr bb = operator()(r->block());
       Keyframe_Rule_Obj k = SASS_MEMORY_NEW(Keyframe_Rule, r->pstate(), bb);
       if (r->selector()) {
-        selector_stack.push_back(0);
-        k->name(SASS_MEMORY_CAST_PTR(Selector_List, r->selector()->perform(&eval)));
-        selector_stack.pop_back();
+        if (Selector_List_Ptr s = r->selector()) {
+          selector_stack.push_back(0);
+          k->name(s->eval(eval));
+          selector_stack.pop_back();
+        }
       }
       return k.detach();
     }
@@ -108,50 +97,54 @@
     // reset when leaving scope
     LOCAL_FLAG(at_root_without_rule, false);
 
-    // do some special checks for the base level rules
-    if (r->is_root()) {
-      if (Selector_List_Ptr selector_list = SASS_MEMORY_CAST(Selector_List, r->selector())) {
+    // `&` is allowed in `@at-root`!
+    bool has_parent_selector = false;
+    for (size_t i = 0, L = selector_stack.size(); i < L && !has_parent_selector; i++) {
+      Selector_List_Obj ll = selector_stack.at(i);
+      has_parent_selector = ll != 0 && ll->length() > 0;
+    }
+
+    Selector_List_Obj sel = r->selector();
+    if (sel) sel = sel->eval(eval);
+
+    // check for parent selectors in base level rules
+    if (r->is_root() || (block_stack.back() && block_stack.back()->is_root())) {
+      if (Selector_List_Ptr selector_list = Cast<Selector_List>(r->selector())) {
         for (Complex_Selector_Obj complex_selector : selector_list->elements()) {
-          Complex_Selector_Ptr tail = &complex_selector;
+          Complex_Selector_Ptr tail = complex_selector;
           while (tail) {
             if (tail->head()) for (Simple_Selector_Obj header : tail->head()->elements()) {
-              if (SASS_MEMORY_CAST(Parent_Selector, header) == NULL) continue; // skip all others
+              Parent_Selector_Ptr ptr = Cast<Parent_Selector>(header);
+              if (ptr == NULL || (!ptr->real() || has_parent_selector)) continue;
               std::string sel_str(complex_selector->to_string(ctx.c_options));
-              error("Base-level rules cannot contain the parent-selector-referencing character '&'.", header->pstate(), backtrace());
+              error("Base-level rules cannot contain the parent-selector-referencing character '&'.", header->pstate(), traces);
             }
-            tail = &tail->tail();
+            tail = tail->tail();
           }
         }
       }
     }
-
-    Expression_Obj ex = 0;
-    if (r->selector()) ex = r->selector()->perform(&eval);
-    Selector_List_Obj sel = SASS_MEMORY_CAST(Selector_List, ex);
-    if (sel == 0) throw std::runtime_error("Expanded null selector");
-
-    if (sel->length() == 0 || sel->has_parent_ref()) {
-      bool has_parent_selector = false;
-      for (size_t i = 0, L = selector_stack.size(); i < L && !has_parent_selector; i++) {
-        Selector_List_Obj ll = selector_stack.at(i);
-        has_parent_selector = ll != 0 && ll->length() > 0;
-      }
-      if (sel->has_real_parent_ref() && !has_parent_selector) {
-        error("Base-level rules cannot contain the parent-selector-referencing character '&'.", sel->pstate(), backtrace());
+    else {
+      if (sel->length() == 0 || sel->has_parent_ref()) {
+        if (sel->has_real_parent_ref() && !has_parent_selector) {
+          error("Base-level rules cannot contain the parent-selector-referencing character '&'.", sel->pstate(), traces);
+        }
       }
     }
 
-    selector_stack.push_back(&sel);
+    // do not connect parent again
+    sel->remove_parent_selectors();
+    selector_stack.push_back(sel);
     Env env(environment());
     if (block_stack.back()->is_root()) {
       env_stack.push_back(&env);
     }
     sel->set_media_block(media_block_stack.back());
     Block_Obj blk = 0;
-    if (r->block()) blk = operator()(&r->block());
+    if (r->block()) blk = operator()(r->block());
     Ruleset_Ptr rr = SASS_MEMORY_NEW(Ruleset,
                                   r->pstate(),
-                                  &sel,
+                                  sel,
                                   blk);
     selector_stack.pop_back();
     if (block_stack.back()->is_root()) {
@@ -169,27 +162,33 @@
     Expression_Obj condition = f->condition()->perform(&eval);
     Supports_Block_Obj ff = SASS_MEMORY_NEW(Supports_Block,
                                        f->pstate(),
-                                       SASS_MEMORY_CAST(Supports_Condition, condition),
-                                       operator()(&f->block()));
+                                       Cast<Supports_Condition>(condition),
+                                       operator()(f->block()));
     return ff.detach();
   }
 
   Statement_Ptr Expand::operator()(Media_Block_Ptr m)
   {
-    media_block_stack.push_back(m);
-    Expression_Obj mq = m->media_queries()->perform(&eval);
+    Media_Block_Obj cpy = SASS_MEMORY_COPY(m);
+    // Media_Blocks are prone to have circular references
+    // Copy could leak memory if it does not get picked up
+    // Looks like we are able to reset block reference for copy
+    // Good as it will ensure a low memory overhead for this fix
+    // So this is a cheap solution with a minimal price
+    ctx.ast_gc.push_back(cpy); cpy->block(0);
+    Expression_Obj mq = eval(m->media_queries());
     std::string str_mq(mq->to_string(ctx.c_options));
     char* str = sass_copy_c_string(str_mq.c_str());
     ctx.strings.push_back(str);
-    Parser p(Parser::from_c_str(str, ctx, mq->pstate()));
-    mq = &p.parse_media_queries(); // re-assign now
-    List_Obj ls = SASS_MEMORY_CAST_PTR(List, mq->perform(&eval));
-    Block_Obj blk = operator()(&m->block());
+    Parser p(Parser::from_c_str(str, ctx, traces, mq->pstate()));
+    mq = p.parse_media_queries(); // re-assign now
+    cpy->media_queries(mq);
+    media_block_stack.push_back(cpy);
+    Block_Obj blk = operator()(m->block());
     Media_Block_Ptr mm = SASS_MEMORY_NEW(Media_Block,
                                       m->pstate(),
-                                      ls,
-                                      blk,
-                                      0);
+                                      mq,
+                                      blk);
     media_block_stack.pop_back();
     mm->tabs(m->tabs());
     return mm;
@@ -198,7 +197,7 @@
   Statement_Ptr Expand::operator()(At_Root_Block_Ptr a)
   {
     Block_Obj ab = a->block();
-    Expression_Obj ae = &a->expression();
+    Expression_Obj ae = a->expression();
 
     if (ae) ae = ae->perform(&eval);
     else ae = SASS_MEMORY_NEW(At_Root_Query, a->pstate());
@@ -208,23 +207,23 @@
 
                                        ;
 
-    Block_Obj bb = ab ? operator()(&ab) : NULL;
+    Block_Obj bb = ab ? operator()(ab) : NULL;
     At_Root_Block_Obj aa = SASS_MEMORY_NEW(At_Root_Block,
                                         a->pstate(),
                                         bb,
-                                        SASS_MEMORY_CAST(At_Root_Query, ae));
+                                        Cast<At_Root_Query>(ae));
     return aa.detach();
   }
 
   Statement_Ptr Expand::operator()(Directive_Ptr a)
   {
     LOCAL_FLAG(in_keyframes, a->is_keyframes());
-    Block_Ptr ab = &a->block();
-    Selector_Ptr as = &a->selector();
-    Expression_Ptr av = &a->value();
+    Block_Ptr ab = a->block();
+    Selector_List_Ptr as = a->selector();
+    Expression_Ptr av = a->value();
     selector_stack.push_back(0);
     if (av) av = av->perform(&eval);
-    if (as) as = SASS_MEMORY_CAST_PTR(Selector, as->perform(&eval));
+    if (as) as = eval(as);
     selector_stack.pop_back();
     Block_Ptr bb = ab ? operator()(ab) : NULL;
     Directive_Ptr aa = SASS_MEMORY_NEW(Directive,
@@ -241,14 +240,14 @@
     Block_Obj ab = d->block();
     String_Obj old_p = d->property();
     Expression_Obj prop = old_p->perform(&eval);
-    String_Obj new_p = SASS_MEMORY_CAST(String, prop);
+    String_Obj new_p = Cast<String>(prop);
     // we might get a color back
     if (!new_p) {
       std::string str(prop->to_string(ctx.c_options));
       new_p = SASS_MEMORY_NEW(String_Constant, old_p->pstate(), str);
     }
     Expression_Obj value = d->value()->perform(&eval);
-    Block_Obj bb = ab ? operator()(&ab) : NULL;
+    Block_Obj bb = ab ? operator()(ab) : NULL;
     if (!bb) {
       if (!value || (value->is_invisible() && !d->is_important())) return 0;
     }
@@ -257,6 +256,7 @@
                                         new_p,
                                         value,
                                         d->is_important(),
+                                        d->is_custom_property(),
                                         bb);
     decl->tabs(d->tabs());
     return decl;
@@ -265,11 +265,11 @@
   Statement_Ptr Expand::operator()(Assignment_Ptr a)
   {
     Env* env = environment();
-    std::string var(a->variable());
+    const std::string& var(a->variable());
     if (a->is_global()) {
       if (a->is_default()) {
         if (env->has_global(var)) {
-          Expression_Obj e = SASS_MEMORY_CAST(Expression, env->get_global(var));
+          Expression_Obj e = Cast<Expression>(env->get_global(var));
           if (!e || e->concrete_type() == Expression::NULL_VAL) {
             env->set_global(var, a->value()->perform(&eval));
           }
@@ -288,7 +288,7 @@
         while (cur && cur->is_lexical()) {
           if (cur->has_local(var)) {
             if (AST_Node_Obj node = cur->get_local(var)) {
-              Expression_Obj e = SASS_MEMORY_CAST(Expression, node);
+              Expression_Obj e = Cast<Expression>(node);
               if (!e || e->concrete_type() == Expression::NULL_VAL) {
                 cur->set_local(var, a->value()->perform(&eval));
               }
@@ -304,7 +304,7 @@
       }
       else if (env->has_global(var)) {
         if (AST_Node_Obj node = env->get_global(var)) {
-          Expression_Obj e = SASS_MEMORY_CAST(Expression, node);
+          Expression_Obj e = Cast<Expression>(node);
           if (!e || e->concrete_type() == Expression::NULL_VAL) {
             env->set_global(var, a->value()->perform(&eval));
           }
@@ -328,7 +328,7 @@
     Import_Obj result = SASS_MEMORY_NEW(Import, imp->pstate());
     if (imp->import_queries() && imp->import_queries()->size()) {
       Expression_Obj ex = imp->import_queries()->perform(&eval);
-      result->import_queries(SASS_MEMORY_CAST(List, ex));
+      result->import_queries(Cast<List>(ex));
     }
     for ( size_t i = 0, S = imp->urls().size(); i < S; ++i) {
       result->urls().push_back(imp->urls()[i]->perform(&eval));
@@ -340,10 +340,11 @@
 
   Statement_Ptr Expand::operator()(Import_Stub_Ptr i)
   {
+    traces.push_back(Backtrace(i->pstate()));
     // get parent node from call stack
     AST_Node_Obj parent = call_stack.back();
-    if (SASS_MEMORY_CAST(Block, parent) == NULL) {
-      error("Import directives may not be used within control directives or mixins.", i->pstate());
+    if (Cast<Block>(parent) == NULL) {
+      error("Import directives may not be used within control directives or mixins.", i->pstate(), traces);
     }
     // we don't seem to need that actually afterall
     Sass_Import_Entry import = sass_make_import(
@@ -352,10 +353,18 @@
       0, 0
     );
     ctx.import_stack.push_back(import);
+
+    Block_Obj trace_block = SASS_MEMORY_NEW(Block, i->pstate());
+    Trace_Obj trace = SASS_MEMORY_NEW(Trace, i->pstate(), i->imp_path(), trace_block, 'i');
+    block_stack.back()->append(trace);
+    block_stack.push_back(trace_block);
+
     const std::string& abs_path(i->resource().abs_path);
-    append_block(&ctx.sheets.at(abs_path).root);
+    append_block(ctx.sheets.at(abs_path).root);
     sass_delete_import(ctx.import_stack.back());
     ctx.import_stack.pop_back();
+    block_stack.pop_back();
+    traces.pop_back();
     return 0;
   }
 
@@ -382,8 +391,13 @@
 
   Statement_Ptr Expand::operator()(Comment_Ptr c)
   {
+    if (ctx.output_style() == COMPRESSED) {
+      // comments should not be evaluated in compact
+      // https://github.com/sass/libsass/issues/2359
+      if (!c->is_important()) return NULL;
+    }
     eval.is_in_comment = true;
-    Comment_Ptr rv = SASS_MEMORY_NEW(Comment, c->pstate(), SASS_MEMORY_CAST_PTR(String, c->text()->perform(&eval)), c->is_important());
+    Comment_Ptr rv = SASS_MEMORY_NEW(Comment, c->pstate(), Cast<String>(c->text()->perform(&eval)), c->is_important());
     eval.is_in_comment = false;
     // TODO: eval the text, once we're parsing/storing it as a String_Schema
     return rv;
@@ -396,10 +410,10 @@
     call_stack.push_back(i);
     Expression_Obj rv = i->predicate()->perform(&eval);
     if (*rv) {
-      append_block(&i->block());
+      append_block(i->block());
     }
     else {
-      Block_Ptr alt = &i->alternative();
+      Block_Ptr alt = i->alternative();
       if (alt) append_block(alt);
     }
     call_stack.pop_back();
@@ -414,20 +428,22 @@
     std::string variable(f->variable());
     Expression_Obj low = f->lower_bound()->perform(&eval);
     if (low->concrete_type() != Expression::NUMBER) {
-      throw Exception::TypeMismatch(*low, "integer");
+      traces.push_back(Backtrace(low->pstate()));
+      throw Exception::TypeMismatch(traces, *low, "integer");
     }
     Expression_Obj high = f->upper_bound()->perform(&eval);
     if (high->concrete_type() != Expression::NUMBER) {
-      throw Exception::TypeMismatch(*high, "integer");
+      traces.push_back(Backtrace(high->pstate()));
+      throw Exception::TypeMismatch(traces, *high, "integer");
     }
-    Number_Obj sass_start = SASS_MEMORY_CAST(Number, low);
-    Number_Obj sass_end = SASS_MEMORY_CAST(Number, high);
+    Number_Obj sass_start = Cast<Number>(low);
+    Number_Obj sass_end = Cast<Number>(high);
     // check if units are valid for sequence
     if (sass_start->unit() != sass_end->unit()) {
       std::stringstream msg; msg << "Incompatible units: '"
         << sass_start->unit() << "' and '"
         << sass_end->unit() << "'.";
-      error(msg.str(), low->pstate(), backtrace());
+      error(msg.str(), low->pstate(), traces);
     }
     double start = sass_start->value();
     double end = sass_end->value();
@@ -435,17 +451,14 @@
     Env env(environment(), true);
     env_stack.push_back(&env);
     call_stack.push_back(f);
-    Number_Obj it = SASS_MEMORY_NEW(Number, low->pstate(), start, sass_end->unit());
-    env.set_local(variable, &it);
-    Block_Ptr body = &f->block();
+    Block_Ptr body = f->block();
     if (start < end) {
       if (f->is_inclusive()) ++end;
       for (double i = start;
            i < end;
            ++i) {
-        it = SASS_MEMORY_COPY(it);
-        it->value(i);
-        env.set_local(variable, &it);
+        Number_Obj it = SASS_MEMORY_NEW(Number, low->pstate(), i, sass_end->unit());
+        env.set_local(variable, it);
         append_block(body);
       }
     } else {
@@ -453,9 +466,8 @@
       for (double i = start;
            i > end;
            --i) {
-        it = SASS_MEMORY_COPY(it);
-        it->value(i);
-        env.set_local(variable, &it);
+        Number_Obj it = SASS_MEMORY_NEW(Number, low->pstate(), i, sass_end->unit());
+        env.set_local(variable, it);
         append_block(body);
       }
     }
@@ -473,25 +485,25 @@
     List_Obj list = 0;
     Map_Obj map;
     if (expr->concrete_type() == Expression::MAP) {
-      map = SASS_MEMORY_CAST(Map, expr);
+      map = Cast<Map>(expr);
     }
-    else if (Selector_List_Ptr ls = SASS_MEMORY_CAST(Selector_List, expr)) {
+    else if (Selector_List_Ptr ls = Cast<Selector_List>(expr)) {
       Listize listize;
       Expression_Obj rv = ls->perform(&listize);
-      list = SASS_MEMORY_CAST(List, rv);
+      list = Cast<List>(rv);
     }
     else if (expr->concrete_type() != Expression::LIST) {
       list = SASS_MEMORY_NEW(List, expr->pstate(), 1, SASS_COMMA);
       list->append(expr);
     }
     else {
-      list = SASS_MEMORY_CAST(List, expr);
+      list = Cast<List>(expr);
     }
     // remember variables and then reset them
     Env env(environment(), true);
     env_stack.push_back(&env);
     call_stack.push_back(e);
-    Block_Ptr body = &e->block();
+    Block_Ptr body = e->block();
 
     if (map) {
       for (auto key : map->keys()) {
@@ -502,43 +514,43 @@
           List_Obj variable = SASS_MEMORY_NEW(List, map->pstate(), 2, SASS_SPACE);
           variable->append(k);
           variable->append(v);
-          env.set_local(variables[0], &variable);
+          env.set_local(variables[0], variable);
         } else {
-          env.set_local(variables[0], &k);
-          env.set_local(variables[1], &v);
+          env.set_local(variables[0], k);
+          env.set_local(variables[1], v);
         }
         append_block(body);
       }
     }
     else {
       // bool arglist = list->is_arglist();
-      if (list->length() == 1 && SASS_MEMORY_CAST(Selector_List, list)) {
-        list = SASS_MEMORY_CAST(List, list);
+      if (list->length() == 1 && Cast<Selector_List>(list)) {
+        list = Cast<List>(list);
       }
       for (size_t i = 0, L = list->length(); i < L; ++i) {
-        Expression_Obj e = list->at(i);
+        Expression_Obj item = list->at(i);
         // unwrap value if the expression is an argument
-        if (Argument_Obj arg = SASS_MEMORY_CAST(Argument, e)) e = arg->value();
+        if (Argument_Obj arg = Cast<Argument>(item)) item = arg->value();
         // check if we got passed a list of args (investigate)
-        if (List_Obj scalars = SASS_MEMORY_CAST(List, e)) {
+        if (List_Obj scalars = Cast<List>(item)) {
           if (variables.size() == 1) {
             List_Obj var = scalars;
             // if (arglist) var = (*scalars)[0];
-            env.set_local(variables[0], &var);
+            env.set_local(variables[0], var);
           } else {
             for (size_t j = 0, K = variables.size(); j < K; ++j) {
               Expression_Obj res = j >= scalars->length()
                 ? SASS_MEMORY_NEW(Null, expr->pstate())
                 : (*scalars)[j]->perform(&eval);
-              env.set_local(variables[j], &res);
+              env.set_local(variables[j], res);
             }
           }
         } else {
           if (variables.size() > 0) {
-            env.set_local(variables.at(0), &e);
+            env.set_local(variables.at(0), item);
             for (size_t j = 1, K = variables.size(); j < K; ++j) {
               Expression_Obj res = SASS_MEMORY_NEW(Null, expr->pstate());
-              env.set_local(variables[j], &res);
+              env.set_local(variables[j], res);
             }
           }
         }
@@ -553,12 +565,12 @@
   Statement_Ptr Expand::operator()(While_Ptr w)
   {
     Expression_Obj pred = w->predicate();
-    Block_Ptr body = &w->block();
+    Block_Ptr body = w->block();
     Env env(environment(), true);
     env_stack.push_back(&env);
     call_stack.push_back(w);
     Expression_Obj cond = pred->perform(&eval);
-    while (*&cond) {
+    while (!cond->is_false()) {
       append_block(body);
       cond = pred->perform(&eval);
     }
@@ -569,21 +581,21 @@
 
   Statement_Ptr Expand::operator()(Return_Ptr r)
   {
-    error("@return may only be used within a function", r->pstate(), backtrace());
+    error("@return may only be used within a function", r->pstate(), traces);
     return 0;
   }
 
 
   void Expand::expand_selector_list(Selector_Obj s, Selector_List_Obj extender) {
 
-    if (Selector_List_Obj sl = SASS_MEMORY_CAST(Selector_List, s)) {
+    if (Selector_List_Obj sl = Cast<Selector_List>(s)) {
       for (Complex_Selector_Obj complex_selector : sl->elements()) {
         Complex_Selector_Obj tail = complex_selector;
         while (tail) {
           if (tail->head()) for (Simple_Selector_Obj header : tail->head()->elements()) {
-            if (SASS_MEMORY_CAST(Parent_Selector, header) == NULL) continue; // skip all others
+            if (Cast<Parent_Selector>(header) == NULL) continue; // skip all others
             std::string sel_str(complex_selector->to_string(ctx.c_options));
-            error("Can't extend " + sel_str + ": can't extend parent selectors", header->pstate(), backtrace());
+            error("Can't extend " + sel_str + ": can't extend parent selectors", header->pstate(), traces);
           }
           tail = tail->tail();
         }
@@ -591,20 +603,20 @@
     }
 
 
-    Selector_List_Obj contextualized = SASS_MEMORY_CAST_PTR(Selector_List, s->perform(&eval));
+    Selector_List_Obj contextualized = Cast<Selector_List>(s->perform(&eval));
     if (contextualized == false) return;
     for (auto complex_sel : contextualized->elements()) {
       Complex_Selector_Obj c = complex_sel;
       if (!c->head() || c->tail()) {
         std::string sel_str(contextualized->to_string(ctx.c_options));
-        error("Can't extend " + sel_str + ": can't extend nested selectors", c->pstate(), backtrace());
+        error("Can't extend " + sel_str + ": can't extend nested selectors", c->pstate(), traces);
       }
-      Compound_Selector_Obj placeholder = c->head();
-      if (contextualized->is_optional()) placeholder->is_optional(true);
+      Compound_Selector_Obj target = c->head();
+      if (contextualized->is_optional()) target->is_optional(true);
       for (size_t i = 0, L = extender->length(); i < L; ++i) {
         Complex_Selector_Obj sel = (*extender)[i];
         if (!(sel->head() && sel->head()->length() > 0 &&
-            SASS_MEMORY_CAST(Parent_Selector, (*sel->head())[0])))
+            Cast<Parent_Selector>((*sel->head())[0])))
         {
           Compound_Selector_Obj hh = SASS_MEMORY_NEW(Compound_Selector, (*extender)[i]->pstate());
           hh->media_block((*extender)[i]->media_block());
@@ -613,13 +625,13 @@
           if (sel->has_line_feed()) ssel->has_line_feed(true);
           Parent_Selector_Obj ps = SASS_MEMORY_NEW(Parent_Selector, (*extender)[i]->pstate());
           ps->media_block((*extender)[i]->media_block());
-          hh->append(&ps);
+          hh->append(ps);
           ssel->tail(sel);
           ssel->head(hh);
           sel = ssel;
         }
         // if (c->has_line_feed()) sel->has_line_feed(true);
-        ctx.subset_map.put(placeholder, std::make_pair(sel, placeholder));
+        ctx.subset_map.put(target, std::make_pair(sel, target));
       }
     }
 
@@ -627,31 +639,30 @@
 
   Statement* Expand::operator()(Extension_Ptr e)
   {
-    if (Selector_List_Obj extender = SASS_MEMORY_CAST(Selector_List, selector())) {
-      Selector_Obj s = e->selector();
-      Selector_List_Obj sl = NULL;
-      // check if we already have a valid selector list
-      if ((sl = SASS_MEMORY_CAST(Selector_List, s))) {}
-      // convert selector schema to a selector list
-      else if (Selector_Schema_Obj schema = SASS_MEMORY_CAST(Selector_Schema, s)) {
+    if (Selector_List_Ptr extender = selector()) {
+      Selector_List_Ptr sl = e->selector();
+      // abort on invalid selector
+      if (sl == NULL) return NULL;
+      if (Selector_Schema_Ptr schema = sl->schema()) {
         if (schema->has_real_parent_ref()) {
-          sl = eval(&schema);
+          // put root block on stack again (ignore parents)
+          // selector schema must not connect in eval!
+          block_stack.push_back(block_stack.at(1));
+          sl = eval(sl->schema());
+          block_stack.pop_back();
         } else {
           selector_stack.push_back(0);
-          sl = eval(&schema);
-          sl->remove_parent_selectors();
+          sl = eval(sl->schema());
           selector_stack.pop_back();
         }
       }
-      // abort on invalid selector
-      if (sl.isNull()) return NULL;
       for (Complex_Selector_Obj cs : sl->elements()) {
         if (!cs.isNull() && !cs->head().isNull()) {
           cs->head()->media_block(media_block_stack.back());
         }
       }
       selector_stack.push_back(0);
-      expand_selector_list(&sl, extender);
+      expand_selector_list(sl, extender);
       selector_stack.pop_back();
     }
     return 0;
@@ -662,7 +673,7 @@
     Env* env = environment();
     Definition_Obj dd = SASS_MEMORY_COPY(d);
     env->local_frame()[d->name() +
-                        (d->type() == Definition::MIXIN ? "[m]" : "[f]")] = &dd;
+                        (d->type() == Definition::MIXIN ? "[m]" : "[f]")] = dd;
 
     if (d->type() == Definition::FUNCTION && (
       Prelexer::calc_fn_call(d->name().c_str()) ||
@@ -671,9 +682,9 @@
       d->name() == "url"
     )) {
       deprecated(
-        "Naming a function \"" + d->name() + "\" is disallowed",
+        "Naming a function \"" + d->name() + "\" is disallowed and will be an error in future versions of Sass.",
         "This name conflicts with an existing CSS function with special parse rules.",
-         d->pstate()
+        false, d->pstate()
       );
     }
 
@@ -684,9 +695,8 @@
 
   Statement_Ptr Expand::operator()(Mixin_Call_Ptr c)
   {
-
     if (recursions > maxRecursion) {
-      throw Exception::StackError(*c);
+      throw Exception::StackError(traces, *c);
     }
 
     recursions ++;
@@ -694,19 +704,28 @@
     Env* env = environment();
     std::string full_name(c->name() + "[m]");
     if (!env->has(full_name)) {
-      error("no mixin named " + c->name(), c->pstate(), backtrace());
+      error("no mixin named " + c->name(), c->pstate(), traces);
     }
-    Definition_Obj def = SASS_MEMORY_CAST(Definition, (*env)[full_name]);
+    Definition_Obj def = Cast<Definition>((*env)[full_name]);
     Block_Obj body = def->block();
     Parameters_Obj params = def->parameters();
 
     if (c->block() && c->name() != "@content" && !body->has_content()) {
-      error("Mixin \"" + c->name() + "\" does not accept a content block.", c->pstate(), backtrace());
+      error("Mixin \"" + c->name() + "\" does not accept a content block.", c->pstate(), traces);
     }
     Expression_Obj rv = c->arguments()->perform(&eval);
-    Arguments_Obj args = SASS_MEMORY_CAST(Arguments, rv);
-    Backtrace new_bt(backtrace(), c->pstate(), ", in mixin `" + c->name() + "`");
-    backtrace_stack.push_back(&new_bt);
+    Arguments_Obj args = Cast<Arguments>(rv);
+    std::string msg(", in mixin `" + c->name() + "`");
+    traces.push_back(Backtrace(c->pstate(), msg));
+    ctx.callee_stack.push_back({
+      c->name().c_str(),
+      c->pstate().path,
+      c->pstate().line + 1,
+      c->pstate().column + 1,
+      SASS_CALLEE_MIXIN,
+      { env }
+    });
+
     Env new_env(def->environment());
     env_stack.push_back(&new_env);
     if (c->block()) {
@@ -718,7 +737,7 @@
                                           c->block(),
                                           Definition::MIXIN);
       thunk->environment(env);
-      new_env.local_frame()["@content[m]"] = &thunk;
+      new_env.local_frame()["@content[m]"] = thunk;
     }
 
     bind(std::string("Mixin"), c->name(), params, args, &ctx, &new_env, &eval);
@@ -726,16 +745,24 @@
     Block_Obj trace_block = SASS_MEMORY_NEW(Block, c->pstate());
     Trace_Obj trace = SASS_MEMORY_NEW(Trace, c->pstate(), c->name(), trace_block);
 
-
-    block_stack.push_back(&trace_block);
+    env->set_global("is_in_mixin", bool_true);
+    if (Block_Ptr pr = block_stack.back()) {
+      trace_block->is_root(pr->is_root());
+    }
+    block_stack.push_back(trace_block);
     for (auto bb : body->elements()) {
+      if (Ruleset_Ptr r = Cast<Ruleset>(bb)) {
+        r->is_root(trace_block->is_root());
+      }
       Statement_Obj ith = bb->perform(this);
       if (ith) trace->block()->append(ith);
     }
     block_stack.pop_back();
+    env->del_global("is_in_mixin");
 
+    ctx.callee_stack.pop_back();
     env_stack.pop_back();
-    backtrace_stack.pop_back();
+    traces.pop_back();
 
     recursions --;
     return trace.detach();
@@ -756,7 +783,7 @@
                                        "@content",
                                        SASS_MEMORY_NEW(Arguments, c->pstate()));
 
-    Trace_Obj trace = SASS_MEMORY_CAST_PTR(Trace, call->perform(this));
+    Trace_Obj trace = Cast<Trace>(call->perform(this));
 
     if (block_stack.back()->is_root()) {
       selector_stack.pop_back();
@@ -770,8 +797,8 @@
   {
     std::string err =std:: string("`Expand` doesn't handle ") + typeid(*n).name();
     String_Quoted_Obj msg = SASS_MEMORY_NEW(String_Quoted, ParserState("[WARN]"), err);
-    error("unknown internal error; please contact the LibSass maintainers", n->pstate(), backtrace());
-    return SASS_MEMORY_NEW(Warning, ParserState("[WARN]"), &msg);
+    error("unknown internal error; please contact the LibSass maintainers", n->pstate(), traces);
+    return SASS_MEMORY_NEW(Warning, ParserState("[WARN]"), msg);
   }
 
   // process and add to last block on stack
@@ -779,7 +806,7 @@
   {
     if (b->is_root()) call_stack.push_back(b);
     for (size_t i = 0, L = b->length(); i < L; ++i) {
-      Statement_Ptr stm = &b->at(i);
+      Statement_Ptr stm = b->at(i);
       Statement_Obj ith = stm->perform(this);
       if (ith) block_stack.back()->append(ith);
     }
diff --git a/libsass/src/expand.hpp b/libsass/src/expand.hpp
--- a/libsass/src/expand.hpp
+++ b/libsass/src/expand.hpp
@@ -13,18 +13,16 @@
   class Listize;
   class Context;
   class Eval;
-  typedef Environment<AST_Node_Obj> Env;
   struct Backtrace;
 
   class Expand : public Operation_CRTP<Statement_Ptr, Expand> {
   public:
 
     Env* environment();
-    Context& context();
     Selector_List_Obj selector();
-    Backtrace* backtrace();
 
     Context&          ctx;
+    Backtraces&       traces;
     Eval              eval;
     size_t            recursions;
     bool              in_keyframes;
@@ -37,15 +35,16 @@
     std::vector<AST_Node_Obj>      call_stack;
     std::vector<Selector_List_Obj> selector_stack;
     std::vector<Media_Block_Ptr>   media_block_stack;
-    std::vector<Backtrace*>        backtrace_stack;
 
+    Boolean_Obj bool_true;
+
     Statement_Ptr fallback_impl(AST_Node_Ptr n);
 
   private:
     void expand_selector_list(Selector_Obj, Selector_List_Obj extender);
 
   public:
-    Expand(Context&, Env*, Backtrace*, std::vector<Selector_List_Obj>* stack = NULL);
+    Expand(Context&, Env*, std::vector<Selector_List_Obj>* stack = NULL);
     ~Expand() { }
 
     Block_Ptr operator()(Block_Ptr);
diff --git a/libsass/src/extend.cpp b/libsass/src/extend.cpp
--- a/libsass/src/extend.cpp
+++ b/libsass/src/extend.cpp
@@ -4,6 +4,7 @@
 #include "backtrace.hpp"
 #include "paths.hpp"
 #include "parser.hpp"
+#include "expand.hpp"
 #include "node.hpp"
 #include "sass_util.hpp"
 #include "remove_placeholders.hpp"
@@ -61,8 +62,6 @@
 namespace Sass {
 
 
-  typedef std::pair<Complex_Selector_Obj, Compound_Selector_Obj> ExtensionPair;
-  typedef std::vector<ExtensionPair> SubsetMapEntries;
 
 #ifdef DEBUG
 
@@ -112,11 +111,6 @@
   }
 
   // Print a string representation of a Compound_Selector
-    typedef std::pair<Compound_Selector_Obj, Complex_Selector_Obj> SelsNewSeqPair;
-    typedef std::vector<SelsNewSeqPair> SelsNewSeqPairCollection;
-
-
-  // Print a string representation of a Compound_Selector
   static void printCompoundSelector(Compound_Selector_Ptr pCompoundSelector, const char* message=NULL, bool newline=true) {
 
     if (message) {
@@ -186,14 +180,14 @@
     }
   }
 
-  static void printSelsNewSeqPairCollection(SelsNewSeqPairCollection& collection, const char* message=NULL, bool newline=true) {
+  static void printSelsNewSeqPairCollection(SubSetMapLookups& collection, const char* message=NULL, bool newline=true) {
 
     if (message) {
       std::cerr << message;
     }
     bool first = true;
     std::cerr << "[";
-    for(SelsNewSeqPair& pair : collection) {
+    for(SubSetMapLookup& pair : collection) {
       if (first) {
         first = false;
       } else {
@@ -212,8 +206,8 @@
     }
   }
 
-  // Print a string representation of a SourcesSet
-  static void printSourcesSet(SourcesSet& sources, Context& ctx, const char* message=NULL, bool newline=true) {
+  // Print a string representation of a ComplexSelectorSet
+  static void printSourcesSet(ComplexSelectorSet& sources, const char* message=NULL, bool newline=true) {
 
     if (message) {
       std::cerr << message;
@@ -223,17 +217,17 @@
     // the differences we see when debug printing.
     typedef std::deque<std::string> SourceStrings;
     SourceStrings sourceStrings;
-    for (SourcesSet::iterator iterator = sources.begin(), iteratorEnd = sources.end(); iterator != iteratorEnd; ++iterator) {
+    for (ComplexSelectorSet::iterator iterator = sources.begin(), iteratorEnd = sources.end(); iterator != iteratorEnd; ++iterator) {
       Complex_Selector_Ptr pSource = *iterator;
       std::stringstream sstream;
-      sstream << complexSelectorToNode(pSource, ctx);
+      sstream << complexSelectorToNode(pSource);
       sourceStrings.push_back(sstream.str());
     }
 
     // Sort to get consistent output
     std::sort(sourceStrings.begin(), sourceStrings.end());
 
-    std::cerr << "SourcesSet[";
+    std::cerr << "ComplexSelectorSet[";
     for (SourceStrings::iterator iterator = sourceStrings.begin(), iteratorEnd = sourceStrings.end(); iterator != iteratorEnd; ++iterator) {
       std::string source = *iterator;
       if (iterator != sourceStrings.begin()) {
@@ -249,10 +243,10 @@
   }
 
 
-  std::ostream& operator<<(std::ostream& os, SubsetMapEntries& entries) {
+  std::ostream& operator<<(std::ostream& os, SubSetMapPairs& entries) {
     os << "SUBSET_MAP_ENTRIES[";
 
-    for (SubsetMapEntries::iterator iterator = entries.begin(), endIterator = entries.end(); iterator != endIterator; ++iterator) {
+    for (SubSetMapPairs::iterator iterator = entries.begin(), endIterator = entries.end(); iterator != endIterator; ++iterator) {
       Complex_Selector_Obj pExtComplexSelector = iterator->first;    // The selector up to where the @extend is (ie, the thing to merge)
       Compound_Selector_Obj pExtCompoundSelector = iterator->second; // The stuff after the @extend
 
@@ -286,17 +280,16 @@
   }
 #endif
 
-  static bool parentSuperselector(Complex_Selector_Ptr pOne, Complex_Selector_Ptr pTwo, Context& ctx) {
+  static bool parentSuperselector(Complex_Selector_Ptr pOne, Complex_Selector_Ptr pTwo) {
     // TODO: figure out a better way to create a Complex_Selector from scratch
     // TODO: There's got to be a better way. This got ugly quick...
-    Position noPosition(-1, -1, -1);
     Element_Selector_Obj fakeParent = SASS_MEMORY_NEW(Element_Selector, ParserState("[FAKE]"), "temp");
     Compound_Selector_Obj fakeHead = SASS_MEMORY_NEW(Compound_Selector, ParserState("[FAKE]"), 1 /*size*/);
-    fakeHead->elements().push_back(&fakeParent);
-    Complex_Selector_Obj fakeParentContainer = SASS_MEMORY_NEW(Complex_Selector, ParserState("[FAKE]"), Complex_Selector::ANCESTOR_OF, &fakeHead /*head*/, NULL /*tail*/);
+    fakeHead->elements().push_back(fakeParent);
+    Complex_Selector_Obj fakeParentContainer = SASS_MEMORY_NEW(Complex_Selector, ParserState("[FAKE]"), Complex_Selector::ANCESTOR_OF, fakeHead /*head*/, NULL /*tail*/);
 
-    pOne->set_innermost(&fakeParentContainer, Complex_Selector::ANCESTOR_OF);
-    pTwo->set_innermost(&fakeParentContainer, Complex_Selector::ANCESTOR_OF);
+    pOne->set_innermost(fakeParentContainer, Complex_Selector::ANCESTOR_OF);
+    pTwo->set_innermost(fakeParentContainer, Complex_Selector::ANCESTOR_OF);
 
     bool isSuperselector = pOne->is_superselector_of(pTwo);
 
@@ -306,19 +299,19 @@
     return isSuperselector;
   }
 
-  void nodeToComplexSelectorDeque(const Node& node, ComplexSelectorDeque& out, Context& ctx) {
+  void nodeToComplexSelectorDeque(const Node& node, ComplexSelectorDeque& out) {
     for (NodeDeque::iterator iter = node.collection()->begin(), iterEnd = node.collection()->end(); iter != iterEnd; iter++) {
       Node& child = *iter;
-      out.push_back(nodeToComplexSelector(child, ctx));
+      out.push_back(nodeToComplexSelector(child));
     }
   }
 
-  Node complexSelectorDequeToNode(const ComplexSelectorDeque& deque, Context& ctx) {
+  Node complexSelectorDequeToNode(const ComplexSelectorDeque& deque) {
     Node result = Node::createCollection();
 
     for (ComplexSelectorDeque::const_iterator iter = deque.begin(), iterEnd = deque.end(); iter != iterEnd; iter++) {
       Complex_Selector_Obj pChild = *iter;
-      result.collection()->push_back(complexSelectorToNode(&pChild, ctx));
+      result.collection()->push_back(complexSelectorToNode(pChild));
     }
 
     return result;
@@ -326,9 +319,7 @@
 
   class LcsCollectionComparator {
   public:
-    LcsCollectionComparator(Context& ctx) : mCtx(ctx) {}
-
-    Context& mCtx;
+    LcsCollectionComparator() {}
 
     bool operator()(Complex_Selector_Obj pOne, Complex_Selector_Obj pTwo, Complex_Selector_Obj& pOut) const {
       /*
@@ -341,7 +332,7 @@
         end
       */
 
-      if (selectors_equal(*pOne, *pTwo, true /*simpleSelectorOrderDependent*/)) {
+      if (*pOne == *pTwo) {
         pOut = pOne;
         return true;
       }
@@ -350,12 +341,12 @@
         return false;
       }
 
-      if (parentSuperselector(&pOne, &pTwo, mCtx)) {
+      if (parentSuperselector(pOne, pTwo)) {
         pOut = pTwo;
         return true;
       }
 
-      if (parentSuperselector(&pTwo, &pOne, mCtx)) {
+      if (parentSuperselector(pTwo, pOne)) {
         pOut = pOne;
         return true;
       }
@@ -420,7 +411,7 @@
       for (size_t j = 1; j < y.size(); j++) {
         Complex_Selector_Obj pCompareOut;
 
-        if (comparator(&x[i], &y[j], pCompareOut)) {
+        if (comparator(x[i], y[j], pCompareOut)) {
           c[i][j] = c[i - 1][j - 1] + 1;
         } else {
           c[i][j] = std::max(c[i][j - 1], c[i - 1][j]);
@@ -445,7 +436,7 @@
 
   http://en.wikipedia.org/wiki/Longest_common_subsequence_problem
   */
-  void lcs(ComplexSelectorDeque& x, ComplexSelectorDeque& y, const LcsCollectionComparator& comparator, Context& ctx, ComplexSelectorDeque& out) {
+  void lcs(ComplexSelectorDeque& x, ComplexSelectorDeque& y, const LcsCollectionComparator& comparator, ComplexSelectorDeque& out) {
     //DEBUG_PRINTLN(LCS, "LCS: X=" << x << " Y=" << y)
     // TODO: make printComplexSelectorDeque and use DEBUG_EXEC AND DEBUG_PRINTLN HERE to get equivalent output
 
@@ -525,7 +516,7 @@
   /*
    - IMPROVEMENT: We could probably work directly in the output trimmed deque.
    */
-  static Node trim(Node& seqses, Context& ctx, bool isReplace) {
+  Node Extend::trim(Node& seqses, bool isReplace) {
     // See the comments in the above ruby code before embarking on understanding this function.
 
     // Avoid poor performance in extreme cases.
@@ -558,7 +549,7 @@
       for (NodeDeque::iterator seqs1Iter = seqs1.collection()->begin(), seqs1EndIter = seqs1.collection()->end(); seqs1Iter != seqs1EndIter; ++seqs1Iter) {
         Node& seq1 = *seqs1Iter;
 
-        Complex_Selector_Obj pSeq1 = nodeToComplexSelector(seq1, ctx);
+        Complex_Selector_Obj pSeq1 = nodeToComplexSelector(seq1);
 
         // Compute the maximum specificity. This requires looking at the "sources" of the sequence. See SimpleSequence.sources in the ruby code
         // for a good description of sources.
@@ -569,12 +560,12 @@
         // best guess at this point is that we're cloning an object somewhere and maintaining the sources when we shouldn't be. This is purely
         // a guess though.
         unsigned long maxSpecificity = isReplace ? pSeq1->specificity() : 0;
-        SourcesSet sources = pSeq1->sources();
+        ComplexSelectorSet sources = pSeq1->sources();
 
         DEBUG_PRINTLN(TRIM, "TRIM SEQ1: " << seq1)
-        DEBUG_EXEC(TRIM, printSourcesSet(sources, ctx, "TRIM SOURCES: "))
+        DEBUG_EXEC(TRIM, printSourcesSet(sources, "TRIM SOURCES: "))
 
-        for (SourcesSet::iterator sourcesSetIterator = sources.begin(), sourcesSetIteratorEnd = sources.end(); sourcesSetIterator != sourcesSetIteratorEnd; ++sourcesSetIterator) {
+        for (ComplexSelectorSet::iterator sourcesSetIterator = sources.begin(), sourcesSetIteratorEnd = sources.end(); sourcesSetIterator != sourcesSetIteratorEnd; ++sourcesSetIterator) {
           const Complex_Selector_Obj& pCurrentSelector = *sourcesSetIterator;
           maxSpecificity = std::max(maxSpecificity, pCurrentSelector->specificity());
         }
@@ -605,7 +596,7 @@
           for (NodeDeque::iterator seqs2Iter = seqs2.collection()->begin(), seqs2IterEnd = seqs2.collection()->end(); seqs2Iter != seqs2IterEnd; ++seqs2Iter) {
             Node& seq2 = *seqs2Iter;
 
-            Complex_Selector_Obj pSeq2 = nodeToComplexSelector(seq2, ctx);
+            Complex_Selector_Obj pSeq2 = nodeToComplexSelector(seq2);
 
             DEBUG_PRINTLN(TRIM, "SEQ2 SPEC: " << pSeq2->specificity())
             DEBUG_PRINTLN(TRIM, "IS SPEC: " << pSeq2->specificity() << " >= " << maxSpecificity << " " << (pSeq2->specificity() >= maxSpecificity ? "true" : "false"))
@@ -649,19 +640,18 @@
 
 
 
-  static bool parentSuperselector(const Node& one, const Node& two, Context& ctx) {
+  static bool parentSuperselector(const Node& one, const Node& two) {
     // TODO: figure out a better way to create a Complex_Selector from scratch
     // TODO: There's got to be a better way. This got ugly quick...
-    Position noPosition(-1, -1, -1);
     Element_Selector_Obj fakeParent = SASS_MEMORY_NEW(Element_Selector, ParserState("[FAKE]"), "temp");
     Compound_Selector_Obj fakeHead = SASS_MEMORY_NEW(Compound_Selector, ParserState("[FAKE]"), 1 /*size*/);
-    fakeHead->elements().push_back(&fakeParent);
-    Complex_Selector_Obj fakeParentContainer = SASS_MEMORY_NEW(Complex_Selector, ParserState("[FAKE]"), Complex_Selector::ANCESTOR_OF, &fakeHead /*head*/, NULL /*tail*/);
+    fakeHead->elements().push_back(fakeParent);
+    Complex_Selector_Obj fakeParentContainer = SASS_MEMORY_NEW(Complex_Selector, ParserState("[FAKE]"), Complex_Selector::ANCESTOR_OF, fakeHead /*head*/, NULL /*tail*/);
 
-    Complex_Selector_Obj pOneWithFakeParent = nodeToComplexSelector(one, ctx);
-    pOneWithFakeParent->set_innermost(&fakeParentContainer, Complex_Selector::ANCESTOR_OF);
-    Complex_Selector_Obj pTwoWithFakeParent = nodeToComplexSelector(two, ctx);
-    pTwoWithFakeParent->set_innermost(&fakeParentContainer, Complex_Selector::ANCESTOR_OF);
+    Complex_Selector_Obj pOneWithFakeParent = nodeToComplexSelector(one);
+    pOneWithFakeParent->set_innermost(fakeParentContainer, Complex_Selector::ANCESTOR_OF);
+    Complex_Selector_Obj pTwoWithFakeParent = nodeToComplexSelector(two);
+    pTwoWithFakeParent->set_innermost(fakeParentContainer, Complex_Selector::ANCESTOR_OF);
 
     return pOneWithFakeParent->is_superselector_of(pTwoWithFakeParent);
   }
@@ -669,14 +659,13 @@
 
   class ParentSuperselectorChunker {
   public:
-    ParentSuperselectorChunker(Node& lcs, Context& ctx) : mLcs(lcs), mCtx(ctx) {}
+    ParentSuperselectorChunker(Node& lcs) : mLcs(lcs) {}
     Node& mLcs;
-    Context& mCtx;
 
     bool operator()(const Node& seq) const {
       // {|s| parent_superselector?(s.first, lcs.first)}
       if (seq.collection()->size() == 0) return false;
-      return parentSuperselector(seq.collection()->front(), mLcs.collection()->front(), mCtx);
+      return parentSuperselector(seq.collection()->front(), mLcs.collection()->front());
     }
   };
 
@@ -730,7 +719,7 @@
     }
 
     Node chunk2 = Node::createCollection();
-    while (!chunker(seq2)) {
+    while (!seq2.collection()->empty() && !chunker(seq2)) {
       chunk2.collection()->push_back(seq2.collection()->front());
       seq2.collection()->pop_front();
     }
@@ -772,7 +761,7 @@
   }
 
 
-  static Node groupSelectors(Node& seq, Context& ctx) {
+  static Node groupSelectors(Node& seq) {
     Node newSeq = Node::createCollection();
 
     Node tail = Node::createCollection();
@@ -832,7 +821,7 @@
         return (newline ? ["\n"] : []) + (ops1.size > ops2.size ? ops1 : ops2)
       end
   */
-  static Node mergeInitialOps(Node& seq1, Node& seq2, Context& ctx) {
+  static Node mergeInitialOps(Node& seq1, Node& seq2) {
     Node ops1 = Node::createCollection();
     Node ops2 = Node::createCollection();
 
@@ -846,9 +835,9 @@
 
     // If neither sequence is a subsequence of the other, they cannot be merged successfully
     DefaultLcsComparator lcsDefaultComparator;
-    Node opsLcs = lcs(ops1, ops2, lcsDefaultComparator, ctx);
+    Node opsLcs = lcs(ops1, ops2, lcsDefaultComparator);
 
-    if (!(nodesEqual(opsLcs, ops1, true) || nodesEqual(opsLcs, ops2, true))) {
+    if (!(opsLcs == ops1 || opsLcs == ops2)) {
       return Node::createNil();
     }
 
@@ -923,7 +912,7 @@
         end
       end
   */
-  static Node mergeFinalOps(Node& seq1, Node& seq2, Context& ctx, Node& res) {
+  static Node mergeFinalOps(Node& seq1, Node& seq2, Node& res) {
 
     Node ops1 = Node::createCollection();
     Node ops2 = Node::createCollection();
@@ -941,11 +930,11 @@
 
     if (ops1.collection()->size() > 1 || ops2.collection()->size() > 1) {
       DefaultLcsComparator lcsDefaultComparator;
-      Node opsLcs = lcs(ops1, ops2, lcsDefaultComparator, ctx);
+      Node opsLcs = lcs(ops1, ops2, lcsDefaultComparator);
 
       // If there are multiple operators, something hacky's going on. If one is a supersequence of the other, use that, otherwise give up.
 
-      if (!(nodesEqual(opsLcs, ops1, true) || nodesEqual(opsLcs, ops2, true))) {
+      if (!(opsLcs == ops1 || opsLcs == ops2)) {
         return Node::createNil();
       }
 
@@ -988,7 +977,7 @@
 
           Complex_Selector_Obj pMergedWrapper = SASS_MEMORY_CLONE(sel1.selector()); // Clone the Complex_Selector to get back to something we can transform to a node once we replace the head with the unification result
           // TODO: does subject matter? Ruby: return unless merged = sel1.unify(sel2.members, sel2.subject?)
-          Compound_Selector_Ptr pMerged = sel1.selector()->head()->unify_with(&sel2.selector()->head(), ctx);
+          Compound_Selector_Ptr pMerged = sel1.selector()->head()->unify_with(sel2.selector()->head());
           pMergedWrapper->head(pMerged);
 
           DEBUG_EXEC(ALL, printCompoundSelector(pMerged, "MERGED: "))
@@ -1011,7 +1000,7 @@
 
           if (pMerged) {
             Node mergedPerm = Node::createCollection();
-            mergedPerm.collection()->push_back(Node::createSelector(&pMergedWrapper, ctx));
+            mergedPerm.collection()->push_back(Node::createSelector(pMergedWrapper));
             mergedPerm.collection()->push_back(Node::createCombinator(Complex_Selector::PRECEDES));
             newRes.collection()->push_back(mergedPerm);
           }
@@ -1025,12 +1014,10 @@
       } else if (((op1.combinator() == Complex_Selector::PRECEDES && op2.combinator() == Complex_Selector::ADJACENT_TO)) || ((op1.combinator() == Complex_Selector::ADJACENT_TO && op2.combinator() == Complex_Selector::PRECEDES))) {
 
           Node tildeSel = sel1;
-          Node tildeOp = op1;
           Node plusSel = sel2;
           Node plusOp = op2;
           if (op1.combinator() != Complex_Selector::PRECEDES) {
             tildeSel = sel2;
-            tildeOp = op2;
             plusSel = sel1;
             plusOp = op1;
           }
@@ -1047,7 +1034,7 @@
 
             Complex_Selector_Obj pMergedWrapper = SASS_MEMORY_CLONE(plusSel.selector()); // Clone the Complex_Selector to get back to something we can transform to a node once we replace the head with the unification result
             // TODO: does subject matter? Ruby: merged = plus_sel.unify(tilde_sel.members, tilde_sel.subject?)
-            Compound_Selector_Ptr pMerged = plusSel.selector()->head()->unify_with(&tildeSel.selector()->head(), ctx);
+            Compound_Selector_Ptr pMerged = plusSel.selector()->head()->unify_with(tildeSel.selector()->head());
             pMergedWrapper->head(pMerged);
 
             DEBUG_EXEC(ALL, printCompoundSelector(pMerged, "MERGED: "))
@@ -1063,7 +1050,7 @@
 
             if (pMerged) {
               Node mergedPerm = Node::createCollection();
-              mergedPerm.collection()->push_back(Node::createSelector(&pMergedWrapper, ctx));
+              mergedPerm.collection()->push_back(Node::createSelector(pMergedWrapper));
               mergedPerm.collection()->push_back(Node::createCombinator(Complex_Selector::ADJACENT_TO));
               newRes.collection()->push_back(mergedPerm);
             }
@@ -1096,7 +1083,7 @@
 
         Complex_Selector_Obj pMergedWrapper = SASS_MEMORY_CLONE(sel1.selector()); // Clone the Complex_Selector to get back to something we can transform to a node once we replace the head with the unification result
         // TODO: does subject matter? Ruby: return unless merged = sel1.unify(sel2.members, sel2.subject?)
-        Compound_Selector_Ptr pMerged = sel1.selector()->head()->unify_with(&sel2.selector()->head(), ctx);
+        Compound_Selector_Ptr pMerged = sel1.selector()->head()->unify_with(sel2.selector()->head());
         pMergedWrapper->head(pMerged);
 
         DEBUG_EXEC(ALL, printCompoundSelector(pMerged, "MERGED: "))
@@ -1106,7 +1093,7 @@
         }
 
         res.collection()->push_front(op1);
-        res.collection()->push_front(Node::createSelector(&pMergedWrapper, ctx));
+        res.collection()->push_front(Node::createSelector(pMergedWrapper));
 
         DEBUG_PRINTLN(ALL, "RESULT: " << res)
 
@@ -1114,7 +1101,7 @@
         return Node::createNil();
       }
 
-      return mergeFinalOps(seq1, seq2, ctx, res);
+      return mergeFinalOps(seq1, seq2, res);
 
     } else if (!ops1.collection()->empty()) {
 
@@ -1129,7 +1116,7 @@
       res.collection()->push_front(seq1.collection()->back());
       seq1.collection()->pop_back();
 
-      return mergeFinalOps(seq1, seq2, ctx, res);
+      return mergeFinalOps(seq1, seq2, res);
 
     } else { // !ops2.collection()->empty()
 
@@ -1143,7 +1130,7 @@
       res.collection()->push_front(seq2.collection()->back());
       seq2.collection()->pop_back();
 
-      return mergeFinalOps(seq1, seq2, ctx, res);
+      return mergeFinalOps(seq1, seq2, res);
 
     }
 
@@ -1186,7 +1173,7 @@
         result
       end
   */
-  Node Extend::subweave(Node& one, Node& two, Context& ctx) {
+  Node subweave(Node& one, Node& two) {
     // Check for the simple cases
     if (one.collection()->size() == 0) {
       Node out = Node::createCollection();
@@ -1199,8 +1186,6 @@
       return out;
     }
 
-
-
     Node seq1 = Node::createCollection();
     seq1.plus(one);
     Node seq2 = Node::createCollection();
@@ -1209,7 +1194,7 @@
     DEBUG_PRINTLN(SUBWEAVE, "SUBWEAVE ONE: " << seq1)
     DEBUG_PRINTLN(SUBWEAVE, "SUBWEAVE TWO: " << seq2)
 
-    Node init = mergeInitialOps(seq1, seq2, ctx);
+    Node init = mergeInitialOps(seq1, seq2);
     if (init.isNil()) {
       return Node::createNil();
     }
@@ -1217,7 +1202,7 @@
     DEBUG_PRINTLN(SUBWEAVE, "INIT: " << init)
 
     Node res = Node::createCollection();
-    Node fin = mergeFinalOps(seq1, seq2, ctx, res);
+    Node fin = mergeFinalOps(seq1, seq2, res);
     if (fin.isNil()) {
       return Node::createNil();
     }
@@ -1245,23 +1230,23 @@
 
 
 
-    Node groupSeq1 = groupSelectors(seq1, ctx);
+    Node groupSeq1 = groupSelectors(seq1);
     DEBUG_PRINTLN(SUBWEAVE, "SEQ1: " << groupSeq1)
 
-    Node groupSeq2 = groupSelectors(seq2, ctx);
+    Node groupSeq2 = groupSelectors(seq2);
     DEBUG_PRINTLN(SUBWEAVE, "SEQ2: " << groupSeq2)
 
 
     ComplexSelectorDeque groupSeq1Converted;
-    nodeToComplexSelectorDeque(groupSeq1, groupSeq1Converted, ctx);
+    nodeToComplexSelectorDeque(groupSeq1, groupSeq1Converted);
 
     ComplexSelectorDeque groupSeq2Converted;
-    nodeToComplexSelectorDeque(groupSeq2, groupSeq2Converted, ctx);
+    nodeToComplexSelectorDeque(groupSeq2, groupSeq2Converted);
 
     ComplexSelectorDeque out;
-    LcsCollectionComparator collectionComparator(ctx);
-    lcs(groupSeq2Converted, groupSeq1Converted, collectionComparator, ctx, out);
-    Node seqLcs = complexSelectorDequeToNode(out, ctx);
+    LcsCollectionComparator collectionComparator;
+    lcs(groupSeq2Converted, groupSeq1Converted, collectionComparator, out);
+    Node seqLcs = complexSelectorDequeToNode(out);
 
     DEBUG_PRINTLN(SUBWEAVE, "SEQLCS: " << seqLcs)
 
@@ -1275,7 +1260,7 @@
 
 
     while (!seqLcs.collection()->empty()) {
-      ParentSuperselectorChunker superselectorChunker(seqLcs, ctx);
+      ParentSuperselectorChunker superselectorChunker(seqLcs);
       Node chunksResult = chunks(groupSeq1, groupSeq2, superselectorChunker);
       diff.collection()->push_back(chunksResult);
 
@@ -1320,7 +1305,7 @@
     DEBUG_PRINTLN(SUBWEAVE, "DIFF POST REJECT: " << diff)
 
 
-    Node pathsResult = paths(diff, ctx);
+    Node pathsResult = paths(diff);
 
     DEBUG_PRINTLN(SUBWEAVE, "PATHS: " << pathsResult)
 
@@ -1330,7 +1315,7 @@
       pathsIter != pathsEndIter; ++pathsIter) {
 
       Node& child = *pathsIter;
-      child = flatten(child, ctx);
+      child = flatten(child);
     }
 
     DEBUG_PRINTLN(SUBWEAVE, "FLATTENED: " << pathsResult)
@@ -1348,25 +1333,25 @@
   }
   /*
   // disabled to avoid clang warning [-Wunused-function]
-  static Node subweaveNaive(const Node& one, const Node& two, Context& ctx) {
+  static Node subweaveNaive(const Node& one, const Node& two) {
     Node out = Node::createCollection();
 
     // Check for the simple cases
     if (one.isNil()) {
-      out.collection()->push_back(two.klone(ctx));
+      out.collection()->push_back(two.klone());
     } else if (two.isNil()) {
-      out.collection()->push_back(one.klone(ctx));
+      out.collection()->push_back(one.klone());
     } else {
       // Do the naive implementation. pOne = A B and pTwo = C D ...yields...  A B C D and C D A B
       // See https://gist.github.com/nex3/7609394 for details.
 
-      Node firstPerm = one.klone(ctx);
-      Node twoCloned = two.klone(ctx);
+      Node firstPerm = one.klone();
+      Node twoCloned = two.klone();
       firstPerm.plus(twoCloned);
       out.collection()->push_back(firstPerm);
 
-      Node secondPerm = two.klone(ctx);
-      Node oneCloned = one.klone(ctx);
+      Node secondPerm = two.klone();
+      Node oneCloned = one.klone();
       secondPerm.plus(oneCloned );
       out.collection()->push_back(secondPerm);
     }
@@ -1449,7 +1434,7 @@
         return befores
       end
   */
-  static Node weave(Node& path, Context& ctx) {
+  Node Extend::weave(Node& path) {
 
     DEBUG_PRINTLN(WEAVE, "WEAVE: " << path)
 
@@ -1460,7 +1445,7 @@
     afters.plus(path);
 
     while (!afters.collection()->empty()) {
-      Node current = afters.collection()->front().klone(ctx);
+      Node current = afters.collection()->front().klone();
       afters.collection()->pop_front();
       DEBUG_PRINTLN(WEAVE, "CURRENT: " << current)
       if (current.collection()->size() == 0) continue;
@@ -1476,7 +1461,7 @@
       for (NodeDeque::iterator beforesIter = befores.collection()->begin(), beforesEndIter = befores.collection()->end(); beforesIter != beforesEndIter; beforesIter++) {
         Node& before = *beforesIter;
 
-        Node sub = Extend::subweave(before, current, ctx);
+        Node sub = subweave(before, current);
 
         DEBUG_PRINTLN(WEAVE, "SUB: " << sub)
 
@@ -1491,6 +1476,13 @@
           toPush.plus(seqs);
           toPush.plus(last_current);
 
+          // move line feed from inner to outer selector (very hacky indeed)
+          if (last_current.collection() && last_current.collection()->front().selector()) {
+            toPush.got_line_feed = last_current.collection()->front().got_line_feed;
+            last_current.collection()->front().selector()->has_line_feed(false);
+            last_current.collection()->front().got_line_feed = false;
+          }
+
           tempResult.collection()->push_back(toPush);
 
         }
@@ -1505,16 +1497,6 @@
 
 
 
-  // This forward declaration is needed since extendComplexSelector calls extendCompoundSelector, which may recursively
-  // call extendComplexSelector again.
-  static Node extendComplexSelector(
-    Complex_Selector_Ptr pComplexSelector,
-    Context& ctx,
-    Subset_Map& subset_map,
-    std::set<Compound_Selector> seen, bool isReplace, bool isOriginal);
-
-
-
   /*
    This is the equivalent of ruby's SimpleSequence.do_extend.
 
@@ -1530,65 +1512,60 @@
   template<typename KeyType>
   class GroupByToAFunctor {
   public:
-    KeyType operator()(ExtensionPair& extPair) const {
+    KeyType operator()(SubSetMapPair& extPair) const {
       Complex_Selector_Obj pSelector = extPair.first;
-      return &pSelector;
+      return pSelector;
     }
   };
-  static Node extendCompoundSelector(
-    Compound_Selector_Ptr pSelector,
-    Context& ctx,
-    Subset_Map& subset_map,
-    std::set<Compound_Selector> seen, bool isReplace) {
+  Node Extend::extendCompoundSelector(Compound_Selector_Ptr pSelector, CompoundSelectorSet& seen, bool isReplace) {
 
+    /* this turned out to be too much overhead
+       probably due to holding a "Node" object
+    // check if we already extended this selector
+    // we can do this since subset_map is "static"
+    auto memoized = memoizeCompound.find(pSelector);
+    if (memoized != memoizeCompound.end()) {
+      return memoized->second.klone();
+    }
+    */
+
     DEBUG_EXEC(EXTEND_COMPOUND, printCompoundSelector(pSelector, "EXTEND COMPOUND: "))
     // TODO: Ruby has another loop here to skip certain members?
 
-    Node extendedSelectors = Node::createCollection();
+    // let RESULTS be an empty list of complex selectors
+    Node results = Node::createCollection();
     // extendedSelectors.got_line_feed = true;
 
-    SubsetMapEntries entries = subset_map.get_v(pSelector);
-
-    typedef std::vector<std::pair<Complex_Selector_Obj, std::vector<ExtensionPair> > > GroupedByToAResult;
+    SubSetMapPairs entries = subset_map.get_v(pSelector);
 
     GroupByToAFunctor<Complex_Selector_Obj> extPairKeyFunctor;
-    GroupedByToAResult arr;
+    SubSetMapResults arr;
     group_by_to_a(entries, extPairKeyFunctor, arr);
 
-    typedef std::pair<Compound_Selector_Obj, Complex_Selector_Obj> SelsNewSeqPair;
-    typedef std::vector<SelsNewSeqPair> SelsNewSeqPairCollection;
-
-
-    SelsNewSeqPairCollection holder;
-
+    SubSetMapLookups holder;
 
-    for (GroupedByToAResult::iterator groupedIter = arr.begin(), groupedIterEnd = arr.end(); groupedIter != groupedIterEnd; groupedIter++) {
-      std::pair<Complex_Selector_Obj, std::vector<ExtensionPair> >& groupedPair = *groupedIter;
+    // for each (EXTENDER, TARGET) in MAP.get(COMPOUND):
+    for (SubSetMapResult& groupedPair : arr) {
 
       Complex_Selector_Obj seq = groupedPair.first;
-      std::vector<ExtensionPair>& group = groupedPair.second;
+      SubSetMapPairs& group = groupedPair.second;
 
-      DEBUG_EXEC(EXTEND_COMPOUND, printComplexSelector(&seq, "SEQ: "))
+      DEBUG_EXEC(EXTEND_COMPOUND, printComplexSelector(seq, "SEQ: "))
 
-// changing this makes aua
       Compound_Selector_Obj pSels = SASS_MEMORY_NEW(Compound_Selector, pSelector->pstate());
-      for (std::vector<ExtensionPair>::iterator groupIter = group.begin(), groupIterEnd = group.end(); groupIter != groupIterEnd; groupIter++) {
-        ExtensionPair& pair = *groupIter;
-        Compound_Selector_Obj pCompound = pair.second;
-        for (size_t index = 0; index < pCompound->length(); index++) {
-          Simple_Selector_Obj pSimpleSelector = (*pCompound)[index];
-          pSels->append(&pSimpleSelector);
-          pCompound->extended(true);
-        }
+      for (SubSetMapPair& pair : group) {
+        pair.second->extended(true);
+        pSels->concat(pair.second);
       }
 
-      DEBUG_EXEC(EXTEND_COMPOUND, printCompoundSelector(&pSels, "SELS: "))
+      DEBUG_EXEC(EXTEND_COMPOUND, printCompoundSelector(pSels, "SELS: "))
 
-      Complex_Selector_Ptr pExtComplexSelector = &seq;    // The selector up to where the @extend is (ie, the thing to merge)
+      // The selector up to where the @extend is (ie, the thing to merge)
+      Complex_Selector_Ptr pExtComplexSelector = seq;
 
       // TODO: This can return a Compound_Selector with no elements. Should that just be returning NULL?
       // RUBY: self_without_sel = Sass::Util.array_minus(members, sels)
-      Compound_Selector_Obj pSelectorWithoutExtendSelectors = pSelector->minus(&pSels, ctx);
+      Compound_Selector_Obj pSelectorWithoutExtendSelectors = pSelector->minus(pSels);
 
       DEBUG_EXEC(EXTEND_COMPOUND, printCompoundSelector(pSelector, "MEMBERS: "))
       DEBUG_EXEC(EXTEND_COMPOUND, printCompoundSelector(pSelectorWithoutExtendSelectors, "SELF_WO_SEL: "))
@@ -1598,7 +1575,7 @@
       if (!pInnermostCompoundSelector) {
         pInnermostCompoundSelector = SASS_MEMORY_NEW(Compound_Selector, pSelector->pstate());
       }
-      Compound_Selector_Obj pUnifiedSelector = pInnermostCompoundSelector->unify_with(&pSelectorWithoutExtendSelectors, ctx);
+      Compound_Selector_Obj pUnifiedSelector = pInnermostCompoundSelector->unify_with(pSelectorWithoutExtendSelectors);
 
       DEBUG_EXEC(EXTEND_COMPOUND, printCompoundSelector(pInnermostCompoundSelector, "LHS: "))
       DEBUG_EXEC(EXTEND_COMPOUND, printCompoundSelector(pSelectorWithoutExtendSelectors, "RHS: "))
@@ -1621,10 +1598,10 @@
       Complex_Selector_Obj pNewInnerMost = SASS_MEMORY_NEW(Complex_Selector, pSelector->pstate(), Complex_Selector::ANCESTOR_OF, pUnifiedSelector, NULL);
 
       Complex_Selector::Combinator combinator = pNewSelector->clear_innermost();
-      pNewSelector->set_innermost(&pNewInnerMost, combinator);
+      pNewSelector->set_innermost(pNewInnerMost, combinator);
 
 #ifdef DEBUG
-      SourcesSet debugSet;
+      ComplexSelectorSet debugSet;
       debugSet = pNewSelector->sources();
       if (debugSet.size() > 0) {
         throw std::runtime_error("The new selector should start with no sources. Something needs to be cloned to fix this.");
@@ -1638,21 +1615,22 @@
 
       // if (pSelector && pSelector->has_line_feed()) pNewInnerMost->has_line_feed(true);
       // Set the sources on our new Complex_Selector to the sources of this simple sequence plus the thing we're extending.
-      DEBUG_PRINTLN(EXTEND_COMPOUND, "SOURCES SETTING ON NEW SEQ: " << complexSelectorToNode(pNewSelector, ctx))
+      DEBUG_PRINTLN(EXTEND_COMPOUND, "SOURCES SETTING ON NEW SEQ: " << complexSelectorToNode(pNewSelector))
 
-      DEBUG_EXEC(EXTEND_COMPOUND, SourcesSet oldSet = pNewSelector->sources(); printSourcesSet(oldSet, ctx, "SOURCES NEW SEQ BEGIN: "))
+      DEBUG_EXEC(EXTEND_COMPOUND, ComplexSelectorSet oldSet = pNewSelector->sources(); printSourcesSet(oldSet, "SOURCES NEW SEQ BEGIN: "))
 
-      SourcesSet newSourcesSet = pSelector->sources();
-      DEBUG_EXEC(EXTEND_COMPOUND, printSourcesSet(newSourcesSet, ctx, "SOURCES THIS EXTEND: "))
+      // I actually want to create a copy here (performance!)
+      ComplexSelectorSet newSourcesSet = pSelector->sources(); // XXX
+      DEBUG_EXEC(EXTEND_COMPOUND, printSourcesSet(newSourcesSet, "SOURCES THIS EXTEND: "))
 
       newSourcesSet.insert(pExtComplexSelector);
-      DEBUG_EXEC(EXTEND_COMPOUND, printSourcesSet(newSourcesSet, ctx, "SOURCES WITH NEW SOURCE: "))
+      DEBUG_EXEC(EXTEND_COMPOUND, printSourcesSet(newSourcesSet, "SOURCES WITH NEW SOURCE: "))
 
       // RUBY: new_seq.add_sources!(sources + [seq])
-      pNewSelector->addSources(newSourcesSet, ctx);
+      pNewSelector->addSources(newSourcesSet);
 
-      DEBUG_EXEC(EXTEND_COMPOUND, SourcesSet newSet = pNewSelector->sources(); printSourcesSet(newSet, ctx, "SOURCES ON NEW SELECTOR AFTER ADD: "))
-      DEBUG_EXEC(EXTEND_COMPOUND, printSourcesSet(pSelector->sources(), ctx, "SOURCES THIS EXTEND WHICH SHOULD BE SAME STILL: "))
+      DEBUG_EXEC(EXTEND_COMPOUND, ComplexSelectorSet newSet = pNewSelector->sources(); printSourcesSet(newSet, "SOURCES ON NEW SELECTOR AFTER ADD: "))
+      DEBUG_EXEC(EXTEND_COMPOUND, printSourcesSet(pSelector->sources(), "SOURCES THIS EXTEND WHICH SHOULD BE SAME STILL: "))
 
 
       if (pSels->has_line_feed()) pNewSelector->has_line_feed(true);
@@ -1661,25 +1639,24 @@
     }
 
 
-    for (SelsNewSeqPairCollection::iterator holderIter = holder.begin(), holderIterEnd = holder.end(); holderIter != holderIterEnd; holderIter++) {
-      SelsNewSeqPair& pair = *holderIter;
+    for (SubSetMapLookup& pair : holder) {
 
       Compound_Selector_Obj pSels = pair.first;
       Complex_Selector_Obj pNewSelector = pair.second;
 
 
       // RUBY??: next [] if seen.include?(sels)
-      if (seen.find(*pSels) != seen.end()) {
+      if (seen.find(pSels) != seen.end()) {
         continue;
       }
 
 
-      std::set<Compound_Selector> recurseSeen(seen);
-      recurseSeen.insert(*pSels);
+      CompoundSelectorSet recurseSeen(seen);
+      recurseSeen.insert(pSels);
 
 
-      DEBUG_PRINTLN(EXTEND_COMPOUND, "RECURSING DO EXTEND: " << complexSelectorToNode(pNewSelector, ctx))
-      Node recurseExtendedSelectors = extendComplexSelector(&pNewSelector, ctx, subset_map, recurseSeen, isReplace, false); // !:isOriginal
+      DEBUG_PRINTLN(EXTEND_COMPOUND, "RECURSING DO EXTEND: " << complexSelectorToNode(pNewSelector))
+      Node recurseExtendedSelectors = extendComplexSelector(pNewSelector, recurseSeen, isReplace, false); // !:isOriginal
 
       DEBUG_PRINTLN(EXTEND_COMPOUND, "RECURSING DO EXTEND RETURN: " << recurseExtendedSelectors)
 
@@ -1687,38 +1664,39 @@
            iterator != endIterator; ++iterator) {
         Node newSelector = *iterator;
 
-//        DEBUG_PRINTLN(EXTEND_COMPOUND, "EXTENDED AT THIS POINT: " << extendedSelectors)
-//        DEBUG_PRINTLN(EXTEND_COMPOUND, "SELECTOR EXISTS ALREADY: " << newSelector << " " << extendedSelectors.contains(newSelector, false /*simpleSelectorOrderDependent*/));
+//        DEBUG_PRINTLN(EXTEND_COMPOUND, "EXTENDED AT THIS POINT: " << results)
+//        DEBUG_PRINTLN(EXTEND_COMPOUND, "SELECTOR EXISTS ALREADY: " << newSelector << " " << results.contains(newSelector, false /*simpleSelectorOrderDependent*/));
 
-        if (!extendedSelectors.contains(newSelector, false /*simpleSelectorOrderDependent*/)) {
+        if (!results.contains(newSelector)) {
 //          DEBUG_PRINTLN(EXTEND_COMPOUND, "ADDING NEW SELECTOR")
-          extendedSelectors.collection()->push_back(newSelector);
+          results.collection()->push_back(newSelector);
         }
       }
     }
 
     DEBUG_EXEC(EXTEND_COMPOUND, printCompoundSelector(pSelector, "EXTEND COMPOUND END: "))
 
-    return extendedSelectors;
+    // this turned out to be too much overhead
+    // memory results in a map table - since extending is very expensive
+    // memoizeCompound.insert(std::pair<Compound_Selector_Obj, Node>(pSelector, results));
+
+    return results;
   }
 
 
-  static bool complexSelectorHasExtension(
-    Complex_Selector_Ptr pComplexSelector,
-    Context& ctx,
-    Subset_Map& subset_map,
-    std::set<Compound_Selector>& seen) {
+  // check if selector has something to be extended by subset_map
+  bool Extend::complexSelectorHasExtension(Complex_Selector_Ptr selector, CompoundSelectorSet& seen) {
 
     bool hasExtension = false;
 
-    Complex_Selector_Obj pIter = pComplexSelector;
+    Complex_Selector_Obj pIter = selector;
 
     while (!hasExtension && pIter) {
       Compound_Selector_Obj pHead = pIter->head();
 
       if (pHead) {
-        SubsetMapEntries entries = subset_map.get_v(pHead);
-        for (ExtensionPair ext : entries) {
+        SubSetMapPairs entries = subset_map.get_v(pHead);
+        for (SubSetMapPair ext : entries) {
           // check if both selectors have the same media block parent
           // if (ext.first->media_block() == pComplexSelector->media_block()) continue;
           if (ext.second->media_block() == 0) continue;
@@ -1726,8 +1704,8 @@
               ext.second->media_block()->media_queries() &&
               pHead->media_block()->media_queries()
           ) {
-            std::string query_left(ext.second->media_block()->media_queries()->to_string(ctx.c_options));
-            std::string query_right(pHead->media_block()->media_queries()->to_string(ctx.c_options));
+            std::string query_left(ext.second->media_block()->media_queries()->to_string());
+            std::string query_right(pHead->media_block()->media_queries()->to_string());
             if (query_left == query_right) continue;
           }
 
@@ -1738,9 +1716,9 @@
           std::string rel_path(Sass::File::abs2rel(pstate.path, cwd, cwd));
           err << "You may not @extend an outer selector from within @media.\n";
           err << "You may only @extend selectors within the same directive.\n";
-          err << "From \"@extend " << ext.second->to_string(ctx.c_options) << "\"";
+          err << "From \"@extend " << ext.second->to_string() << "\"";
           err << " on line " << pstate.line+1 << " of " << rel_path << "\n";
-          error(err.str(), pComplexSelector->pstate());
+          error(err.str(), selector->pstate(), eval->exp.traces);
         }
         if (entries.size() > 0) hasExtension = true;
       }
@@ -1763,23 +1741,25 @@
      the combinator and compound selector are one unit
      next [[sseq_or_op]] unless sseq_or_op.is_a?(SimpleSequence)
    */
-  static Node extendComplexSelector(
-    Complex_Selector_Ptr pComplexSelector,
-    Context& ctx,
-    Subset_Map& subset_map,
-    std::set<Compound_Selector> seen, bool isReplace, bool isOriginal) {
+  Node Extend::extendComplexSelector(Complex_Selector_Ptr selector, CompoundSelectorSet& seen, bool isReplace, bool isOriginal) {
 
-    Node complexSelector = complexSelectorToNode(pComplexSelector, ctx);
-    DEBUG_PRINTLN(EXTEND_COMPLEX, "EXTEND COMPLEX: " << complexSelector)
+    // check if we already extended this selector
+    // we can do this since subset_map is "static"
+    auto memoized = memoizeComplex.find(selector);
+    if (memoized != memoizeComplex.end()) {
+      return memoized->second;
+    }
 
-    Node extendedNotExpanded = Node::createCollection();
+    // convert the input selector to extend node format
+    Node complexSelector = complexSelectorToNode(selector);
+    DEBUG_PRINTLN(EXTEND_COMPLEX, "EXTEND COMPLEX: " << complexSelector)
 
-    for (NodeDeque::iterator complexSelIter = complexSelector.collection()->begin(),
-                             complexSelIterEnd = complexSelector.collection()->end();
-         complexSelIter != complexSelIterEnd; ++complexSelIter)
-    {
+    // let CHOICES be an empty list of selector-lists
+    // create new collection to hold the results
+    Node choices = Node::createCollection();
 
-      Node& sseqOrOp = *complexSelIter;
+    // for each compound selector COMPOUND in COMPLEX:
+    for (Node& sseqOrOp : *complexSelector.collection()) {
 
       DEBUG_PRINTLN(EXTEND_COMPLEX, "LOOP: " << sseqOrOp)
 
@@ -1792,94 +1772,93 @@
         Node inner = Node::createCollection();
         outer.collection()->push_back(inner);
         inner.collection()->push_back(sseqOrOp);
-        extendedNotExpanded.collection()->push_back(outer);
+        choices.collection()->push_back(outer);
         continue;
       }
 
-      Compound_Selector_Obj pCompoundSelector = sseqOrOp.selector()->head();
+      // verified now that node is a valid selector
+      Complex_Selector_Obj sseqSel = sseqOrOp.selector();
+      Compound_Selector_Obj sseqHead = sseqSel->head();
 
+      // let EXTENDED be extend_compound(COMPOUND, SEEN)
+      // extend the compound selector against the given subset_map
       // RUBY: extended = sseq_or_op.do_extend(extends, parent_directives, replace, seen)
-      Node extended = extendCompoundSelector(&pCompoundSelector, ctx, subset_map, seen, isReplace);
+      Node extended = extendCompoundSelector(sseqHead, seen, isReplace); // slow(17%)!
       if (sseqOrOp.got_line_feed) extended.got_line_feed = true;
       DEBUG_PRINTLN(EXTEND_COMPLEX, "EXTENDED: " << extended)
 
-
-      // Prepend the Compound_Selector based on the choices logic; choices seems to be extend but with an ruby Array instead of a Sequence
-      // due to the member mapping: choices = extended.map {|seq| seq.members}
-      Complex_Selector_Obj pJustCurrentCompoundSelector = sseqOrOp.selector();
-
+      // Prepend the Compound_Selector based on the choices logic; choices seems to be extend but with a ruby
+      // Array instead of a Sequence due to the member mapping: choices = extended.map {|seq| seq.members}
       // RUBY: extended.first.add_sources!([self]) if original && !has_placeholder?
-      if (isOriginal && !pComplexSelector->has_placeholder()) {
-        SourcesSet srcset;
-        srcset.insert(pComplexSelector);
-        pJustCurrentCompoundSelector->addSources(srcset, ctx);
-        DEBUG_PRINTLN(EXTEND_COMPLEX, "ADD SOURCES: " << *pComplexSelector)
+      if (isOriginal && !selector->has_placeholder()) {
+        ComplexSelectorSet srcset;
+        srcset.insert(selector);
+        sseqSel->addSources(srcset);
+        // DEBUG_PRINTLN(EXTEND_COMPLEX, "ADD SOURCES: " << *pComplexSelector)
       }
 
       bool isSuperselector = false;
-      for (NodeDeque::iterator iterator = extended.collection()->begin(), endIterator = extended.collection()->end();
-           iterator != endIterator; ++iterator) {
-        Node& childNode = *iterator;
-        Complex_Selector_Obj pExtensionSelector = nodeToComplexSelector(childNode, ctx);
-        if (pExtensionSelector->is_superselector_of(pJustCurrentCompoundSelector)) {
+      // if no complex selector in EXTENDED is a superselector of COMPOUND:
+      for (Node& childNode : *extended.collection()) {
+        Complex_Selector_Obj pExtensionSelector = nodeToComplexSelector(childNode);
+        if (pExtensionSelector->is_superselector_of(sseqSel)) {
           isSuperselector = true;
           break;
         }
       }
 
       if (!isSuperselector) {
-        if (sseqOrOp.got_line_feed) pJustCurrentCompoundSelector->has_line_feed(sseqOrOp.got_line_feed);
-        extended.collection()->push_front(complexSelectorToNode(&pJustCurrentCompoundSelector, ctx));
+        // add a complex selector composed only of COMPOUND to EXTENDED
+        if (sseqOrOp.got_line_feed) sseqSel->has_line_feed(sseqOrOp.got_line_feed);
+        extended.collection()->push_front(complexSelectorToNode(sseqSel));
       }
 
       DEBUG_PRINTLN(EXTEND_COMPLEX, "CHOICES UNSHIFTED: " << extended)
 
+      // add EXTENDED to CHOICES
       // Aggregate our current extensions
-      extendedNotExpanded.collection()->push_back(extended);
+      choices.collection()->push_back(extended);
     }
 
 
-    DEBUG_PRINTLN(EXTEND_COMPLEX, "EXTENDED NOT EXPANDED: " << extendedNotExpanded)
+    DEBUG_PRINTLN(EXTEND_COMPLEX, "EXTENDED NOT EXPANDED: " << choices)
 
 
 
     // Ruby Equivalent: paths
-    Node paths = Sass::paths(extendedNotExpanded, ctx);
+    Node paths = Sass::paths(choices);
 
     DEBUG_PRINTLN(EXTEND_COMPLEX, "PATHS: " << paths)
 
-
-
-    // Ruby Equivalent: weave
+    // let WEAVES be an empty list of selector lists
     Node weaves = Node::createCollection();
 
-    for (NodeDeque::iterator pathsIter = paths.collection()->begin(), pathsEndIter = paths.collection()->end(); pathsIter != pathsEndIter; ++pathsIter) {
-      Node& path = *pathsIter;
-      Node weaved = weave(path, ctx);
+    // for each list of complex selectors PATH in paths(CHOICES):
+    for (Node& path : *paths.collection()) {
+      // add weave(PATH) to WEAVES
+      Node weaved = weave(path); // slow(12%)!
       weaved.got_line_feed = path.got_line_feed;
       weaves.collection()->push_back(weaved);
     }
 
     DEBUG_PRINTLN(EXTEND_COMPLEX, "WEAVES: " << weaves)
 
-
-
     // Ruby Equivalent: trim
-    Node trimmed = trim(weaves, ctx, isReplace);
+    Node trimmed(trim(weaves, isReplace)); // slow(19%)!
 
     DEBUG_PRINTLN(EXTEND_COMPLEX, "TRIMMED: " << trimmed)
 
-
     // Ruby Equivalent: flatten
-    Node extendedSelectors = flatten(trimmed, ctx, 1);
+    Node flattened(flatten(trimmed, 1));
 
     DEBUG_PRINTLN(EXTEND_COMPLEX, ">>>>> EXTENDED: " << extendedSelectors)
-
-
     DEBUG_PRINTLN(EXTEND_COMPLEX, "EXTEND COMPLEX END: " << complexSelector)
 
+    // memory results in a map table - since extending is very expensive
+    memoizeComplex.insert(std::pair<Complex_Selector_Obj, Node>(selector, flattened));
 
-    return extendedSelectors;
+    // return trim(WEAVES)
+    return flattened;
   }
 
 
@@ -1887,20 +1866,23 @@
   /*
    This is the equivalent of ruby's CommaSequence.do_extend.
   */
-  Selector_List_Ptr Extend::extendSelectorList(Selector_List_Obj pSelectorList, Context& ctx, Subset_Map& subset_map, bool isReplace, bool& extendedSomething) {
-    std::set<Compound_Selector> seen;
-    return extendSelectorList(pSelectorList, ctx, subset_map, isReplace, extendedSomething, seen);
-  }
-
-  /*
-   This is the equivalent of ruby's CommaSequence.do_extend.
-  */
-  Selector_List_Ptr Extend::extendSelectorList(Selector_List_Obj pSelectorList, Context& ctx, Subset_Map& subset_map, bool isReplace, bool& extendedSomething, std::set<Compound_Selector>& seen) {
+  // We get a selector list with has something to extend and a subset_map with
+  // all extenders. Pick the ones that match our selectors in the list.
+  Selector_List_Ptr Extend::extendSelectorList(Selector_List_Obj pSelectorList, bool isReplace, bool& extendedSomething, CompoundSelectorSet& seen) {
 
     Selector_List_Obj pNewSelectors = SASS_MEMORY_NEW(Selector_List, pSelectorList->pstate(), pSelectorList->length());
 
-    extendedSomething = false;
+    // check if we already extended this selector
+    // we can do this since subset_map is "static"
+    auto memoized = memoizeList.find(pSelectorList);
+    if (memoized != memoizeList.end()) {
+      extendedSomething = true;
+      return memoized->second;
+    }
 
+    extendedSomething = false;
+    // process each comlplex selector in the selector list.
+    // Find the ones that can be extended by given subset_map.
     for (size_t index = 0, length = pSelectorList->length(); index < length; index++) {
       Complex_Selector_Obj pSelector = (*pSelectorList)[index];
 
@@ -1909,89 +1891,100 @@
       // run through the extend code (which does a data model transformation), check if there is anything to extend before doing
       // the extend. We might be able to optimize extendComplexSelector, but this approach keeps us closer to ruby sass (which helps
       // when debugging).
-      if (!complexSelectorHasExtension(&pSelector, ctx, subset_map, seen)) {
-        pNewSelectors->append(&pSelector);
+      if (!complexSelectorHasExtension(pSelector, seen)) {
+        pNewSelectors->append(pSelector);
         continue;
       }
 
+      // complexSelectorHasExtension was true!
       extendedSomething = true;
 
-      Node extendedSelectors = extendComplexSelector(&pSelector, ctx, subset_map, seen, isReplace, true);
+      // now do the actual extension of the complex selector
+      Node extendedSelectors = extendComplexSelector(pSelector, seen, isReplace, true);
+
       if (!pSelector->has_placeholder()) {
-        if (!extendedSelectors.contains(complexSelectorToNode(&pSelector, ctx), true /*simpleSelectorOrderDependent*/)) {
+        Node nSelector(complexSelectorToNode(pSelector));
+        if (!extendedSelectors.contains(nSelector)) {
           pNewSelectors->append(pSelector);
           continue;
         }
       }
 
-      for (NodeDeque::iterator iterator = extendedSelectors.collection()->begin(), iteratorBegin = extendedSelectors.collection()->begin(), iteratorEnd = extendedSelectors.collection()->end(); iterator != iteratorEnd; ++iterator) {
+      bool doReplace = isReplace;
+      for (Node& childNode : *extendedSelectors.collection()) {
         // When it is a replace, skip the first one, unless there is only one
-        if(isReplace && iterator == iteratorBegin && extendedSelectors.collection()->size() > 1 ) continue;
-
-        Node& childNode = *iterator;
-        pNewSelectors->append(nodeToComplexSelector(childNode, ctx));
+        if(doReplace && extendedSelectors.collection()->size() > 1 ) {
+          doReplace = false;
+          continue;
+        }
+        pNewSelectors->append(nodeToComplexSelector(childNode));
       }
     }
 
-    Remove_Placeholders remove_placeholders(ctx);
+    Remove_Placeholders remove_placeholders;
     // it seems that we have to remove the place holders early here
     // normally we do this as the very last step (compare to ruby sass)
-    pNewSelectors = remove_placeholders.remove_placeholders(&pNewSelectors);
+    pNewSelectors = remove_placeholders.remove_placeholders(pNewSelectors);
 
     // unwrap all wrapped selectors with inner lists
     for (Complex_Selector_Obj cur : pNewSelectors->elements()) {
       // process tails
       while (cur) {
         // process header
-        if (cur->head() && seen.find(*cur->head()) == seen.end()) {
-          std::set<Compound_Selector> recseen(seen);
-          recseen.insert(*cur->head());
+        if (cur->head() && seen.find(cur->head()) == seen.end()) {
+          CompoundSelectorSet recseen(seen);
+          recseen.insert(cur->head());
           // create a copy since we add multiple items if stuff get unwrapped
           Compound_Selector_Obj cpy_head = SASS_MEMORY_NEW(Compound_Selector, cur->pstate());
           for (Simple_Selector_Obj hs : *cur->head()) {
-            if (Wrapped_Selector_Obj ws = SASS_MEMORY_CAST(Wrapped_Selector, hs)) {
+            if (Wrapped_Selector_Obj ws = Cast<Wrapped_Selector>(hs)) {
               ws->selector(SASS_MEMORY_CLONE(ws->selector()));
-              if (Selector_List_Obj sl = SASS_MEMORY_CAST(Selector_List, ws->selector())) {
+              if (Selector_List_Obj sl = Cast<Selector_List>(ws->selector())) {
                 // special case for ruby ass
                 if (sl->empty()) {
                   // this seems inconsistent but it is how ruby sass seems to remove parentheses
                   cpy_head->append(SASS_MEMORY_NEW(Element_Selector, hs->pstate(), ws->name()));
                 }
-                // has wrapped selectors
-                else {
+                // has wrapped not selectors
+                else if (ws->name() == ":not") {
                   // extend the inner list of wrapped selector
-                  Selector_List_Obj ext_sl = extendSelectorList(sl, ctx, subset_map, recseen);
+                  bool extended = false;
+                  Selector_List_Obj ext_sl = extendSelectorList(sl, false, extended, recseen);
                   for (size_t i = 0; i < ext_sl->length(); i += 1) {
                     if (Complex_Selector_Obj ext_cs = ext_sl->at(i)) {
                       // create clones for wrapped selector and the inner list
-                      Wrapped_Selector_Obj cpy_ws = SASS_MEMORY_COPY(&ws);
+                      Wrapped_Selector_Obj cpy_ws = SASS_MEMORY_COPY(ws);
                       Selector_List_Obj cpy_ws_sl = SASS_MEMORY_NEW(Selector_List, sl->pstate());
                       // remove parent selectors from inner selector
-                      if (ext_cs->first() && ext_cs->first()->head()->length() > 0) {
-                        Wrapped_Selector_Ptr ext_ws = SASS_MEMORY_CAST(Wrapped_Selector, ext_cs->first()->head()->first());
-                        if (ext_ws/* && ext_cs->length() == 1*/) {
-                          Selector_List_Obj ws_cs = SASS_MEMORY_CAST(Selector_List, ext_ws->selector());
-                          Compound_Selector_Obj ws_ss = ws_cs->first()->head();
-                          if (!(
-                            SASS_MEMORY_CAST(Pseudo_Selector, ws_ss->first()) ||
-                            SASS_MEMORY_CAST(Element_Selector, ws_ss->first()) ||
-                            SASS_MEMORY_CAST(Placeholder_Selector, ws_ss->first())
-                          )) continue;
-                        }
+                      Compound_Selector_Obj ext_head = NULL;
+                      if (ext_cs->first()) ext_head = ext_cs->first()->head();
+                      if (ext_head && ext_head && ext_head->length() > 0) {
                         cpy_ws_sl->append(ext_cs->first());
                       }
                       // assign list to clone
-                      cpy_ws->selector(&cpy_ws_sl);
+                      cpy_ws->selector(cpy_ws_sl);
                       // append the clone
-                      cpy_head->append(&cpy_ws);
+                      cpy_head->append(cpy_ws);
                     }
                   }
+                  if (eval && extended) {
+                    eval->exp.selector_stack.push_back(pNewSelectors);
+                    cpy_head->perform(eval);
+                    eval->exp.selector_stack.pop_back();
+                  }
                 }
+                // has wrapped selectors
+                else {
+                  Wrapped_Selector_Obj cpy_ws = SASS_MEMORY_COPY(ws);
+                  Selector_List_Obj ext_sl = extendSelectorList(sl, recseen);
+                  cpy_ws->selector(ext_sl);
+                  cpy_head->append(cpy_ws);
+                }
               } else {
-                cpy_head->append(&hs);
+                cpy_head->append(hs);
               }
             } else {
-              cpy_head->append(&hs);
+              cpy_head->append(hs);
             }
           }
           // replace header
@@ -2001,6 +1994,10 @@
         cur = cur->tail();
       }
     }
+
+    // memory results in a map table - since extending is very expensive
+    memoizeList.insert(std::pair<Selector_List_Obj, Selector_List_Obj>(pSelectorList, pNewSelectors));
+
     return pNewSelectors.detach();
 
   }
@@ -2024,8 +2021,9 @@
     for (size_t i = 0, L = b->length(); i < L; ++i) {
       Statement_Obj stm = b->at(i);
 
-      if (dynamic_cast<Ruleset_Ptr>(&stm)) {
-        // Do nothing. This doesn't count as a statement that causes extension since we'll iterate over this rule set in a future visit and try to extend it.
+      if (Cast<Ruleset>(stm)) {
+        // Do nothing. This doesn't count as a statement that causes extension since we'll
+        // iterate over this rule set in a future visit and try to extend it.
       }
       else {
         return true;
@@ -2038,37 +2036,45 @@
 
 
   // Extend a ruleset by extending the selectors and updating them on the ruleset. The block's rules don't need to change.
-  template <typename ObjectType>
-  static void extendObjectWithSelectorAndBlock(ObjectType* pObject, Context& ctx, Subset_Map& subset_map) {
+  // Every Ruleset in the whole tree is calling this function. We decide if there
+  // was is @extend that matches our selector. If we find one, we will go further
+  // and call the extend magic for our selector. The subset_map contains all blocks
+  // where @extend was found. Pick the ones that match our selector!
+  void Extend::extendObjectWithSelectorAndBlock(Ruleset_Ptr pObject) {
 
-    DEBUG_PRINTLN(EXTEND_OBJECT, "FOUND SELECTOR: " << static_cast<Selector_List_Ptr>(pObject->selector())->to_string(ctx.c_options))
+    DEBUG_PRINTLN(EXTEND_OBJECT, "FOUND SELECTOR: " << Cast<Selector_List>(pObject->selector())->to_string())
 
-    // Ruby sass seems to filter nodes that don't have any content well before we get here. I'm not sure the repercussions
-    // of doing so, so for now, let's just not extend things that won't be output later.
+    // Ruby sass seems to filter nodes that don't have any content well before we get here.
+    // I'm not sure the repercussions of doing so, so for now, let's just not extend things
+    // that won't be output later. Profiling shows this may us 0.2% or so.
     if (!shouldExtendBlock(pObject->block())) {
       DEBUG_PRINTLN(EXTEND_OBJECT, "RETURNING WITHOUT EXTEND ATTEMPT")
       return;
     }
 
     bool extendedSomething = false;
-    Selector_List_Obj pNewSelectorList = Extend::extendSelectorList(SASS_MEMORY_CAST(Selector_List, pObject->selector()), ctx, subset_map, false, extendedSomething);
 
+    CompoundSelectorSet seen;
+    Selector_List_Obj pNewSelectorList = extendSelectorList(pObject->selector(), false, extendedSomething, seen);
+
     if (extendedSomething && pNewSelectorList) {
-      DEBUG_PRINTLN(EXTEND_OBJECT, "EXTEND ORIGINAL SELECTORS: " << static_cast<Selector_List_Ptr>(pObject->selector())->to_string(ctx.c_options))
-      DEBUG_PRINTLN(EXTEND_OBJECT, "EXTEND SETTING NEW SELECTORS: " << pNewSelectorList->to_string(ctx.c_options))
+      DEBUG_PRINTLN(EXTEND_OBJECT, "EXTEND ORIGINAL SELECTORS: " << pObject->selector()->to_string())
+      DEBUG_PRINTLN(EXTEND_OBJECT, "EXTEND SETTING NEW SELECTORS: " << pNewSelectorList->to_string())
       pNewSelectorList->remove_parent_selectors();
-      pObject->selector(&pNewSelectorList);
+      pObject->selector(pNewSelectorList);
     } else {
       DEBUG_PRINTLN(EXTEND_OBJECT, "EXTEND DID NOT TRY TO EXTEND ANYTHING")
     }
   }
 
-
-
-  Extend::Extend(Context& ctx, Subset_Map& ssm)
-  : ctx(ctx), subset_map(ssm)
+  Extend::Extend(Subset_Map& ssm)
+  : subset_map(ssm), eval(NULL)
   { }
 
+  void Extend::setEval(Eval& e) {
+    eval = &e;
+  }
+
   void Extend::operator()(Block_Ptr b)
   {
     for (size_t i = 0, L = b->length(); i < L; ++i) {
@@ -2080,17 +2086,19 @@
     if (b->is_root()) {
       // debug_subset_map(subset_map);
       for(auto const &it : subset_map.values()) {
-        Complex_Selector_Ptr sel = it.first ? &it.first->first() : NULL;
-        Compound_Selector_Ptr ext = it.second ? &it.second : NULL;
+        Complex_Selector_Ptr sel = NULL;
+        Compound_Selector_Ptr ext = NULL;
+        if (it.first) sel = it.first->first();
+        if (it.second) ext = it.second;
         if (ext && (ext->extended() || ext->is_optional())) continue;
-        std::string str_sel(sel->to_string({ NESTED, 5 }));
-        std::string str_ext(ext->to_string({ NESTED, 5 }));
+        std::string str_sel(sel ? sel->to_string({ NESTED, 5 }) : "NULL");
+        std::string str_ext(ext ? ext->to_string({ NESTED, 5 }) : "NULL");
         // debug_ast(sel, "sel: ");
         // debug_ast(ext, "ext: ");
         error("\"" + str_sel + "\" failed to @extend \"" + str_ext + "\".\n"
               "The selector \"" + str_ext + "\" was not found.\n"
               "Use \"@extend " + str_ext + " !optional\" if the"
-                " extend should be able to fail.", ext->pstate());
+              " extend should be able to fail.", (ext ? ext->pstate() : NULL), eval->exp.traces);
       }
     }
 
@@ -2098,7 +2106,7 @@
 
   void Extend::operator()(Ruleset_Ptr pRuleset)
   {
-    extendObjectWithSelectorAndBlock( pRuleset, ctx, subset_map);
+    extendObjectWithSelectorAndBlock( pRuleset );
     pRuleset->block()->perform(this);
   }
 
@@ -2114,7 +2122,7 @@
 
   void Extend::operator()(Directive_Ptr a)
   {
-    // Selector_List_Ptr ls = dynamic_cast<Selector_List_Ptr>(a->selector());
+    // Selector_List_Ptr ls = Cast<Selector_List>(a->selector());
     // selector_stack.push_back(ls);
     if (a->block()) a->block()->perform(this);
     // exp.selector_stack.pop_back();
diff --git a/libsass/src/extend.hpp b/libsass/src/extend.hpp
--- a/libsass/src/extend.hpp
+++ b/libsass/src/extend.hpp
@@ -5,35 +5,70 @@
 #include <set>
 
 #include "ast.hpp"
+#include "node.hpp"
+#include "eval.hpp"
 #include "operation.hpp"
 #include "subset_map.hpp"
+#include "ast_fwd_decl.hpp"
 
 namespace Sass {
 
-  class Context;
-  class Node;
+  Node subweave(Node& one, Node& two);
 
   class Extend : public Operation_CRTP<void, Extend> {
 
-    Context&            ctx;
     Subset_Map& subset_map;
+    Eval* eval;
 
     void fallback_impl(AST_Node_Ptr n) { }
 
+  private:
+
+    std::unordered_map<
+      Selector_List_Obj, // key
+      Selector_List_Obj, // value
+      HashNodes, // hasher
+      CompareNodes // compare
+    > memoizeList;
+
+    std::unordered_map<
+      Complex_Selector_Obj, // key
+      Node, // value
+      HashNodes, // hasher
+      CompareNodes // compare
+    > memoizeComplex;
+
+    /* this turned out to be too much overhead
+       re-evaluate once we store an ast selector
+    std::unordered_map<
+      Compound_Selector_Obj, // key
+      Node, // value
+      HashNodes, // hasher
+      CompareNodes // compare
+    > memoizeCompound;
+    */
+
+    void extendObjectWithSelectorAndBlock(Ruleset_Ptr pObject);
+    Node extendComplexSelector(Complex_Selector_Ptr sel, CompoundSelectorSet& seen, bool isReplace, bool isOriginal);
+    Node extendCompoundSelector(Compound_Selector_Ptr sel, CompoundSelectorSet& seen, bool isReplace);
+    bool complexSelectorHasExtension(Complex_Selector_Ptr selector, CompoundSelectorSet& seen);
+    Node trim(Node& seqses, bool isReplace);
+    Node weave(Node& path);
+
   public:
-    static Node subweave(Node& one, Node& two, Context& ctx);
-    static Selector_List_Ptr extendSelectorList(Selector_List_Obj pSelectorList, Context& ctx, Subset_Map& subset_map, bool isReplace, bool& extendedSomething, std::set<Compound_Selector>& seen);
-    static Selector_List_Ptr extendSelectorList(Selector_List_Obj pSelectorList, Context& ctx, Subset_Map& subset_map, bool isReplace, bool& extendedSomething);
-    static Selector_List_Ptr extendSelectorList(Selector_List_Obj pSelectorList, Context& ctx, Subset_Map& subset_map, bool isReplace = false) {
+    void setEval(Eval& eval);
+    Selector_List_Ptr extendSelectorList(Selector_List_Obj pSelectorList, bool isReplace, bool& extendedSomething, CompoundSelectorSet& seen);
+    Selector_List_Ptr extendSelectorList(Selector_List_Obj pSelectorList, bool isReplace = false) {
       bool extendedSomething = false;
-      return extendSelectorList(pSelectorList, ctx, subset_map, isReplace, extendedSomething);
+      CompoundSelectorSet seen;
+      return extendSelectorList(pSelectorList, isReplace, extendedSomething, seen);
     }
-    static Selector_List_Ptr extendSelectorList(Selector_List_Obj pSelectorList, Context& ctx, Subset_Map& subset_map, std::set<Compound_Selector>& seen) {
+    Selector_List_Ptr extendSelectorList(Selector_List_Obj pSelectorList, CompoundSelectorSet& seen) {
       bool isReplace = false;
       bool extendedSomething = false;
-      return extendSelectorList(pSelectorList, ctx, subset_map, isReplace, extendedSomething, seen);
+      return extendSelectorList(pSelectorList, isReplace, extendedSomething, seen);
     }
-    Extend(Context&, Subset_Map&);
+    Extend(Subset_Map&);
     ~Extend() { }
 
     void operator()(Block_Ptr);
diff --git a/libsass/src/file.cpp b/libsass/src/file.cpp
--- a/libsass/src/file.cpp
+++ b/libsass/src/file.cpp
@@ -1,3 +1,4 @@
+#include "sass.hpp"
 #ifdef _WIN32
 # ifdef __MINGW32__
 #  ifndef off64_t
@@ -9,7 +10,6 @@
 #else
 # include <unistd.h>
 #endif
-#include "sass.hpp"
 #include <iostream>
 #include <fstream>
 #include <cctype>
@@ -20,6 +20,7 @@
 #include "context.hpp"
 #include "prelexer.hpp"
 #include "utf8_string.hpp"
+#include "sass_functions.hpp"
 #include "sass2scss.h"
 
 #ifdef _WIN32
@@ -48,15 +49,22 @@
 
     // return the current directory
     // always with forward slashes
+    // always with trailing slash
     std::string get_cwd()
     {
-      const size_t wd_len = 1024;
+      const size_t wd_len = 4096;
       #ifndef _WIN32
         char wd[wd_len];
-        std::string cwd = getcwd(wd, wd_len);
+        char* pwd = getcwd(wd, wd_len);
+        // we should check error for more detailed info (e.g. ENOENT)
+        // http://man7.org/linux/man-pages/man2/getcwd.2.html#ERRORS
+        if (pwd == NULL) throw Exception::OperationError("cwd gone missing");
+        std::string cwd = pwd;
       #else
         wchar_t wd[wd_len];
-        std::string cwd = wstring_to_string(_wgetcwd(wd, wd_len));
+        wchar_t* pwd = _wgetcwd(wd, wd_len);
+        if (pwd == NULL) throw Exception::OperationError("cwd gone missing");
+        std::string cwd = wstring_to_string(pwd);
         //convert backslashes to forward slashes
         replace(cwd.begin(), cwd.end(), '\\', '/');
       #endif
@@ -68,8 +76,15 @@
     bool file_exists(const std::string& path)
     {
       #ifdef _WIN32
-        std::wstring wpath = UTF_8::convert_to_utf16(path);
-        DWORD dwAttrib = GetFileAttributesW(wpath.c_str());
+        wchar_t resolved[32768];
+        // windows unicode filepaths are encoded in utf16
+        std::string abspath(join_paths(get_cwd(), path));
+        std::wstring wpath(UTF_8::convert_to_utf16("\\\\?\\" + abspath));
+        std::replace(wpath.begin(), wpath.end(), '/', '\\');
+        DWORD rv = GetFullPathNameW(wpath.c_str(), 32767, resolved, NULL);
+        if (rv > 32767) throw Exception::OperationError("Path is too long");
+        if (rv == 0) throw Exception::OperationError("Path could not be resolved");
+        DWORD dwAttrib = GetFileAttributesW(resolved);
         return (dwAttrib != INVALID_FILE_ATTRIBUTES &&
                (!(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)));
       #else
@@ -99,7 +114,7 @@
     // helper function to find the last directory seperator
     inline size_t find_last_folder_separator(const std::string& path, size_t limit = std::string::npos)
     {
-      size_t pos = std::string::npos;
+      size_t pos;
       size_t pos_p = path.find_last_of('/', limit);
       #ifdef _WIN32
         size_t pos_w = path.find_last_of('\\', limit);
@@ -150,7 +165,7 @@
       pos = 0; // remove all self references inside the path string
       while((pos = path.find("/./", pos)) != std::string::npos) path.erase(pos, 2);
 
-      pos = 0; // remove all leading and trailing self references
+      // remove all leading and trailing self references
       while(path.length() > 1 && path.substr(0, 2) == "./") path.erase(0, 2);
       while((pos = path.length()) > 1 && path.substr(pos - 2) == "/.") path.erase(pos - 2);
 
@@ -191,6 +206,13 @@
       if (is_absolute_path(r)) return r;
       if (l[l.length()-1] != '/') l += '/';
 
+      // this does a logical cleanup of the right hand path
+      // Note that this does collapse x/../y sections into y.
+      // This is by design. If /foo on your system is a symlink
+      // to /bar/baz, then /foo/../cd is actually /bar/cd,
+      // not /cd as a naive ../ removal would give you.
+      // will only work on leading double dot dirs on rhs
+      // therefore it is safe if lhs is already resolved cwd
       while ((r.length() > 3) && ((r.substr(0, 3) == "../") || (r.substr(0, 3)) == "..\\")) {
         size_t L = l.length(), pos = find_last_folder_separator(l, L - 2);
         bool is_slash = pos + 2 == L && (l[pos+1] == '/' || l[pos+1] == '\\');
@@ -301,13 +323,9 @@
     // (2) underscore + given
     // (3) underscore + given + extension
     // (4) given + extension
-    std::vector<Include> resolve_includes(const std::string& root, const std::string& file)
+    std::vector<Include> resolve_includes(const std::string& root, const std::string& file, const std::vector<std::string>& exts)
     {
       std::string filename = join_paths(root, file);
-      // supported extensions
-      const std::vector<std::string> exts = {
-        ".scss", ".sass", ".css"
-      };
       // split the filename
       std::string base(dir_name(file));
       std::string name(base_name(file));
@@ -336,9 +354,42 @@
       return includes;
     }
 
-    // helper function to resolve a filename
+    std::vector<std::string> find_files(const std::string& file, const std::vector<std::string> paths)
+    {
+      std::vector<std::string> includes;
+      for (std::string path : paths) {
+        std::string abs_path(join_paths(path, file));
+        if (file_exists(abs_path)) includes.push_back(abs_path);
+      }
+      return includes;
+    }
+
+    std::vector<std::string> find_files(const std::string& file, struct Sass_Compiler* compiler)
+    {
+      // get the last import entry to get current base directory
+      // struct Sass_Options* options = sass_compiler_get_options(compiler);
+      Sass_Import_Entry import = sass_compiler_get_last_import(compiler);
+      const std::vector<std::string>& incs = compiler->cpp_ctx->include_paths;
+      // create the vector with paths to lookup
+      std::vector<std::string> paths(1 + incs.size());
+      paths.push_back(dir_name(import->abs_path));
+      paths.insert(paths.end(), incs.begin(), incs.end());
+      // dispatch to find files in paths
+      return find_files(file, paths);
+    }
+
+    // helper function to search one file in all include paths
+    // this is normally not used internally by libsass (C-API sugar)
     std::string find_file(const std::string& file, const std::vector<std::string> paths)
     {
+      if (file.empty()) return file;
+      auto res = find_files(file, paths);
+      return res.empty() ? "" : res.front();
+    }
+
+    // helper function to resolve a filename
+    std::string find_include(const std::string& file, const std::vector<std::string> paths)
+    {
       // search in every include path for a match
       for (size_t i = 0, S = paths.size(); i < S; ++i)
       {
@@ -349,20 +400,6 @@
       return std::string("");
     }
 
-    // inc paths can be directly passed from C code
-    std::string find_file(const std::string& file, const char* paths[])
-    {
-      if (paths == 0) return std::string("");
-      std::vector<std::string> includes(0);
-      // includes.push_back(".");
-      const char** it = paths;
-      while (it && *it) {
-        includes.push_back(*it);
-        ++it;
-      }
-      return find_file(file, includes);
-    }
-
     // try to load the given filename
     // returned memory must be freed
     // will auto convert .sass files
@@ -371,16 +408,24 @@
       #ifdef _WIN32
         BYTE* pBuffer;
         DWORD dwBytes;
+        wchar_t resolved[32768];
         // windows unicode filepaths are encoded in utf16
-        std::wstring wpath = UTF_8::convert_to_utf16(path);
-        HANDLE hFile = CreateFileW(wpath.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
+        std::string abspath(join_paths(get_cwd(), path));
+        std::wstring wpath(UTF_8::convert_to_utf16("\\\\?\\" + abspath));
+        std::replace(wpath.begin(), wpath.end(), '/', '\\');
+        DWORD rv = GetFullPathNameW(wpath.c_str(), 32767, resolved, NULL);
+        if (rv > 32767) throw Exception::OperationError("Path is too long");
+        if (rv == 0) throw Exception::OperationError("Path could not be resolved");
+        HANDLE hFile = CreateFileW(resolved, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
         if (hFile == INVALID_HANDLE_VALUE) return 0;
         DWORD dwFileLength = GetFileSize(hFile, NULL);
         if (dwFileLength == INVALID_FILE_SIZE) return 0;
         // allocate an extra byte for the null char
-        pBuffer = (BYTE*)malloc((dwFileLength+1)*sizeof(BYTE));
+        // and another one for edge-cases in lexer
+        pBuffer = (BYTE*)malloc((dwFileLength+2)*sizeof(BYTE));
         ReadFile(hFile, pBuffer, dwFileLength, &dwBytes, NULL);
-        pBuffer[dwFileLength] = '\0';
+        pBuffer[dwFileLength+0] = '\0';
+        pBuffer[dwFileLength+1] = '\0';
         CloseHandle(hFile);
         // just convert from unsigned char*
         char* contents = (char*) pBuffer;
@@ -392,10 +437,12 @@
         if (file.is_open()) {
           size_t size = file.tellg();
           // allocate an extra byte for the null char
-          contents = (char*) malloc((size+1)*sizeof(char));
+          // and another one for edge-cases in lexer
+          contents = (char*) malloc((size+2)*sizeof(char));
           file.seekg(0, std::ios::beg);
           file.read(contents, size);
-          contents[size] = '\0';
+          contents[size+0] = '\0';
+          contents[size+1] = '\0';
           file.close();
         }
       #endif
@@ -412,6 +459,26 @@
       } else {
         return contents;
       }
+    }
+
+    // split a path string delimited by semicolons or colons (OS dependent)
+    std::vector<std::string> split_path_list(const char* str)
+    {
+      std::vector<std::string> paths;
+      if (str == NULL) return paths;
+      // find delimiter via prelexer (return zero at end)
+      const char* end = Prelexer::find_first<PATH_SEP>(str);
+      // search until null delimiter
+      while (end) {
+        // add path from current position to delimiter
+        paths.push_back(std::string(str, end - str));
+        str = end + 1; // skip delimiter
+        end = Prelexer::find_first<PATH_SEP>(str);
+      }
+      // add path from current position to end
+      paths.push_back(std::string(str));
+      // return back
+      return paths;
     }
 
   }
diff --git a/libsass/src/file.hpp b/libsass/src/file.hpp
--- a/libsass/src/file.hpp
+++ b/libsass/src/file.hpp
@@ -4,6 +4,7 @@
 #include <string>
 #include <vector>
 
+#include "sass/context.h"
 #include "ast_fwd_decl.hpp"
 
 namespace Sass {
@@ -47,10 +48,17 @@
     std::string abs2rel(const std::string& path, const std::string& base = ".", const std::string& cwd = get_cwd());
 
     // helper function to resolve a filename
+    // searching without variations in all paths
+    std::string find_file(const std::string& file, struct Sass_Compiler* options);
     std::string find_file(const std::string& file, const std::vector<std::string> paths);
-    // inc paths can be directly passed from C code
-    std::string find_file(const std::string& file, const char** paths);
 
+    // helper function to resolve a include filename
+    // this has the original resolve logic for sass include
+    std::string find_include(const std::string& file, const std::vector<std::string> paths);
+
+    // split a path string delimited by semicolons or colons (OS dependent)
+    std::vector<std::string> split_path_list(const char* paths);
+
     // try to load the given filename
     // returned memory must be freed
     // will auto convert .sass files
@@ -113,7 +121,10 @@
 
   namespace File {
 
-    std::vector<Include> resolve_includes(const std::string& root, const std::string& file);
+    static std::vector<std::string> defaultExtensions = { ".scss", ".sass", ".css" };
+
+    std::vector<Include> resolve_includes(const std::string& root, const std::string& file,
+      const std::vector<std::string>& exts = defaultExtensions);
 
   }
 
diff --git a/libsass/src/functions.cpp b/libsass/src/functions.cpp
--- a/libsass/src/functions.cpp
+++ b/libsass/src/functions.cpp
@@ -10,6 +10,7 @@
 #include "eval.hpp"
 #include "util.hpp"
 #include "expand.hpp"
+#include "operators.hpp"
 #include "utf8_string.hpp"
 #include "sass/base.h"
 #include "utf8.h"
@@ -30,17 +31,34 @@
 #include "wincrypt.h"
 #endif
 
-#define ARG(argname, argtype) get_arg<argtype>(argname, env, sig, pstate, backtrace)
-#define ARGR(argname, argtype, lo, hi) get_arg_r(argname, env, sig, pstate, lo, hi, backtrace)
-#define ARGM(argname, argtype, ctx) get_arg_m(argname, env, sig, pstate, backtrace, ctx)
+#define ARG(argname, argtype) get_arg<argtype>(argname, env, sig, pstate, traces)
+#define ARGM(argname, argtype, ctx) get_arg_m(argname, env, sig, pstate, traces, ctx)
 
+// return a number object (copied since we want to have reduced units)
+#define ARGN(argname) get_arg_n(argname, env, sig, pstate, traces) // Number copy
+
+// special function for weird hsla percent (10px == 10% == 10 != 0.1)
+#define ARGVAL(argname) get_arg_val(argname, env, sig, pstate, traces) // double
+
+// macros for common ranges (u mean unsigned or upper, r for full range)
+#define DARG_U_FACT(argname) get_arg_r(argname, env, sig, pstate, traces, - 0.0, 1.0) // double
+#define DARG_R_FACT(argname) get_arg_r(argname, env, sig, pstate, traces, - 1.0, 1.0) // double
+#define DARG_U_BYTE(argname) get_arg_r(argname, env, sig, pstate, traces, - 0.0, 255.0) // double
+#define DARG_R_BYTE(argname) get_arg_r(argname, env, sig, pstate, traces, - 255.0, 255.0) // double
+#define DARG_U_PRCT(argname) get_arg_r(argname, env, sig, pstate, traces, - 0.0, 100.0) // double
+#define DARG_R_PRCT(argname) get_arg_r(argname, env, sig, pstate, traces, - 100.0, 100.0) // double
+
+// macros for color related inputs (rbg and alpha/opacity values)
+#define COLOR_NUM(argname) color_num(argname, env, sig, pstate, traces) // double
+#define ALPHA_NUM(argname) alpha_num(argname, env, sig, pstate, traces) // double
+
 namespace Sass {
   using std::stringstream;
   using std::endl;
 
   Definition_Ptr make_native_function(Signature sig, Native_Function func, Context& ctx)
   {
-    Parser sig_parser = Parser::from_c_str(sig, ctx, ParserState("[built-in function]"));
+    Parser sig_parser = Parser::from_c_str(sig, ctx, ctx.traces, ParserState("[built-in function]"));
     sig_parser.lex<Prelexer::identifier>();
     std::string name(Util::normalize_underscores(sig_parser.lexed));
     Parameters_Obj params = sig_parser.parse_parameters();
@@ -58,7 +76,7 @@
     using namespace Prelexer;
 
     const char* sig = sass_function_get_signature(c_func);
-    Parser sig_parser = Parser::from_c_str(sig, ctx, ParserState("[c function]"));
+    Parser sig_parser = Parser::from_c_str(sig, ctx, ctx.traces, ParserState("[c function]"));
     // allow to overload generic callback plus @warn, @error and @debug with custom functions
     sig_parser.lex < alternatives < identifier, exactly <'*'>,
                                     exactly < Constants::warn_kwd >,
@@ -84,31 +102,31 @@
 
   namespace Functions {
 
-    inline void handle_utf8_error (const ParserState& pstate, Backtrace* backtrace)
+    inline void handle_utf8_error (const ParserState& pstate, Backtraces traces)
     {
       try {
        throw;
       }
       catch (utf8::invalid_code_point) {
         std::string msg("utf8::invalid_code_point");
-        error(msg, pstate, backtrace);
+        error(msg, pstate, traces);
       }
       catch (utf8::not_enough_room) {
         std::string msg("utf8::not_enough_room");
-        error(msg, pstate, backtrace);
+        error(msg, pstate, traces);
       }
       catch (utf8::invalid_utf8) {
         std::string msg("utf8::invalid_utf8");
-        error(msg, pstate, backtrace);
+        error(msg, pstate, traces);
       }
       catch (...) { throw; }
     }
 
     template <typename T>
-    T* get_arg(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtrace* backtrace)
+    T* get_arg(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces)
     {
       // Minimal error handling -- the expectation is that built-ins will be written correctly!
-      T* val = dynamic_cast<T*>(&env[argname]);
+      T* val = Cast<T>(env[argname]);
       if (!val) {
         std::string msg("argument `");
         msg += argname;
@@ -116,74 +134,138 @@
         msg += sig;
         msg += "` must be a ";
         msg += T::type_name();
-        error(msg, pstate, backtrace);
+        error(msg, pstate, traces);
       }
       return val;
     }
 
-    Map_Ptr get_arg_m(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtrace* backtrace, Context& ctx)
+    Map_Ptr get_arg_m(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces, Context& ctx)
     {
       // Minimal error handling -- the expectation is that built-ins will be written correctly!
-      Map_Ptr val = SASS_MEMORY_CAST(Map, env[argname]);
+      Map_Ptr val = Cast<Map>(env[argname]);
       if (val) return val;
 
-      List_Ptr lval = SASS_MEMORY_CAST(List, env[argname]);
+      List_Ptr lval = Cast<List>(env[argname]);
       if (lval && lval->length() == 0) return SASS_MEMORY_NEW(Map, pstate, 0);
 
       // fallback on get_arg for error handling
-      val = get_arg<Map>(argname, env, sig, pstate, backtrace);
+      val = get_arg<Map>(argname, env, sig, pstate, traces);
       return val;
     }
 
-    Number_Ptr get_arg_r(const std::string& argname, Env& env, Signature sig, ParserState pstate, double lo, double hi, Backtrace* backtrace)
+    double get_arg_r(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces, double lo, double hi)
     {
       // Minimal error handling -- the expectation is that built-ins will be written correctly!
-      Number_Ptr val = get_arg<Number>(argname, env, sig, pstate, backtrace);
-      double v = val->value();
+      Number_Ptr val = get_arg<Number>(argname, env, sig, pstate, traces);
+      Number tmpnr(val);
+      tmpnr.reduce();
+      double v = tmpnr.value();
       if (!(lo <= v && v <= hi)) {
         std::stringstream msg;
         msg << "argument `" << argname << "` of `" << sig << "` must be between ";
         msg << lo << " and " << hi;
-        error(msg.str(), pstate, backtrace);
+        error(msg.str(), pstate, traces);
       }
+      return v;
+    }
+
+    Number_Ptr get_arg_n(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces)
+    {
+      // Minimal error handling -- the expectation is that built-ins will be written correctly!
+      Number_Ptr val = get_arg<Number>(argname, env, sig, pstate, traces);
+      val = SASS_MEMORY_COPY(val);
+      val->reduce();
       return val;
     }
 
-    #define ARGSEL(argname, seltype, contextualize) get_arg_sel<seltype>(argname, env, sig, pstate, backtrace, ctx)
+    double get_arg_v(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces)
+    {
+      // Minimal error handling -- the expectation is that built-ins will be written correctly!
+      Number_Ptr val = get_arg<Number>(argname, env, sig, pstate, traces);
+      Number tmpnr(val);
+      tmpnr.reduce();
+      /*
+      if (tmpnr.unit() == "%") {
+        tmpnr.value(tmpnr.value() / 100);
+        tmpnr.numerators.clear();
+      } else {
+        if (!tmpnr.is_unitless()) error("argument " + argname + " of `" + std::string(sig) + "` must be unitless", pstate);
+      }
+      */
+      return tmpnr.value();
+    }
 
+    double get_arg_val(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces)
+    {
+      // Minimal error handling -- the expectation is that built-ins will be written correctly!
+      Number_Ptr val = get_arg<Number>(argname, env, sig, pstate, traces);
+      Number tmpnr(val);
+      tmpnr.reduce();
+      return tmpnr.value();
+    }
+
+    double color_num(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces)
+    {
+      Number_Ptr val = get_arg<Number>(argname, env, sig, pstate, traces);
+      Number tmpnr(val);
+      tmpnr.reduce();
+      if (tmpnr.unit() == "%") {
+        return std::min(std::max(tmpnr.value() * 255 / 100.0, 0.0), 255.0);
+      } else {
+        return std::min(std::max(tmpnr.value(), 0.0), 255.0);
+      }
+    }
+
+
+    inline double alpha_num(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces) {
+      Number_Ptr val = get_arg<Number>(argname, env, sig, pstate, traces);
+      Number tmpnr(val);
+      tmpnr.reduce();
+      if (tmpnr.unit() == "%") {
+        return std::min(std::max(tmpnr.value(), 0.0), 100.0);
+      } else {
+        return std::min(std::max(tmpnr.value(), 0.0), 1.0);
+      }
+    }
+
+    #define ARGSEL(argname, seltype, contextualize) get_arg_sel<seltype>(argname, env, sig, pstate, traces, ctx)
+
     template <typename T>
-    T get_arg_sel(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtrace* backtrace, Context& ctx);
+    T get_arg_sel(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces, Context& ctx);
 
     template <>
-    Selector_List_Obj get_arg_sel(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtrace* backtrace, Context& ctx) {
+    Selector_List_Obj get_arg_sel(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces, Context& ctx) {
       Expression_Obj exp = ARG(argname, Expression);
       if (exp->concrete_type() == Expression::NULL_VAL) {
         std::stringstream msg;
         msg << argname << ": null is not a valid selector: it must be a string,\n";
         msg << "a list of strings, or a list of lists of strings for `" << function_name(sig) << "'";
-        error(msg.str(), pstate);
+        error(msg.str(), pstate, traces);
       }
-      if (String_Constant_Ptr str = SASS_MEMORY_CAST(String_Constant, exp)) {
+      if (String_Constant_Ptr str = Cast<String_Constant>(exp)) {
         str->quote_mark(0);
       }
-      std::string exp_src = exp->to_string(ctx.c_options) + "{";
-      return Parser::parse_selector(exp_src.c_str(), ctx);
+      std::string exp_src = exp->to_string(ctx.c_options);
+      return Parser::parse_selector(exp_src.c_str(), ctx, traces);
     }
 
     template <>
-    Compound_Selector_Obj get_arg_sel(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtrace* backtrace, Context& ctx) {
+    Compound_Selector_Obj get_arg_sel(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces, Context& ctx) {
       Expression_Obj exp = ARG(argname, Expression);
       if (exp->concrete_type() == Expression::NULL_VAL) {
         std::stringstream msg;
         msg << argname << ": null is not a string for `" << function_name(sig) << "'";
-        error(msg.str(), pstate);
+        error(msg.str(), pstate, traces);
       }
-      if (String_Constant_Ptr str = SASS_MEMORY_CAST(String_Constant, exp)) {
+      if (String_Constant_Ptr str = Cast<String_Constant>(exp)) {
         str->quote_mark(0);
       }
-      std::string exp_src = exp->to_string(ctx.c_options) + "{";
-      Selector_List_Obj sel_list = Parser::parse_selector(exp_src.c_str(), ctx);
-      return (sel_list->length() > 0) ? &sel_list->first()->tail()->head() : 0;
+      std::string exp_src = exp->to_string(ctx.c_options);
+      Selector_List_Obj sel_list = Parser::parse_selector(exp_src.c_str(), ctx, traces);
+      if (sel_list->length() == 0) return NULL;
+      Complex_Selector_Obj first = sel_list->first();
+      if (!first->tail()) return first->head();
+      return first->tail()->head();
     }
 
     #ifdef __MINGW32__
@@ -219,56 +301,110 @@
       "global-variable-shadowing",
       "extend-selector-pseudoclass",
       "at-error",
-      "units-level-3"
+      "units-level-3",
+      "custom-property"
     };
 
     ////////////////
     // RGB FUNCTIONS
     ////////////////
 
-    inline double color_num(Number_Ptr n) {
-      if (n->unit() == "%") {
-        return std::min(std::max(n->value() * 255 / 100.0, 0.0), 255.0);
-      } else {
-        return std::min(std::max(n->value(), 0.0), 255.0);
-      }
-    }
-
-    inline double alpha_num(Number_Ptr n) {
-      if (n->unit() == "%") {
-        return std::min(std::max(n->value(), 0.0), 100.0);
-      } else {
-        return std::min(std::max(n->value(), 0.0), 1.0);
+    inline bool special_number(String_Constant_Ptr s) {
+      if (s) {
+        std::string calc("calc(");
+        std::string var("var(");
+        std::string ss(s->value());
+        return std::equal(calc.begin(), calc.end(), ss.begin()) ||
+               std::equal(var.begin(), var.end(), ss.begin());
       }
+      return false;
     }
 
     Signature rgb_sig = "rgb($red, $green, $blue)";
     BUILT_IN(rgb)
     {
+      if (
+        special_number(Cast<String_Constant>(env["$red"])) ||
+        special_number(Cast<String_Constant>(env["$green"])) ||
+        special_number(Cast<String_Constant>(env["$blue"]))
+      ) {
+        return SASS_MEMORY_NEW(String_Constant, pstate, "rgb("
+                                                        + env["$red"]->to_string()
+                                                        + ", "
+                                                        + env["$green"]->to_string()
+                                                        + ", "
+                                                        + env["$blue"]->to_string()
+                                                        + ")"
+        );
+      }
+
       return SASS_MEMORY_NEW(Color,
                              pstate,
-                             color_num(ARG("$red",   Number)),
-                             color_num(ARG("$green", Number)),
-                             color_num(ARG("$blue",  Number)));
+                             COLOR_NUM("$red"),
+                             COLOR_NUM("$green"),
+                             COLOR_NUM("$blue"));
     }
 
     Signature rgba_4_sig = "rgba($red, $green, $blue, $alpha)";
     BUILT_IN(rgba_4)
     {
+      if (
+        special_number(Cast<String_Constant>(env["$red"])) ||
+        special_number(Cast<String_Constant>(env["$green"])) ||
+        special_number(Cast<String_Constant>(env["$blue"])) ||
+        special_number(Cast<String_Constant>(env["$alpha"]))
+      ) {
+        return SASS_MEMORY_NEW(String_Constant, pstate, "rgba("
+                                                        + env["$red"]->to_string()
+                                                        + ", "
+                                                        + env["$green"]->to_string()
+                                                        + ", "
+                                                        + env["$blue"]->to_string()
+                                                        + ", "
+                                                        + env["$alpha"]->to_string()
+                                                        + ")"
+        );
+      }
+
       return SASS_MEMORY_NEW(Color,
                              pstate,
-                             color_num(ARG("$red",   Number)),
-                             color_num(ARG("$green", Number)),
-                             color_num(ARG("$blue",  Number)),
-                             alpha_num(ARG("$alpha", Number)));
+                             COLOR_NUM("$red"),
+                             COLOR_NUM("$green"),
+                             COLOR_NUM("$blue"),
+                             ALPHA_NUM("$alpha"));
     }
 
     Signature rgba_2_sig = "rgba($color, $alpha)";
     BUILT_IN(rgba_2)
     {
+      if (
+        special_number(Cast<String_Constant>(env["$color"]))
+      ) {
+        return SASS_MEMORY_NEW(String_Constant, pstate, "rgba("
+                                                        + env["$color"]->to_string()
+                                                        + ", "
+                                                        + env["$alpha"]->to_string()
+                                                        + ")"
+        );
+      }
+
       Color_Ptr c_arg = ARG("$color", Color);
+
+      if (
+        special_number(Cast<String_Constant>(env["$alpha"]))
+      ) {
+        std::stringstream strm;
+        strm << "rgba("
+                 << (int)c_arg->r() << ", "
+                 << (int)c_arg->g() << ", "
+                 << (int)c_arg->b() << ", "
+                 << env["$alpha"]->to_string()
+             << ")";
+        return SASS_MEMORY_NEW(String_Constant, pstate, strm.str());
+      }
+
       Color_Ptr new_c = SASS_MEMORY_COPY(c_arg);
-      new_c->a(alpha_num(ARG("$alpha", Number)));
+      new_c->a(ALPHA_NUM("$alpha"));
       new_c->disp("");
       return new_c;
     }
@@ -285,14 +421,8 @@
     BUILT_IN(blue)
     { return SASS_MEMORY_NEW(Number, pstate, ARG("$color", Color)->b()); }
 
-    Signature mix_sig = "mix($color-1, $color-2, $weight: 50%)";
-    BUILT_IN(mix)
-    {
-      Color_Ptr  color1 = ARG("$color-1", Color);
-      Color_Ptr  color2 = ARG("$color-2", Color);
-      Number_Ptr weight = ARGR("$weight", Number, 0, 100);
-
-      double p = weight->value()/100;
+    Color* colormix(Context& ctx, ParserState& pstate, Color* color1, Color* color2, double weight) {
+      double p = weight/100;
       double w = 2*p - 1;
       double a = color1->a() - color2->a();
 
@@ -307,6 +437,16 @@
                              color1->a()*p + color2->a()*(1-p));
     }
 
+    Signature mix_sig = "mix($color-1, $color-2, $weight: 50%)";
+    BUILT_IN(mix)
+    {
+      Color_Obj  color1 = ARG("$color-1", Color);
+      Color_Obj  color2 = ARG("$color-2", Color);
+      double weight = DARG_U_PRCT("$weight");
+      return colormix(ctx, pstate, color1, color2, weight);
+
+    }
+
     ////////////////
     // HSL FUNCTIONS
     ////////////////
@@ -323,7 +463,9 @@
       double min = std::min(r, std::min(g, b));
       double delta = max - min;
 
-      double h = 0, s = 0, l = (max + min) / 2.0;
+      double h = 0;
+      double s;
+      double l = (max + min) / 2.0;
 
       if (max == min) {
         h = s = 0; // achromatic
@@ -390,9 +532,24 @@
     Signature hsl_sig = "hsl($hue, $saturation, $lightness)";
     BUILT_IN(hsl)
     {
-      return hsla_impl(ARG("$hue", Number)->value(),
-                       ARG("$saturation", Number)->value(),
-                       ARG("$lightness",  Number)->value(),
+      if (
+        special_number(Cast<String_Constant>(env["$hue"])) ||
+        special_number(Cast<String_Constant>(env["$saturation"])) ||
+        special_number(Cast<String_Constant>(env["$lightness"]))
+      ) {
+        return SASS_MEMORY_NEW(String_Constant, pstate, "hsl("
+                                                        + env["$hue"]->to_string()
+                                                        + ", "
+                                                        + env["$saturation"]->to_string()
+                                                        + ", "
+                                                        + env["$lightness"]->to_string()
+                                                        + ")"
+        );
+      }
+
+      return hsla_impl(ARGVAL("$hue"),
+                       ARGVAL("$saturation"),
+                       ARGVAL("$lightness"),
                        1.0,
                        ctx,
                        pstate);
@@ -401,10 +558,28 @@
     Signature hsla_sig = "hsla($hue, $saturation, $lightness, $alpha)";
     BUILT_IN(hsla)
     {
-      return hsla_impl(ARG("$hue", Number)->value(),
-                       ARG("$saturation", Number)->value(),
-                       ARG("$lightness",  Number)->value(),
-                       ARG("$alpha",  Number)->value(),
+      if (
+        special_number(Cast<String_Constant>(env["$hue"])) ||
+        special_number(Cast<String_Constant>(env["$saturation"])) ||
+        special_number(Cast<String_Constant>(env["$lightness"])) ||
+        special_number(Cast<String_Constant>(env["$alpha"]))
+      ) {
+        return SASS_MEMORY_NEW(String_Constant, pstate, "hsla("
+                                                        + env["$hue"]->to_string()
+                                                        + ", "
+                                                        + env["$saturation"]->to_string()
+                                                        + ", "
+                                                        + env["$lightness"]->to_string()
+                                                        + ", "
+                                                        + env["$alpha"]->to_string()
+                                                        + ")"
+        );
+      }
+
+      return hsla_impl(ARGVAL("$hue"),
+                       ARGVAL("$saturation"),
+                       ARGVAL("$lightness"),
+                       ARGVAL("$alpha"),
                        ctx,
                        pstate);
     }
@@ -443,11 +618,11 @@
     BUILT_IN(adjust_hue)
     {
       Color_Ptr rgb_color = ARG("$color", Color);
-      Number_Ptr degrees = ARG("$degrees", Number);
+      double degrees = ARGVAL("$degrees");
       HSL hsl_color = rgb_to_hsl(rgb_color->r(),
                                  rgb_color->g(),
                                  rgb_color->b());
-      return hsla_impl(hsl_color.h + degrees->value(),
+      return hsla_impl(hsl_color.h + degrees,
                        hsl_color.s,
                        hsl_color.l,
                        rgb_color->a(),
@@ -459,7 +634,7 @@
     BUILT_IN(lighten)
     {
       Color_Ptr rgb_color = ARG("$color", Color);
-      Number_Ptr amount = ARGR("$amount", Number, 0, 100);
+      double amount = DARG_U_PRCT("$amount");
       HSL hsl_color = rgb_to_hsl(rgb_color->r(),
                                  rgb_color->g(),
                                  rgb_color->b());
@@ -471,7 +646,7 @@
 
       return hsla_impl(hsl_color.h,
                        hsl_color.s,
-                       hslcolorL + amount->value(),
+                       hslcolorL + amount,
                        rgb_color->a(),
                        ctx,
                        pstate);
@@ -481,7 +656,7 @@
     BUILT_IN(darken)
     {
       Color_Ptr rgb_color = ARG("$color", Color);
-      Number_Ptr amount = ARGR("$amount", Number, 0, 100);
+      double amount = DARG_U_PRCT("$amount");
       HSL hsl_color = rgb_to_hsl(rgb_color->r(),
                                  rgb_color->g(),
                                  rgb_color->b());
@@ -494,7 +669,7 @@
 
       return hsla_impl(hsl_color.h,
                        hsl_color.s,
-                       hslcolorL - amount->value(),
+                       hslcolorL - amount,
                        rgb_color->a(),
                        ctx,
                        pstate);
@@ -504,18 +679,17 @@
     BUILT_IN(saturate)
     {
       // CSS3 filter function overload: pass literal through directly
-      Number_Ptr amount = SASS_MEMORY_CAST(Number, env["$amount"]);
-      if (!amount) {
+      if (!Cast<Number>(env["$amount"])) {
         return SASS_MEMORY_NEW(String_Quoted, pstate, "saturate(" + env["$color"]->to_string(ctx.c_options) + ")");
       }
 
-      ARGR("$amount", Number, 0, 100);
+      double amount = DARG_U_PRCT("$amount");
       Color_Ptr rgb_color = ARG("$color", Color);
       HSL hsl_color = rgb_to_hsl(rgb_color->r(),
                                  rgb_color->g(),
                                  rgb_color->b());
 
-      double hslcolorS = hsl_color.s + amount->value();
+      double hslcolorS = hsl_color.s + amount;
 
       // Saturation cannot be below 0 or above 100
       if (hslcolorS < 0) {
@@ -537,12 +711,12 @@
     BUILT_IN(desaturate)
     {
       Color_Ptr rgb_color = ARG("$color", Color);
-      Number_Ptr amount = ARGR("$amount", Number, 0, 100);
+      double amount = DARG_U_PRCT("$amount");
       HSL hsl_color = rgb_to_hsl(rgb_color->r(),
                                  rgb_color->g(),
                                  rgb_color->b());
 
-      double hslcolorS = hsl_color.s - amount->value();
+      double hslcolorS = hsl_color.s - amount;
 
       // Saturation cannot be below 0 or above 100
       if (hslcolorS <= 0) {
@@ -564,7 +738,7 @@
     BUILT_IN(grayscale)
     {
       // CSS3 filter function overload: pass literal through directly
-      Number_Ptr amount = SASS_MEMORY_CAST(Number, env["$color"]);
+      Number_Ptr amount = Cast<Number>(env["$color"]);
       if (amount) {
         return SASS_MEMORY_NEW(String_Quoted, pstate, "grayscale(" + amount->to_string(ctx.c_options) + ")");
       }
@@ -596,22 +770,24 @@
                        pstate);
     }
 
-    Signature invert_sig = "invert($color)";
+    Signature invert_sig = "invert($color, $weight: 100%)";
     BUILT_IN(invert)
     {
       // CSS3 filter function overload: pass literal through directly
-      Number_Ptr amount = SASS_MEMORY_CAST(Number, env["$color"]);
+      Number_Ptr amount = Cast<Number>(env["$color"]);
       if (amount) {
         return SASS_MEMORY_NEW(String_Quoted, pstate, "invert(" + amount->to_string(ctx.c_options) + ")");
       }
 
+      double weight = DARG_U_PRCT("$weight");
       Color_Ptr rgb_color = ARG("$color", Color);
-      return SASS_MEMORY_NEW(Color,
+      Color_Obj inv = SASS_MEMORY_NEW(Color,
                              pstate,
                              255 - rgb_color->r(),
                              255 - rgb_color->g(),
                              255 - rgb_color->b(),
                              rgb_color->a());
+      return colormix(ctx, pstate, inv, rgb_color, weight);
     }
 
     ////////////////////
@@ -621,13 +797,13 @@
     Signature opacity_sig = "opacity($color)";
     BUILT_IN(alpha)
     {
-      String_Constant_Ptr ie_kwd = SASS_MEMORY_CAST(String_Constant, env["$color"]);
+      String_Constant_Ptr ie_kwd = Cast<String_Constant>(env["$color"]);
       if (ie_kwd) {
         return SASS_MEMORY_NEW(String_Quoted, pstate, "alpha(" + ie_kwd->value() + ")");
       }
 
       // CSS3 filter function overload: pass literal through directly
-      Number_Ptr amount = SASS_MEMORY_CAST(Number, env["$color"]);
+      Number_Ptr amount = Cast<Number>(env["$color"]);
       if (amount) {
         return SASS_MEMORY_NEW(String_Quoted, pstate, "opacity(" + amount->to_string(ctx.c_options) + ")");
       }
@@ -640,7 +816,7 @@
     BUILT_IN(opacify)
     {
       Color_Ptr color = ARG("$color", Color);
-      double amount = ARGR("$amount", Number, 0, 1)->value();
+      double amount = DARG_U_FACT("$amount");
       double alpha = std::min(color->a() + amount, 1.0);
       return SASS_MEMORY_NEW(Color,
                              pstate,
@@ -655,7 +831,7 @@
     BUILT_IN(transparentize)
     {
       Color_Ptr color = ARG("$color", Color);
-      double amount = ARGR("$amount", Number, 0, 1)->value();
+      double amount = DARG_U_FACT("$amount");
       double alpha = std::max(color->a() - amount, 0.0);
       return SASS_MEMORY_NEW(Color,
                              pstate,
@@ -673,25 +849,25 @@
     BUILT_IN(adjust_color)
     {
       Color_Ptr color = ARG("$color", Color);
-      Number_Ptr r = SASS_MEMORY_CAST(Number, env["$red"]);
-      Number_Ptr g = SASS_MEMORY_CAST(Number, env["$green"]);
-      Number_Ptr b = SASS_MEMORY_CAST(Number, env["$blue"]);
-      Number_Ptr h = SASS_MEMORY_CAST(Number, env["$hue"]);
-      Number_Ptr s = SASS_MEMORY_CAST(Number, env["$saturation"]);
-      Number_Ptr l = SASS_MEMORY_CAST(Number, env["$lightness"]);
-      Number_Ptr a = SASS_MEMORY_CAST(Number, env["$alpha"]);
+      Number_Ptr r = Cast<Number>(env["$red"]);
+      Number_Ptr g = Cast<Number>(env["$green"]);
+      Number_Ptr b = Cast<Number>(env["$blue"]);
+      Number_Ptr h = Cast<Number>(env["$hue"]);
+      Number_Ptr s = Cast<Number>(env["$saturation"]);
+      Number_Ptr l = Cast<Number>(env["$lightness"]);
+      Number_Ptr a = Cast<Number>(env["$alpha"]);
 
       bool rgb = r || g || b;
       bool hsl = h || s || l;
 
       if (rgb && hsl) {
-        error("Cannot specify HSL and RGB values for a color at the same time for `adjust-color'", pstate);
+        error("Cannot specify HSL and RGB values for a color at the same time for `adjust-color'", pstate, traces);
       }
       if (rgb) {
-        double rr = r ? ARGR("$red",   Number, -255, 255)->value() : 0;
-        double gg = g ? ARGR("$green", Number, -255, 255)->value() : 0;
-        double bb = b ? ARGR("$blue",  Number, -255, 255)->value() : 0;
-        double aa = a ? ARGR("$alpha", Number, -1, 1)->value() : 0;
+        double rr = r ? DARG_R_BYTE("$red") : 0;
+        double gg = g ? DARG_R_BYTE("$green") : 0;
+        double bb = b ? DARG_R_BYTE("$blue") : 0;
+        double aa = a ? DARG_R_FACT("$alpha") : 0;
         return SASS_MEMORY_NEW(Color,
                                pstate,
                                color->r() + rr,
@@ -701,9 +877,9 @@
       }
       if (hsl) {
         HSL hsl_struct = rgb_to_hsl(color->r(), color->g(), color->b());
-        double ss = s ? ARGR("$saturation", Number, -100, 100)->value() : 0;
-        double ll = l ? ARGR("$lightness",  Number, -100, 100)->value() : 0;
-        double aa = a ? ARGR("$alpha",      Number, -1, 1)->value() : 0;
+        double ss = s ? DARG_R_PRCT("$saturation") : 0;
+        double ll = l ? DARG_R_PRCT("$lightness") : 0;
+        double aa = a ? DARG_R_FACT("$alpha") : 0;
         return hsla_impl(hsl_struct.h + (h ? h->value() : 0),
                          hsl_struct.s + ss,
                          hsl_struct.l + ll,
@@ -719,7 +895,7 @@
                                color->b(),
                                color->a() + (a ? a->value() : 0));
       }
-      error("not enough arguments for `adjust-color'", pstate);
+      error("not enough arguments for `adjust-color'", pstate, traces);
       // unreachable
       return color;
     }
@@ -728,25 +904,25 @@
     BUILT_IN(scale_color)
     {
       Color_Ptr color = ARG("$color", Color);
-      Number_Ptr r = SASS_MEMORY_CAST(Number, env["$red"]);
-      Number_Ptr g = SASS_MEMORY_CAST(Number, env["$green"]);
-      Number_Ptr b = SASS_MEMORY_CAST(Number, env["$blue"]);
-      Number_Ptr h = SASS_MEMORY_CAST(Number, env["$hue"]);
-      Number_Ptr s = SASS_MEMORY_CAST(Number, env["$saturation"]);
-      Number_Ptr l = SASS_MEMORY_CAST(Number, env["$lightness"]);
-      Number_Ptr a = SASS_MEMORY_CAST(Number, env["$alpha"]);
+      Number_Ptr r = Cast<Number>(env["$red"]);
+      Number_Ptr g = Cast<Number>(env["$green"]);
+      Number_Ptr b = Cast<Number>(env["$blue"]);
+      Number_Ptr h = Cast<Number>(env["$hue"]);
+      Number_Ptr s = Cast<Number>(env["$saturation"]);
+      Number_Ptr l = Cast<Number>(env["$lightness"]);
+      Number_Ptr a = Cast<Number>(env["$alpha"]);
 
       bool rgb = r || g || b;
       bool hsl = h || s || l;
 
       if (rgb && hsl) {
-        error("Cannot specify HSL and RGB values for a color at the same time for `scale-color'", pstate);
+        error("Cannot specify HSL and RGB values for a color at the same time for `scale-color'", pstate, traces);
       }
       if (rgb) {
-        double rscale = (r ? ARGR("$red",   Number, -100.0, 100.0)->value() : 0.0) / 100.0;
-        double gscale = (g ? ARGR("$green", Number, -100.0, 100.0)->value() : 0.0) / 100.0;
-        double bscale = (b ? ARGR("$blue",  Number, -100.0, 100.0)->value() : 0.0) / 100.0;
-        double ascale = (a ? ARGR("$alpha", Number, -100.0, 100.0)->value() : 0.0) / 100.0;
+        double rscale = (r ? DARG_R_PRCT("$red") : 0.0) / 100.0;
+        double gscale = (g ? DARG_R_PRCT("$green") : 0.0) / 100.0;
+        double bscale = (b ? DARG_R_PRCT("$blue") : 0.0) / 100.0;
+        double ascale = (a ? DARG_R_PRCT("$alpha") : 0.0) / 100.0;
         return SASS_MEMORY_NEW(Color,
                                pstate,
                                color->r() + rscale * (rscale > 0.0 ? 255 - color->r() : color->r()),
@@ -755,10 +931,10 @@
                                color->a() + ascale * (ascale > 0.0 ? 1.0 - color->a() : color->a()));
       }
       if (hsl) {
-        double hscale = (h ? ARGR("$hue",        Number, -100.0, 100.0)->value() : 0.0) / 100.0;
-        double sscale = (s ? ARGR("$saturation", Number, -100.0, 100.0)->value() : 0.0) / 100.0;
-        double lscale = (l ? ARGR("$lightness",  Number, -100.0, 100.0)->value() : 0.0) / 100.0;
-        double ascale = (a ? ARGR("$alpha",      Number, -100.0, 100.0)->value() : 0.0) / 100.0;
+        double hscale = (h ? DARG_R_PRCT("$hue") : 0.0) / 100.0;
+        double sscale = (s ? DARG_R_PRCT("$saturation") : 0.0) / 100.0;
+        double lscale = (l ? DARG_R_PRCT("$lightness") : 0.0) / 100.0;
+        double ascale = (a ? DARG_R_PRCT("$alpha") : 0.0) / 100.0;
         HSL hsl_struct = rgb_to_hsl(color->r(), color->g(), color->b());
         hsl_struct.h += hscale * (hscale > 0.0 ? 360.0 - hsl_struct.h : hsl_struct.h);
         hsl_struct.s += sscale * (sscale > 0.0 ? 100.0 - hsl_struct.s : hsl_struct.s);
@@ -767,7 +943,7 @@
         return hsla_impl(hsl_struct.h, hsl_struct.s, hsl_struct.l, alpha, ctx, pstate);
       }
       if (a) {
-        double ascale = (a ? ARGR("$alpha", Number, -100.0, 100.0)->value() : 0.0) / 100.0;
+        double ascale = (DARG_R_PRCT("$alpha")) / 100.0;
         return SASS_MEMORY_NEW(Color,
                                pstate,
                                color->r(),
@@ -775,7 +951,7 @@
                                color->b(),
                                color->a() + ascale * (ascale > 0.0 ? 1.0 - color->a() : color->a()));
       }
-      error("not enough arguments for `scale-color'", pstate);
+      error("not enough arguments for `scale-color'", pstate, traces);
       // unreachable
       return color;
     }
@@ -784,38 +960,38 @@
     BUILT_IN(change_color)
     {
       Color_Ptr color = ARG("$color", Color);
-      Number_Ptr r = SASS_MEMORY_CAST(Number, env["$red"]);
-      Number_Ptr g = SASS_MEMORY_CAST(Number, env["$green"]);
-      Number_Ptr b = SASS_MEMORY_CAST(Number, env["$blue"]);
-      Number_Ptr h = SASS_MEMORY_CAST(Number, env["$hue"]);
-      Number_Ptr s = SASS_MEMORY_CAST(Number, env["$saturation"]);
-      Number_Ptr l = SASS_MEMORY_CAST(Number, env["$lightness"]);
-      Number_Ptr a = SASS_MEMORY_CAST(Number, env["$alpha"]);
+      Number_Ptr r = Cast<Number>(env["$red"]);
+      Number_Ptr g = Cast<Number>(env["$green"]);
+      Number_Ptr b = Cast<Number>(env["$blue"]);
+      Number_Ptr h = Cast<Number>(env["$hue"]);
+      Number_Ptr s = Cast<Number>(env["$saturation"]);
+      Number_Ptr l = Cast<Number>(env["$lightness"]);
+      Number_Ptr a = Cast<Number>(env["$alpha"]);
 
       bool rgb = r || g || b;
       bool hsl = h || s || l;
 
       if (rgb && hsl) {
-        error("Cannot specify HSL and RGB values for a color at the same time for `change-color'", pstate);
+        error("Cannot specify HSL and RGB values for a color at the same time for `change-color'", pstate, traces);
       }
       if (rgb) {
         return SASS_MEMORY_NEW(Color,
                                pstate,
-                               r ? ARGR("$red",   Number, 0, 255)->value() : color->r(),
-                               g ? ARGR("$green", Number, 0, 255)->value() : color->g(),
-                               b ? ARGR("$blue",  Number, 0, 255)->value() : color->b(),
-                               a ? ARGR("$alpha", Number, 0, 255)->value() : color->a());
+                               r ? DARG_U_BYTE("$red") : color->r(),
+                               g ? DARG_U_BYTE("$green") : color->g(),
+                               b ? DARG_U_BYTE("$blue") : color->b(),
+                               a ? DARG_U_BYTE("$alpha") : color->a());
       }
       if (hsl) {
         HSL hsl_struct = rgb_to_hsl(color->r(), color->g(), color->b());
         if (h) hsl_struct.h = std::fmod(h->value(), 360.0);
-        if (s) hsl_struct.s = ARGR("$saturation", Number, 0, 100)->value();
-        if (l) hsl_struct.l = ARGR("$lightness",  Number, 0, 100)->value();
-        double alpha = a ? ARGR("$alpha", Number, 0, 1.0)->value() : color->a();
+        if (s) hsl_struct.s = DARG_U_PRCT("$saturation");
+        if (l) hsl_struct.l = DARG_U_PRCT("$lightness");
+        double alpha = a ? DARG_U_FACT("$alpha") : color->a();
         return hsla_impl(hsl_struct.h, hsl_struct.s, hsl_struct.l, alpha, ctx, pstate);
       }
       if (a) {
-        double alpha = a ? ARGR("$alpha", Number, 0, 1.0)->value() : color->a();
+        double alpha = DARG_U_FACT("$alpha");
         return SASS_MEMORY_NEW(Color,
                                pstate,
                                color->r(),
@@ -823,7 +999,7 @@
                                color->b(),
                                alpha);
       }
-      error("not enough arguments for `change-color'", pstate);
+      error("not enough arguments for `change-color'", pstate, traces);
       // unreachable
       return color;
     }
@@ -866,25 +1042,26 @@
     BUILT_IN(sass_unquote)
     {
       AST_Node_Obj arg = env["$string"];
-      if (String_Quoted_Ptr string_quoted = SASS_MEMORY_CAST(String_Quoted, arg)) {
+      if (String_Quoted_Ptr string_quoted = Cast<String_Quoted>(arg)) {
         String_Constant_Ptr result = SASS_MEMORY_NEW(String_Constant, pstate, string_quoted->value());
         // remember if the string was quoted (color tokens)
         result->is_delayed(true); // delay colors
         return result;
       }
-      else if (SASS_MEMORY_CAST(String_Constant, arg)) {
-        return (Expression_Ptr) &arg;
+      else if (String_Constant_Ptr str = Cast<String_Constant>(arg)) {
+        return str;
       }
-      else {
+      else if (Expression_Ptr ex = Cast<Expression>(arg)) {
         Sass_Output_Style oldstyle = ctx.c_options.output_style;
         ctx.c_options.output_style = SASS_STYLE_NESTED;
         std::string val(arg->to_string(ctx.c_options));
-        val = SASS_MEMORY_CAST(Null, arg) ? "null" : val;
+        val = Cast<Null>(arg) ? "null" : val;
         ctx.c_options.output_style = oldstyle;
 
         deprecated_function("Passing " + val + ", a non-string value, to unquote()", pstate);
-        return (Expression_Ptr) &arg;
+        return ex;
       }
+      throw std::runtime_error("Invalid Data Type for unquote");
     }
 
     Signature quote_sig = "quote($string)";
@@ -892,7 +1069,7 @@
     {
       AST_Node_Obj arg = env["$string"];
       // only set quote mark to true if already a string
-      if (String_Quoted_Ptr qstr = SASS_MEMORY_CAST(String_Quoted, arg)) {
+      if (String_Quoted_Ptr qstr = Cast<String_Quoted>(arg)) {
         qstr->quote_mark('*');
         return qstr;
       }
@@ -915,7 +1092,7 @@
       }
       // handle any invalid utf8 errors
       // other errors will be re-thrown
-      catch (...) { handle_utf8_error(pstate, backtrace); }
+      catch (...) { handle_utf8_error(pstate, traces); }
       // return something even if we had an error (-1)
       return SASS_MEMORY_NEW(Number, pstate, (double)len);
     }
@@ -931,8 +1108,7 @@
         String_Constant_Ptr i = ARG("$insert", String_Constant);
         std::string ins = i->value();
         ins = unquote(ins);
-        Number_Ptr ind = ARG("$index", Number);
-        double index = ind->value();
+        double index = ARGVAL("$index");
         size_t len = UTF_8::code_point_count(str, 0, str.size());
 
         if (index > 0 && index <= len) {
@@ -956,13 +1132,13 @@
           str = ins + str;
         }
 
-        if (String_Quoted_Ptr ss = SASS_MEMORY_CAST_PTR(String_Quoted, s)) {
+        if (String_Quoted_Ptr ss = Cast<String_Quoted>(s)) {
           if (ss->quote_mark()) str = quote(str);
         }
       }
       // handle any invalid utf8 errors
       // other errors will be re-thrown
-      catch (...) { handle_utf8_error(pstate, backtrace); }
+      catch (...) { handle_utf8_error(pstate, traces); }
       return SASS_MEMORY_NEW(String_Quoted, pstate, str);
     }
 
@@ -986,7 +1162,7 @@
       }
       // handle any invalid utf8 errors
       // other errors will be re-thrown
-      catch (...) { handle_utf8_error(pstate, backtrace); }
+      catch (...) { handle_utf8_error(pstate, traces); }
       // return something even if we had an error (-1)
       return SASS_MEMORY_NEW(Number, pstate, (double)index);
     }
@@ -997,15 +1173,15 @@
       std::string newstr;
       try {
         String_Constant_Ptr s = ARG("$string", String_Constant);
-        double start_at = ARG("$start-at", Number)->value();
-        double end_at = ARG("$end-at", Number)->value();
-        String_Quoted_Ptr ss = SASS_MEMORY_CAST_PTR(String_Quoted, s);
+        double start_at = ARGVAL("$start-at");
+        double end_at = ARGVAL("$end-at");
+        String_Quoted_Ptr ss = Cast<String_Quoted>(s);
 
         std::string str = unquote(s->value());
 
         size_t size = utf8::distance(str.begin(), str.end());
 
-        if (!SASS_MEMORY_CAST(Number, env["$end-at"])) {
+        if (!Cast<Number>(env["$end-at"])) {
           end_at = -1;
         }
 
@@ -1039,7 +1215,7 @@
       }
       // handle any invalid utf8 errors
       // other errors will be re-thrown
-      catch (...) { handle_utf8_error(pstate, backtrace); }
+      catch (...) { handle_utf8_error(pstate, traces); }
       return SASS_MEMORY_NEW(String_Quoted, pstate, newstr);
     }
 
@@ -1055,7 +1231,7 @@
         }
       }
 
-      if (String_Quoted_Ptr ss = SASS_MEMORY_CAST_PTR(String_Quoted, s)) {
+      if (String_Quoted_Ptr ss = Cast<String_Quoted>(s)) {
         String_Quoted_Ptr cpy = SASS_MEMORY_COPY(ss);
         cpy->value(str);
         return cpy;
@@ -1076,7 +1252,7 @@
         }
       }
 
-      if (String_Quoted_Ptr ss = SASS_MEMORY_CAST_PTR(String_Quoted, s)) {
+      if (String_Quoted_Ptr ss = Cast<String_Quoted>(s)) {
         String_Quoted_Ptr cpy = SASS_MEMORY_COPY(ss);
         cpy->value(str);
         return cpy;
@@ -1092,49 +1268,45 @@
     Signature percentage_sig = "percentage($number)";
     BUILT_IN(percentage)
     {
-      Number_Ptr n = ARG("$number", Number);
-      if (!n->is_unitless()) error("argument $number of `" + std::string(sig) + "` must be unitless", pstate);
+      Number_Obj n = ARGN("$number");
+      if (!n->is_unitless()) error("argument $number of `" + std::string(sig) + "` must be unitless", pstate, traces);
       return SASS_MEMORY_NEW(Number, pstate, n->value() * 100, "%");
     }
 
     Signature round_sig = "round($number)";
     BUILT_IN(round)
     {
-      Number_Ptr n = ARG("$number", Number);
-      Number_Ptr r = SASS_MEMORY_COPY(n);
-      r->pstate(pstate);
+      Number_Obj r = ARGN("$number");
       r->value(Sass::round(r->value(), ctx.c_options.precision));
-      return r;
+      r->pstate(pstate);
+      return r.detach();
     }
 
     Signature ceil_sig = "ceil($number)";
     BUILT_IN(ceil)
     {
-      Number_Ptr n = ARG("$number", Number);
-      Number_Ptr r = SASS_MEMORY_COPY(n);
-      r->pstate(pstate);
+      Number_Obj r = ARGN("$number");
       r->value(std::ceil(r->value()));
-      return r;
+      r->pstate(pstate);
+      return r.detach();
     }
 
     Signature floor_sig = "floor($number)";
     BUILT_IN(floor)
     {
-      Number_Ptr n = ARG("$number", Number);
-      Number_Ptr r = SASS_MEMORY_COPY(n);
-      r->pstate(pstate);
+      Number_Obj r = ARGN("$number");
       r->value(std::floor(r->value()));
-      return r;
+      r->pstate(pstate);
+      return r.detach();
     }
 
     Signature abs_sig = "abs($number)";
     BUILT_IN(abs)
     {
-      Number_Ptr n = ARG("$number", Number);
-      Number_Ptr r = SASS_MEMORY_COPY(n);
-      r->pstate(pstate);
+      Number_Obj r = ARGN("$number");
       r->value(std::abs(r->value()));
-      return r;
+      r->pstate(pstate);
+      return r.detach();
     }
 
     Signature min_sig = "min($numbers...)";
@@ -1144,9 +1316,9 @@
       Number_Obj least = NULL;
       for (size_t i = 0, L = arglist->length(); i < L; ++i) {
         Expression_Obj val = arglist->value_at_index(i);
-        Number_Obj xi = SASS_MEMORY_CAST(Number, val);
+        Number_Obj xi = Cast<Number>(val);
         if (!xi) {
-          error("\"" + val->to_string(ctx.c_options) + "\" is not a number for `min'", pstate);
+          error("\"" + val->to_string(ctx.c_options) + "\" is not a number for `min'", pstate, traces);
         }
         if (least) {
           if (*xi < *least) least = xi;
@@ -1162,9 +1334,9 @@
       Number_Obj greatest = NULL;
       for (size_t i = 0, L = arglist->length(); i < L; ++i) {
         Expression_Obj val = arglist->value_at_index(i);
-        Number_Obj xi = SASS_MEMORY_CAST(Number, val);
+        Number_Obj xi = Cast<Number>(val);
         if (!xi) {
-          error("\"" + val->to_string(ctx.c_options) + "\" is not a number for `max'", pstate);
+          error("\"" + val->to_string(ctx.c_options) + "\" is not a number for `max'", pstate, traces);
         }
         if (greatest) {
           if (*greatest < *xi) greatest = xi;
@@ -1177,23 +1349,23 @@
     BUILT_IN(random)
     {
       AST_Node_Obj arg = env["$limit"];
-      Value_Ptr v = SASS_MEMORY_CAST(Value, arg);
-      Number_Ptr l = SASS_MEMORY_CAST(Number, arg);
-      Boolean_Ptr b = SASS_MEMORY_CAST(Boolean, arg);
+      Value_Ptr v = Cast<Value>(arg);
+      Number_Ptr l = Cast<Number>(arg);
+      Boolean_Ptr b = Cast<Boolean>(arg);
       if (l) {
-        double v = l->value();
-        if (v < 1) {
+        double lv = l->value();
+        if (lv < 1) {
           stringstream err;
-          err << "$limit " << v << " must be greater than or equal to 1 for `random'";
-          error(err.str(), pstate);
+          err << "$limit " << lv << " must be greater than or equal to 1 for `random'";
+          error(err.str(), pstate, traces);
         }
-        bool eq_int = std::fabs(trunc(v) - v) < NUMBER_EPSILON;
+        bool eq_int = std::fabs(trunc(lv) - lv) < NUMBER_EPSILON;
         if (!eq_int) {
           stringstream err;
-          err << "Expected $limit to be an integer but got " << v << " for `random'";
-          error(err.str(), pstate);
+          err << "Expected $limit to be an integer but got " << lv << " for `random'";
+          error(err.str(), pstate, traces);
         }
-        std::uniform_real_distribution<> distributor(1, v + 1);
+        std::uniform_real_distribution<> distributor(1, lv + 1);
         uint_fast32_t distributed = static_cast<uint_fast32_t>(distributor(rand));
         return SASS_MEMORY_NEW(Number, pstate, (double)distributed);
       }
@@ -1202,11 +1374,12 @@
         double distributed = static_cast<double>(distributor(rand));
         return SASS_MEMORY_NEW(Number, pstate, distributed);
       } else if (v) {
-        throw Exception::InvalidArgumentType(pstate, "random", "$limit", "number", v);
+        traces.push_back(Backtrace(pstate));
+        throw Exception::InvalidArgumentType(pstate, traces, "random", "$limit", "number", v);
       } else {
-        throw Exception::InvalidArgumentType(pstate, "random", "$limit", "number");
+        traces.push_back(Backtrace(pstate));
+        throw Exception::InvalidArgumentType(pstate, traces, "random", "$limit", "number");
       }
-      return 0;
     }
 
     /////////////////
@@ -1216,25 +1389,25 @@
     Signature length_sig = "length($list)";
     BUILT_IN(length)
     {
-      if (Selector_List_Ptr sl = SASS_MEMORY_CAST(Selector_List, env["$list"])) {
+      if (Selector_List_Ptr sl = Cast<Selector_List>(env["$list"])) {
         return SASS_MEMORY_NEW(Number, pstate, (double)sl->length());
       }
       Expression_Ptr v = ARG("$list", Expression);
       if (v->concrete_type() == Expression::MAP) {
-        Map_Ptr map = SASS_MEMORY_CAST(Map, env["$list"]);
+        Map_Ptr map = Cast<Map>(env["$list"]);
         return SASS_MEMORY_NEW(Number, pstate, (double)(map ? map->length() : 1));
       }
       if (v->concrete_type() == Expression::SELECTOR) {
-        if (Compound_Selector_Ptr h = dynamic_cast<Compound_Selector_Ptr>(v)) {
+        if (Compound_Selector_Ptr h = Cast<Compound_Selector>(v)) {
           return SASS_MEMORY_NEW(Number, pstate, (double)h->length());
-        } else if (Selector_List_Ptr ls = SASS_MEMORY_CAST_PTR(Selector_List, v)) {
+        } else if (Selector_List_Ptr ls = Cast<Selector_List>(v)) {
           return SASS_MEMORY_NEW(Number, pstate, (double)ls->length());
         } else {
           return SASS_MEMORY_NEW(Number, pstate, 1);
         }
       }
 
-      List_Ptr list = SASS_MEMORY_CAST(List, env["$list"]);
+      List_Ptr list = Cast<List>(env["$list"]);
       return SASS_MEMORY_NEW(Number,
                              pstate,
                              (double)(list ? list->size() : 1));
@@ -1243,20 +1416,20 @@
     Signature nth_sig = "nth($list, $n)";
     BUILT_IN(nth)
     {
-      Number_Ptr n = ARG("$n", Number);
-      Map_Ptr m = SASS_MEMORY_CAST(Map, env["$list"]);
-      if (Selector_List_Ptr sl = SASS_MEMORY_CAST(Selector_List, env["$list"])) {
+      double nr = ARGVAL("$n");
+      Map_Ptr m = Cast<Map>(env["$list"]);
+      if (Selector_List_Ptr sl = Cast<Selector_List>(env["$list"])) {
         size_t len = m ? m->length() : sl->length();
         bool empty = m ? m->empty() : sl->empty();
-        if (empty) error("argument `$list` of `" + std::string(sig) + "` must not be empty", pstate);
-        double index = std::floor(n->value() < 0 ? len + n->value() : n->value() - 1);
-        if (index < 0 || index > len - 1) error("index out of bounds for `" + std::string(sig) + "`", pstate);
+        if (empty) error("argument `$list` of `" + std::string(sig) + "` must not be empty", pstate, traces);
+        double index = std::floor(nr < 0 ? len + nr : nr - 1);
+        if (index < 0 || index > len - 1) error("index out of bounds for `" + std::string(sig) + "`", pstate, traces);
         // return (*sl)[static_cast<int>(index)];
         Listize listize;
         return (*sl)[static_cast<int>(index)]->perform(&listize);
       }
-      List_Obj l = SASS_MEMORY_CAST(List, env["$list"]);
-      if (n->value() == 0) error("argument `$n` of `" + std::string(sig) + "` must be non-zero", pstate);
+      List_Obj l = Cast<List>(env["$list"]);
+      if (nr == 0) error("argument `$n` of `" + std::string(sig) + "` must be non-zero", pstate, traces);
       // if the argument isn't a list, then wrap it in a singleton list
       if (!m && !l) {
         l = SASS_MEMORY_NEW(List, pstate, 1);
@@ -1264,9 +1437,9 @@
       }
       size_t len = m ? m->length() : l->length();
       bool empty = m ? m->empty() : l->empty();
-      if (empty) error("argument `$list` of `" + std::string(sig) + "` must not be empty", pstate);
-      double index = std::floor(n->value() < 0 ? len + n->value() : n->value() - 1);
-      if (index < 0 || index > len - 1) error("index out of bounds for `" + std::string(sig) + "`", pstate);
+      if (empty) error("argument `$list` of `" + std::string(sig) + "` must not be empty", pstate, traces);
+      double index = std::floor(nr < 0 ? len + nr : nr - 1);
+      if (index < 0 || index > len - 1) error("index out of bounds for `" + std::string(sig) + "`", pstate, traces);
 
       if (m) {
         l = SASS_MEMORY_NEW(List, pstate, 1);
@@ -1284,8 +1457,8 @@
     Signature set_nth_sig = "set-nth($list, $n, $value)";
     BUILT_IN(set_nth)
     {
-      Map_Obj m = SASS_MEMORY_CAST(Map, env["$list"]);
-      List_Obj l = SASS_MEMORY_CAST(List, env["$list"]);
+      Map_Obj m = Cast<Map>(env["$list"]);
+      List_Obj l = Cast<List>(env["$list"]);
       Number_Obj n = ARG("$n", Number);
       Expression_Obj v = ARG("$value", Expression);
       if (!l) {
@@ -1293,12 +1466,12 @@
         l->append(ARG("$list", Expression));
       }
       if (m) {
-        l = m->to_list(ctx, pstate);
+        l = m->to_list(pstate);
       }
-      if (l->empty()) error("argument `$list` of `" + std::string(sig) + "` must not be empty", pstate);
+      if (l->empty()) error("argument `$list` of `" + std::string(sig) + "` must not be empty", pstate, traces);
       double index = std::floor(n->value() < 0 ? l->length() + n->value() : n->value() - 1);
-      if (index < 0 || index > l->length() - 1) error("index out of bounds for `" + std::string(sig) + "`", pstate);
-      List_Ptr result = SASS_MEMORY_NEW(List, pstate, l->length(), l->separator());
+      if (index < 0 || index > l->length() - 1) error("index out of bounds for `" + std::string(sig) + "`", pstate, traces);
+      List_Ptr result = SASS_MEMORY_NEW(List, pstate, l->length(), l->separator(), false, l->is_bracketed());
       for (size_t i = 0, L = l->length(); i < L; ++i) {
         result->append(((i == index) ? v : (*l)[i]));
       }
@@ -1308,67 +1481,75 @@
     Signature index_sig = "index($list, $value)";
     BUILT_IN(index)
     {
-      Map_Obj m = SASS_MEMORY_CAST(Map, env["$list"]);
-      List_Obj l = SASS_MEMORY_CAST(List, env["$list"]);
+      Map_Obj m = Cast<Map>(env["$list"]);
+      List_Obj l = Cast<List>(env["$list"]);
       Expression_Obj v = ARG("$value", Expression);
       if (!l) {
         l = SASS_MEMORY_NEW(List, pstate, 1);
         l->append(ARG("$list", Expression));
       }
       if (m) {
-        l = m->to_list(ctx, pstate);
+        l = m->to_list(pstate);
       }
       for (size_t i = 0, L = l->length(); i < L; ++i) {
-        if (Eval::eq(l->value_at_index(i), v)) return SASS_MEMORY_NEW(Number, pstate, (double)(i+1));
+        if (Operators::eq(l->value_at_index(i), v)) return SASS_MEMORY_NEW(Number, pstate, (double)(i+1));
       }
       return SASS_MEMORY_NEW(Null, pstate);
     }
 
-    Signature join_sig = "join($list1, $list2, $separator: auto)";
+    Signature join_sig = "join($list1, $list2, $separator: auto, $bracketed: auto)";
     BUILT_IN(join)
     {
-      Map_Obj m1 = SASS_MEMORY_CAST(Map, env["$list1"]);
-      Map_Obj m2 = SASS_MEMORY_CAST(Map, env["$list2"]);
-      List_Obj l1 = SASS_MEMORY_CAST(List, env["$list1"]);
-      List_Obj l2 = SASS_MEMORY_CAST(List, env["$list2"]);
+      Map_Obj m1 = Cast<Map>(env["$list1"]);
+      Map_Obj m2 = Cast<Map>(env["$list2"]);
+      List_Obj l1 = Cast<List>(env["$list1"]);
+      List_Obj l2 = Cast<List>(env["$list2"]);
       String_Constant_Obj sep = ARG("$separator", String_Constant);
       enum Sass_Separator sep_val = (l1 ? l1->separator() : SASS_SPACE);
+      Value* bracketed = ARG("$bracketed", Value);
+      bool is_bracketed = (l1 ? l1->is_bracketed() : false);
       if (!l1) {
         l1 = SASS_MEMORY_NEW(List, pstate, 1);
         l1->append(ARG("$list1", Expression));
         sep_val = (l2 ? l2->separator() : SASS_SPACE);
+        is_bracketed = (l2 ? l2->is_bracketed() : false);
       }
       if (!l2) {
         l2 = SASS_MEMORY_NEW(List, pstate, 1);
         l2->append(ARG("$list2", Expression));
       }
       if (m1) {
-        l1 = m1->to_list(ctx, pstate);
+        l1 = m1->to_list(pstate);
         sep_val = SASS_COMMA;
       }
       if (m2) {
-        l2 = m2->to_list(ctx, pstate);
+        l2 = m2->to_list(pstate);
       }
       size_t len = l1->length() + l2->length();
       std::string sep_str = unquote(sep->value());
       if (sep_str == "space") sep_val = SASS_SPACE;
       else if (sep_str == "comma") sep_val = SASS_COMMA;
-      else if (sep_str != "auto") error("argument `$separator` of `" + std::string(sig) + "` must be `space`, `comma`, or `auto`", pstate);
-      List_Obj result = SASS_MEMORY_NEW(List, pstate, len, sep_val);
-      result->concat(&l1);
-      result->concat(&l2);
+      else if (sep_str != "auto") error("argument `$separator` of `" + std::string(sig) + "` must be `space`, `comma`, or `auto`", pstate, traces);
+      String_Constant_Obj bracketed_as_str = Cast<String_Constant>(bracketed);
+      bool bracketed_is_auto = bracketed_as_str && unquote(bracketed_as_str->value()) == "auto";
+      if (!bracketed_is_auto) {
+        is_bracketed = !bracketed->is_false();
+      }
+      List_Obj result = SASS_MEMORY_NEW(List, pstate, len, sep_val, false, is_bracketed);
+      result->concat(l1);
+      result->concat(l2);
       return result.detach();
     }
 
     Signature append_sig = "append($list, $val, $separator: auto)";
     BUILT_IN(append)
     {
-      Map_Obj m = SASS_MEMORY_CAST(Map, env["$list"]);
-      List_Obj l = SASS_MEMORY_CAST(List, env["$list"]);
+      Map_Obj m = Cast<Map>(env["$list"]);
+      List_Obj l = Cast<List>(env["$list"]);
       Expression_Obj v = ARG("$val", Expression);
-      if (Selector_List_Ptr sl = SASS_MEMORY_CAST(Selector_List, env["$list"])) {
+      if (Selector_List_Ptr sl = Cast<Selector_List>(env["$list"])) {
         Listize listize;
-        l = SASS_MEMORY_CAST_PTR(List, sl->perform(&listize));
+        l = Cast<List>(sl->perform(&listize));
       }
       String_Constant_Obj sep = ARG("$separator", String_Constant);
       if (!l) {
@@ -1376,14 +1557,14 @@
         l->append(ARG("$list", Expression));
       }
       if (m) {
-        l = m->to_list(ctx, pstate);
+        l = m->to_list(pstate);
       }
       List_Ptr result = SASS_MEMORY_COPY(l);
       std::string sep_str(unquote(sep->value()));
       if (sep_str != "auto") { // check default first
         if (sep_str == "space") result->separator(SASS_SPACE);
         else if (sep_str == "comma") result->separator(SASS_COMMA);
-        else error("argument `$separator` of `" + std::string(sig) + "` must be `space`, `comma`, or `auto`", pstate);
+        else error("argument `$separator` of `" + std::string(sig) + "` must be `space`, `comma`, or `auto`", pstate, traces);
       }
       if (l->is_arglist()) {
         result->append(SASS_MEMORY_NEW(Argument,
@@ -1405,20 +1586,20 @@
       List_Obj arglist = SASS_MEMORY_COPY(ARG("$lists", List));
       size_t shortest = 0;
       for (size_t i = 0, L = arglist->length(); i < L; ++i) {
-        List_Obj ith = SASS_MEMORY_CAST(List, arglist->value_at_index(i));
-        Map_Obj mith = SASS_MEMORY_CAST(Map, arglist->value_at_index(i));
+        List_Obj ith = Cast<List>(arglist->value_at_index(i));
+        Map_Obj mith = Cast<Map>(arglist->value_at_index(i));
         if (!ith) {
           if (mith) {
-            ith = mith->to_list(ctx, pstate);
+            ith = mith->to_list(pstate);
           } else {
             ith = SASS_MEMORY_NEW(List, pstate, 1);
             ith->append(arglist->value_at_index(i));
           }
           if (arglist->is_arglist()) {
-            Argument_Obj arg = (Argument_Ptr)(&arglist->at(i));
-            arg->value(&ith);
+            Argument_Obj arg = (Argument_Ptr)(arglist->at(i).ptr()); // XXX
+            arg->value(ith);
           } else {
-            (*arglist)[i] = &ith;
+            (*arglist)[i] = ith;
           }
         }
         shortest = (i ? std::min(shortest, ith->length()) : ith->length());
@@ -1428,7 +1609,7 @@
       for (size_t i = 0; i < shortest; ++i) {
         List_Ptr zipper = SASS_MEMORY_NEW(List, pstate, L);
         for (size_t j = 0; j < L; ++j) {
-          zipper->append(SASS_MEMORY_CAST(List, arglist->value_at_index(j))->at(i));
+          zipper->append(Cast<List>(arglist->value_at_index(j))->at(i));
         }
         zippers->append(zipper);
       }
@@ -1438,7 +1619,7 @@
     Signature list_separator_sig = "list_separator($list)";
     BUILT_IN(list_separator)
     {
-      List_Obj l = SASS_MEMORY_CAST(List, env["$list"]);
+      List_Obj l = Cast<List>(env["$list"]);
       if (!l) {
         l = SASS_MEMORY_NEW(List, pstate, 1);
         l->append(ARG("$list", Expression));
@@ -1460,8 +1641,10 @@
       Map_Obj m = ARGM("$map", Map, ctx);
       Expression_Obj v = ARG("$key", Expression);
       try {
-        Expression_Obj val = m->at(v); // XXX
-        return val ? val.detach() : SASS_MEMORY_NEW(Null, pstate);
+        Expression_Obj val = m->at(v);
+        if (!val) return SASS_MEMORY_NEW(Null, pstate);
+        val->set_delayed(false);
+        return val.detach();
       } catch (const std::out_of_range&) {
         return SASS_MEMORY_NEW(Null, pstate);
       }
@@ -1507,8 +1690,8 @@
       size_t len = m1->length() + m2->length();
       Map_Ptr result = SASS_MEMORY_NEW(Map, pstate, len);
       // concat not implemented for maps
-      *result += &m1;
-      *result += &m2;
+      *result += m1;
+      *result += m2;
       return result;
     }
 
@@ -1522,7 +1705,7 @@
       for (auto key : m->keys()) {
         remove = false;
         for (size_t j = 0, K = arglist->length(); j < K && !remove; ++j) {
-          remove = Eval::eq(key, arglist->value_at_index(j));
+          remove = Operators::eq(key, arglist->value_at_index(j));
         }
         if (!remove) *result << std::make_pair(key, m->at(key));
       }
@@ -1536,7 +1719,7 @@
       Map_Obj result = SASS_MEMORY_NEW(Map, pstate, 1);
       for (size_t i = arglist->size(), L = arglist->length(); i < L; ++i) {
         Expression_Obj obj = arglist->at(i);
-        Argument_Obj arg = (Argument_Ptr)&obj;
+        Argument_Obj arg = (Argument_Ptr) obj.ptr(); // XXX
         std::string name = std::string(arg->name());
         name = name.erase(0, 1); // sanitize name (remove dollar sign)
         *result << std::make_pair(SASS_MEMORY_NEW(String_Quoted,
@@ -1559,23 +1742,33 @@
 
     Signature unit_sig = "unit($number)";
     BUILT_IN(unit)
-    { return SASS_MEMORY_NEW(String_Quoted, pstate, quote(ARG("$number", Number)->unit(), '"')); }
+    {
+      Number_Obj arg = ARGN("$number");
+      std::string str(quote(arg->unit(), '"'));
+      return SASS_MEMORY_NEW(String_Quoted, pstate, str);
+    }
 
     Signature unitless_sig = "unitless($number)";
     BUILT_IN(unitless)
-    { return SASS_MEMORY_NEW(Boolean, pstate, ARG("$number", Number)->is_unitless()); }
+    {
+      Number_Obj arg = ARGN("$number");
+      bool unitless = arg->is_unitless();
+      return SASS_MEMORY_NEW(Boolean, pstate, unitless);
+    }
 
     Signature comparable_sig = "comparable($number-1, $number-2)";
     BUILT_IN(comparable)
     {
-      Number_Ptr n1 = ARG("$number-1", Number);
-      Number_Ptr n2 = ARG("$number-2", Number);
+      Number_Obj n1 = ARGN("$number-1");
+      Number_Obj n2 = ARGN("$number-2");
       if (n1->is_unitless() || n2->is_unitless()) {
         return SASS_MEMORY_NEW(Boolean, pstate, true);
       }
-      Number tmp_n2(n2); // copy
-      tmp_n2.normalize(n1->find_convertible_unit());
-      return SASS_MEMORY_NEW(Boolean, pstate, n1->unit() == tmp_n2.unit());
+      // normalize into main units
+      n1->normalize(); n2->normalize();
+      Units &lhs_unit = *n1, &rhs_unit = *n2;
+      bool is_comparable = (lhs_unit == rhs_unit);
+      return SASS_MEMORY_NEW(Boolean, pstate, is_comparable);
     }
 
     Signature variable_exists_sig = "variable-exists($name)";
@@ -1607,9 +1800,14 @@
     Signature function_exists_sig = "function-exists($name)";
     BUILT_IN(function_exists)
     {
-      std::string s = Util::normalize_underscores(unquote(ARG("$name", String_Constant)->value()));
+      String_Constant_Ptr ss = Cast<String_Constant>(env["$name"]);
+      if (!ss) {
+        error("$name: " + (env["$name"]->to_string()) + " is not a string for `function-exists'", pstate, traces);
+      }
 
-      if(d_env.has_global(s+"[f]")) {
+      std::string name = Util::normalize_underscores(unquote(ss->value()));
+
+      if(d_env.has_global(name+"[f]")) {
         return SASS_MEMORY_NEW(Boolean, pstate, true);
       }
       else {
@@ -1646,24 +1844,37 @@
     Signature call_sig = "call($name, $args...)";
     BUILT_IN(call)
     {
-      std::string name = Util::normalize_underscores(unquote(ARG("$name", String_Constant)->value()));
+      std::string name;
+      Function_Ptr ff = Cast<Function>(env["$name"]);
+      String_Constant_Ptr ss = Cast<String_Constant>(env["$name"]);
+
+      if (ss) {
+        name = Util::normalize_underscores(unquote(ss->value()));
+        std::cerr << "DEPRECATION WARNING: ";
+        std::cerr << "Passing a string to call() is deprecated and will be illegal" << std::endl;
+        std::cerr << "in Sass 4.0. Use call(get-function(" + quote(name) + ")) instead." << std::endl;
+        std::cerr << std::endl;
+      } else if (ff) {
+        name = ff->name();
+      }
+
       List_Obj arglist = SASS_MEMORY_COPY(ARG("$args", List));
 
       Arguments_Obj args = SASS_MEMORY_NEW(Arguments, pstate);
       // std::string full_name(name + "[f]");
-      // Definition_Ptr def = d_env.has(full_name) ? static_cast<Definition_Ptr>((d_env)[full_name]) : 0;
+      // Definition_Ptr def = d_env.has(full_name) ? Cast<Definition>((d_env)[full_name]) : 0;
       // Parameters_Ptr params = def ? def->parameters() : 0;
       // size_t param_size = params ? params->length() : 0;
       for (size_t i = 0, L = arglist->length(); i < L; ++i) {
         Expression_Obj expr = arglist->value_at_index(i);
         // if (params && params->has_rest_parameter()) {
         //   Parameter_Obj p = param_size > i ? (*params)[i] : 0;
-        //   List_Ptr list = SASS_MEMORY_CAST(List, expr);
+        //   List_Ptr list = Cast<List>(expr);
         //   if (list && p && !p->is_rest_parameter()) expr = (*list)[0];
         // }
         if (arglist->is_arglist()) {
           Expression_Obj obj = arglist->at(i);
-          Argument_Obj arg = (Argument_Ptr)&obj;
+          Argument_Obj arg = (Argument_Ptr) obj.ptr(); // XXX
           args->append(SASS_MEMORY_NEW(Argument,
                                        pstate,
                                        expr,
@@ -1674,11 +1885,11 @@
           args->append(SASS_MEMORY_NEW(Argument, pstate, expr));
         }
       }
-      Function_Call_Obj func = SASS_MEMORY_NEW(Function_Call, pstate, name, &args);
-      Expand expand(ctx, &d_env, backtrace, &selector_stack);
+      Function_Call_Obj func = SASS_MEMORY_NEW(Function_Call, pstate, name, args);
+      Expand expand(ctx, &d_env, &selector_stack);
       func->via_call(true); // calc invoke is allowed
+      if (ff) func->func(ff);
       return func->perform(&expand.eval);
-
     }
 
     ////////////////////
@@ -1696,24 +1907,13 @@
     // { return ARG("$condition", Expression)->is_false() ? ARG("$if-false", Expression) : ARG("$if-true", Expression); }
     BUILT_IN(sass_if)
     {
-      Expand expand(ctx, &d_env, backtrace, &selector_stack);
+      Expand expand(ctx, &d_env, &selector_stack);
       Expression_Obj cond = ARG("$condition", Expression)->perform(&expand.eval);
       bool is_true = !cond->is_false();
-      Expression_Ptr res = ARG(is_true ? "$if-true" : "$if-false", Expression);
+      Expression_Obj res = ARG(is_true ? "$if-true" : "$if-false", Expression);
       res = res->perform(&expand.eval);
       res->set_delayed(false); // clone?
-      return res;
-    }
-
-    ////////////////
-    // URL FUNCTIONS
-    ////////////////
-
-    Signature image_url_sig = "image-url($path, $only-path: false, $cache-buster: false)";
-    BUILT_IN(image_url)
-    {
-      error("`image_url` has been removed from libsass because it's not part of the Sass spec", pstate);
-      return 0; // suppress warning, error will exit anyway
+      return res.detach();
     }
 
     //////////////////////////
@@ -1754,24 +1954,24 @@
 
       // Not enough parameters
       if( arglist->length() == 0 )
-        error("$selectors: At least one selector must be passed for `selector-nest'", pstate);
+        error("$selectors: At least one selector must be passed for `selector-nest'", pstate, traces);
 
       // Parse args into vector of selectors
       std::vector<Selector_List_Obj> parsedSelectors;
       for (size_t i = 0, L = arglist->length(); i < L; ++i) {
-        Expression_Obj exp = SASS_MEMORY_CAST(Expression, arglist->value_at_index(i));
+        Expression_Obj exp = Cast<Expression>(arglist->value_at_index(i));
         if (exp->concrete_type() == Expression::NULL_VAL) {
           std::stringstream msg;
           msg << "$selectors: null is not a valid selector: it must be a string,\n";
           msg << "a list of strings, or a list of lists of strings for 'selector-nest'";
-          error(msg.str(), pstate);
+          error(msg.str(), pstate, traces);
         }
-        if (String_Constant_Obj str = SASS_MEMORY_CAST(String_Constant, exp)) {
+        if (String_Constant_Obj str = Cast<String_Constant>(exp)) {
           str->quote_mark(0);
         }
-        std::string exp_src = exp->to_string(ctx.c_options) + "{";
-        Selector_List_Obj sel = Parser::parse_selector(exp_src.c_str(), ctx);
-        parsedSelectors.push_back(&sel);
+        std::string exp_src = exp->to_string(ctx.c_options);
+        Selector_List_Obj sel = Parser::parse_selector(exp_src.c_str(), ctx, traces);
+        parsedSelectors.push_back(sel);
       }
 
       // Nothing to do
@@ -1787,8 +1987,8 @@
       for(;itr != parsedSelectors.end(); ++itr) {
         Selector_List_Obj child = *itr;
         std::vector<Complex_Selector_Obj> exploded;
-        selector_stack.push_back(&result);
-        Selector_List_Obj rv = child->resolve_parent_refs(ctx, selector_stack);
+        selector_stack.push_back(result);
+        Selector_List_Obj rv = child->resolve_parent_refs(selector_stack, traces);
         selector_stack.pop_back();
         for (size_t m = 0, mLen = rv->length(); m < mLen; ++m) {
           exploded.push_back((*rv)[m]);
@@ -1807,24 +2007,24 @@
 
       // Not enough parameters
       if( arglist->length() == 0 )
-        error("$selectors: At least one selector must be passed for `selector-append'", pstate);
+        error("$selectors: At least one selector must be passed for `selector-append'", pstate, traces);
 
       // Parse args into vector of selectors
       std::vector<Selector_List_Obj> parsedSelectors;
       for (size_t i = 0, L = arglist->length(); i < L; ++i) {
-        Expression_Obj exp = SASS_MEMORY_CAST(Expression, arglist->value_at_index(i));
+        Expression_Obj exp = Cast<Expression>(arglist->value_at_index(i));
         if (exp->concrete_type() == Expression::NULL_VAL) {
           std::stringstream msg;
           msg << "$selectors: null is not a valid selector: it must be a string,\n";
           msg << "a list of strings, or a list of lists of strings for 'selector-append'";
-          error(msg.str(), pstate);
+          error(msg.str(), pstate, traces);
         }
-        if (String_Constant_Ptr str = SASS_MEMORY_CAST(String_Constant, exp)) {
+        if (String_Constant_Ptr str = Cast<String_Constant>(exp)) {
           str->quote_mark(0);
         }
-        std::string exp_src = exp->to_string() + "{";
-        Selector_List_Obj sel = Parser::parse_selector(exp_src.c_str(), ctx);
-        parsedSelectors.push_back(&sel);
+        std::string exp_src = exp->to_string();
+        Selector_List_Obj sel = Parser::parse_selector(exp_src.c_str(), ctx, traces);
+        parsedSelectors.push_back(sel);
       }
 
       // Nothing to do
@@ -1861,29 +2061,29 @@
               msg += "\" to \"";
               msg += parentSeqClone->to_string();
               msg += "\" for `selector-append'";
-              error(msg, pstate, backtrace);
+              error(msg, pstate, traces);
             }
 
             // Cannot be a Universal selector
-            Element_Selector_Obj pType = SASS_MEMORY_CAST(Element_Selector, childSeq->head()->first());
+            Element_Selector_Obj pType = Cast<Element_Selector>(childSeq->head()->first());
             if(pType && pType->name() == "*") {
               std::string msg("Can't append \"");
               msg += childSeq->to_string();
               msg += "\" to \"";
               msg += parentSeqClone->to_string();
               msg += "\" for `selector-append'";
-              error(msg, pstate, backtrace);
+              error(msg, pstate, traces);
             }
 
             // TODO: Add check for namespace stuff
 
             // append any selectors in childSeq's head
-            parentSeqClone->innermost()->head()->concat(&base->head());
+            parentSeqClone->innermost()->head()->concat(base->head());
 
             // Set parentSeqClone new tail
             parentSeqClone->innermost()->tail( base->tail() );
 
-            newElements.push_back(&parentSeqClone);
+            newElements.push_back(parentSeqClone);
           }
         }
 
@@ -1900,7 +2100,7 @@
       Selector_List_Obj selector1 = ARGSEL("$selector1", Selector_List_Obj, p_contextualize);
       Selector_List_Obj selector2 = ARGSEL("$selector2", Selector_List_Obj, p_contextualize);
 
-      Selector_List_Obj result = selector1->unify_with(&selector2, ctx);
+      Selector_List_Obj result = selector1->unify_with(selector2);
       Listize listize;
       return result->perform(&listize);
     }
@@ -1930,9 +2130,10 @@
       Selector_List_Obj  extender = ARGSEL("$extender", Selector_List_Obj, p_contextualize);
 
       Subset_Map subset_map;
-      extender->populate_extends(extendee, ctx, subset_map);
+      extender->populate_extends(extendee, subset_map);
+      Extend extend(subset_map);
 
-      Selector_List_Obj result = Extend::extendSelectorList(selector, ctx, subset_map, false);
+      Selector_List_Obj result = extend.extendSelectorList(selector, false);
 
       Listize listize;
       return result->perform(&listize);
@@ -1945,9 +2146,10 @@
       Selector_List_Obj original = ARGSEL("$original", Selector_List_Obj, p_contextualize);
       Selector_List_Obj replacement = ARGSEL("$replacement", Selector_List_Obj, p_contextualize);
       Subset_Map subset_map;
-      replacement->populate_extends(original, ctx, subset_map);
+      replacement->populate_extends(original, subset_map);
+      Extend extend(subset_map);
 
-      Selector_List_Obj result = Extend::extendSelectorList(selector, ctx, subset_map, true);
+      Selector_List_Obj result = extend.extendSelectorList(selector, true);
 
       Listize listize;
       return result->perform(&listize);
@@ -1981,5 +2183,52 @@
       return SASS_MEMORY_NEW(String_Quoted, pstate, ss.str());
     }
 
+    Signature is_bracketed_sig = "is-bracketed($list)";
+    BUILT_IN(is_bracketed)
+    {
+      Value_Obj value = ARG("$list", Value);
+      List_Obj list = Cast<List>(value);
+      return SASS_MEMORY_NEW(Boolean, pstate, list && list->is_bracketed());
+    }
+
+    Signature content_exists_sig = "content-exists()";
+    BUILT_IN(content_exists)
+    {
+      if (!d_env.has_global("is_in_mixin")) {
+        error("Cannot call content-exists() except within a mixin.", pstate, traces);
+      }
+      return SASS_MEMORY_NEW(Boolean, pstate, d_env.has_lexical("@content[m]"));
+    }
+
+    Signature get_function_sig = "get-function($name, $css: false)";
+    BUILT_IN(get_function)
+    {
+      String_Constant_Ptr ss = Cast<String_Constant>(env["$name"]);
+      if (!ss) {
+        error("$name: " + (env["$name"]->to_string()) + " is not a string for `get-function'", pstate, traces);
+      }
+
+      std::string name = Util::normalize_underscores(unquote(ss->value()));
+      std::string full_name = name + "[f]";
+
+      Boolean_Obj css = ARG("$css", Boolean);
+      if (!css->is_false()) {
+        Definition_Ptr def = SASS_MEMORY_NEW(Definition,
+                                         pstate,
+                                         name,
+                                         SASS_MEMORY_NEW(Parameters, pstate),
+                                         SASS_MEMORY_NEW(Block, pstate, 0, false),
+                                         Definition::FUNCTION);
+        return SASS_MEMORY_NEW(Function, pstate, def, true);
+      }
+
+
+      if (!d_env.has_global(full_name)) {
+        error("Function not found: " + name, pstate, traces);
+      }
+
+      Definition_Ptr def = Cast<Definition>(d_env[full_name]);
+      return SASS_MEMORY_NEW(Function, pstate, def, false);
+    }
   }
 }
diff --git a/libsass/src/functions.hpp b/libsass/src/functions.hpp
--- a/libsass/src/functions.hpp
+++ b/libsass/src/functions.hpp
@@ -8,13 +8,12 @@
 #include "sass/functions.h"
 
 #define BUILT_IN(name) Expression_Ptr \
-name(Env& env, Env& d_env, Context& ctx, Signature sig, ParserState pstate, Backtrace* backtrace, std::vector<Selector_List_Obj> selector_stack)
+name(Env& env, Env& d_env, Context& ctx, Signature sig, ParserState pstate, Backtraces traces, std::vector<Selector_List_Obj> selector_stack)
 
 namespace Sass {
   struct Backtrace;
-  typedef Environment<AST_Node_Obj> Env;
   typedef const char* Signature;
-  typedef Expression_Ptr (*Native_Function)(Env&, Env&, Context&, Signature, ParserState, Backtrace*, std::vector<Selector_List_Obj>);
+  typedef Expression_Ptr (*Native_Function)(Env&, Env&, Context&, Signature, ParserState, Backtraces, std::vector<Selector_List_Obj>);
 
   Definition_Ptr make_native_function(Signature, Native_Function, Context& ctx);
   Definition_Ptr make_c_function(Sass_Function_Entry c_func, Context& ctx);
@@ -89,7 +88,6 @@
     extern Signature call_sig;
     extern Signature not_sig;
     extern Signature if_sig;
-    extern Signature image_url_sig;
     extern Signature map_get_sig;
     extern Signature map_merge_sig;
     extern Signature map_remove_sig;
@@ -107,6 +105,9 @@
     extern Signature is_superselector_sig;
     extern Signature simple_selectors_sig;
     extern Signature selector_parse_sig;
+    extern Signature is_bracketed_sig;
+    extern Signature content_exists_sig;
+    extern Signature get_function_sig;
 
     BUILT_IN(rgb);
     BUILT_IN(rgba_4);
@@ -171,7 +172,6 @@
     BUILT_IN(call);
     BUILT_IN(sass_not);
     BUILT_IN(sass_if);
-    BUILT_IN(image_url);
     BUILT_IN(map_get);
     BUILT_IN(map_merge);
     BUILT_IN(map_remove);
@@ -189,6 +189,9 @@
     BUILT_IN(is_superselector);
     BUILT_IN(simple_selectors);
     BUILT_IN(selector_parse);
+    BUILT_IN(is_bracketed);
+    BUILT_IN(content_exists);
+    BUILT_IN(get_function);
   }
 }
 
diff --git a/libsass/src/inspect.cpp b/libsass/src/inspect.cpp
--- a/libsass/src/inspect.cpp
+++ b/libsass/src/inspect.cpp
@@ -15,7 +15,7 @@
 
 namespace Sass {
 
-  Inspect::Inspect(Emitter emi)
+  Inspect::Inspect(const Emitter& emi)
   : Emitter(emi)
   { }
   Inspect::~Inspect() { }
@@ -42,7 +42,9 @@
   void Inspect::operator()(Ruleset_Ptr ruleset)
   {
     if (ruleset->selector()) {
+      opt.in_selector = true;
       ruleset->selector()->perform(this);
+      opt.in_selector = false;
     }
     if (ruleset->block()) {
       ruleset->block()->perform(this);
@@ -90,7 +92,7 @@
     append_token("@at-root ", at_root_block);
     append_mandatory_space();
     if(at_root_block->expression()) at_root_block->expression()->perform(this);
-    at_root_block->block()->perform(this);
+    if(at_root_block->block()) at_root_block->block()->perform(this);
   }
 
   void Inspect::operator()(Directive_Ptr at_rule)
@@ -121,6 +123,8 @@
     if (dec->value()->concrete_type() == Expression::NULL_VAL) return;
     bool was_decl = in_declaration;
     in_declaration = true;
+    LOCAL_FLAG(in_custom_property, dec->is_custom_property());
+
     if (output_style() == NESTED)
       indentation += dec->tabs();
     append_indentation();
@@ -166,7 +170,7 @@
 
       import->urls().front()->perform(this);
       if (import->urls().size() == 1) {
-        if (&import->import_queries()) {
+        if (import->import_queries()) {
           append_mandatory_space();
           import->import_queries()->perform(this);
         }
@@ -179,7 +183,7 @@
 
         import->urls()[i]->perform(this);
         if (import->urls().size() - 1 == i) {
-          if (&import->import_queries()) {
+          if (import->import_queries()) {
             append_mandatory_space();
             import->import_queries()->perform(this);
           }
@@ -354,16 +358,27 @@
       if (items_output) append_comma_separator();
       key->perform(this);
       append_colon_separator();
+      LOCAL_FLAG(in_space_array, true);
+      LOCAL_FLAG(in_comma_array, true);
       map->at(key)->perform(this);
       items_output = true;
     }
     append_string(")");
   }
 
+  std::string Inspect::lbracket(List_Ptr list) {
+    return list->is_bracketed() ? "[" : "(";
+  }
+
+  std::string Inspect::rbracket(List_Ptr list) {
+    return list->is_bracketed() ? "]" : ")";
+  }
+
   void Inspect::operator()(List_Ptr list)
   {
-    if (output_style() == TO_SASS && list->empty()) {
-      append_string("()");
+    if (list->empty() && (output_style() == TO_SASS || list->is_bracketed())) {
+      append_string(lbracket(list));
+      append_string(rbracket(list));
       return;
     }
     std::string sep(list->separator() == SASS_SPACE ? " " : ",");
@@ -374,19 +389,24 @@
 
     bool was_space_array = in_space_array;
     bool was_comma_array = in_comma_array;
+    // if the list is bracketed, always include the left bracket
+    if (list->is_bracketed()) {
+      append_string(lbracket(list));
+    }
     // probably ruby sass eqivalent of element_needs_parens
-    if (output_style() == TO_SASS &&
+    else if (output_style() == TO_SASS &&
         list->length() == 1 &&
         !list->from_selector() &&
-        !SASS_MEMORY_CAST(List, list->at(0)) &&
-        !SASS_MEMORY_CAST(Selector_List, list->at(0))) {
-      append_string("(");
+        !Cast<List>(list->at(0)) &&
+        !Cast<Selector_List>(list->at(0))
+    ) {
+      append_string(lbracket(list));
     }
     else if (!in_declaration && (list->separator() == SASS_HASH ||
         (list->separator() == SASS_SPACE && in_space_array) ||
         (list->separator() == SASS_COMMA && in_comma_array)
     )) {
-      append_string("(");
+      append_string(lbracket(list));
     }
 
     if (list->separator() == SASS_SPACE) in_space_array = true;
@@ -399,7 +419,7 @@
       if (output_style() != TO_SASS) {
         if (list_item->is_invisible()) {
           // this fixes an issue with "" in a list
-          if (!SASS_MEMORY_CAST(String_Constant, list_item)) {
+          if (!Cast<String_Constant>(list_item)) {
             continue;
           }
         }
@@ -415,19 +435,29 @@
 
     in_comma_array = was_comma_array;
     in_space_array = was_space_array;
+
+    // if the list is bracketed, always include the right bracket
+    if (list->is_bracketed()) {
+      if (list->separator() == SASS_COMMA && list->size() == 1) {
+        append_string(",");
+      }
+      append_string(rbracket(list));
+    }
     // probably ruby sass eqivalent of element_needs_parens
-    if (output_style() == TO_SASS &&
+    else if (output_style() == TO_SASS &&
         list->length() == 1 &&
         !list->from_selector() &&
-        !SASS_MEMORY_CAST(List, list->at(0)) &&
-        !SASS_MEMORY_CAST(Selector_List, list->at(0))) {
-      append_string(",)");
+        !Cast<List>(list->at(0)) &&
+        !Cast<Selector_List>(list->at(0))
+    ) {
+      append_string(",");
+      append_string(rbracket(list));
     }
     else if (!in_declaration && (list->separator() == SASS_HASH ||
         (list->separator() == SASS_SPACE && in_space_array) ||
         (list->separator() == SASS_COMMA && in_comma_array)
     )) {
-      append_string(")");
+      append_string(rbracket(list));
     }
 
   }
@@ -443,7 +473,7 @@
               expr->is_right_interpolant())
 
     )) append_string(" ");
-    switch (expr->type()) {
+    switch (expr->optype()) {
       case Sass_OP::AND: append_string("&&"); break;
       case Sass_OP::OR:  append_string("||");  break;
       case Sass_OP::EQ:  append_string("==");  break;
@@ -471,8 +501,9 @@
 
   void Inspect::operator()(Unary_Expression_Ptr expr)
   {
-    if (expr->type() == Unary_Expression::PLUS) append_string("+");
-    else                                        append_string("-");
+    if (expr->optype() == Unary_Expression::PLUS)       append_string("+");
+    else if (expr->optype() == Unary_Expression::SLASH) append_string("/");
+    else                                                append_string("-");
     expr->operand()->perform(this);
   }
 
@@ -493,16 +524,14 @@
     append_token(var->name(), var);
   }
 
-  void Inspect::operator()(Textual_Ptr txt)
-  {
-    append_token(txt->value(), txt);
-  }
-
   void Inspect::operator()(Number_Ptr n)
   {
 
     std::string res;
 
+    // reduce units
+    n->reduce();
+
     // 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;
@@ -600,6 +629,11 @@
     // maybe an unknown token
     std::string name = c->disp();
 
+    if (opt.in_selector && name != "") {
+      append_token(name, c);
+      return;
+    }
+
     // resolved color
     std::string res_name = name;
 
@@ -648,7 +682,7 @@
       ss << name;
     }
     else if (r == 0 && g == 0 && b == 0 && a == 0) {
-        ss << "transparent";
+      ss << "transparent";
     }
     else if (a >= 1) {
       if (res_name != "") {
@@ -744,9 +778,9 @@
   {
     append_token("not", sn);
     append_mandatory_space();
-    if (sn->needs_parens(&sn->condition())) append_string("(");
+    if (sn->needs_parens(sn->condition())) append_string("(");
     sn->condition()->perform(this);
-    if (sn->needs_parens(&sn->condition())) append_string(")");
+    if (sn->needs_parens(sn->condition())) append_string(")");
   }
 
   void Inspect::operator()(Supports_Declaration_Ptr sd)
@@ -766,7 +800,7 @@
   void Inspect::operator()(Media_Query_Ptr mq)
   {
     size_t i = 0;
-    if (&mq->media_type()) {
+    if (mq->media_type()) {
       if      (mq->is_negated())    append_string("not ");
       else if (mq->is_restricted()) append_string("only ");
       mq->media_type()->perform(this);
@@ -798,12 +832,22 @@
 
   void Inspect::operator()(At_Root_Query_Ptr ae)
   {
-    append_string("(");
-    ae->feature()->perform(this);
-    if (ae->value()) {
-      append_colon_separator();
-      ae->value()->perform(this);
+    if (ae->feature()) {
+      append_string("(");
+      ae->feature()->perform(this);
+      if (ae->value()) {
+        append_colon_separator();
+        ae->value()->perform(this);
+      }
+      append_string(")");
     }
+  }
+
+  void Inspect::operator()(Function_Ptr f)
+  {
+    append_token("get-function", f);
+    append_string("(");
+    append_string(quote(f->name()));
     append_string(")");
   }
 
@@ -851,7 +895,7 @@
       return;
     }
     if (a->value()->concrete_type() == Expression::STRING) {
-      String_Constant_Ptr s = SASS_MEMORY_CAST(String_Constant, a->value());
+      String_Constant_Ptr s = Cast<String_Constant>(a->value());
       if (s) s->perform(this);
     } else {
       a->value()->perform(this);
@@ -877,7 +921,9 @@
 
   void Inspect::operator()(Selector_Schema_Ptr s)
   {
+    opt.in_selector = true;
     s->contents()->perform(this);
+    opt.in_selector = false;
   }
 
   void Inspect::operator()(Parent_Selector_Ptr p)
@@ -919,11 +965,15 @@
     append_token(s->ns_name(), s);
     if (!s->matcher().empty()) {
       append_string(s->matcher());
-      if (&s->value() && *s->value()) {
+      if (s->value() && *s->value()) {
         s->value()->perform(this);
       }
     }
     add_close_mapping(s);
+    if (s->modifier() != 0) {
+      append_mandatory_space();
+      append_char(s->modifier());
+    }
     append_string("]");
   }
 
@@ -939,16 +989,20 @@
 
   void Inspect::operator()(Wrapped_Selector_Ptr s)
   {
-    bool was = in_wrapped;
-    in_wrapped = true;
-    append_token(s->name(), s);
-    append_string("(");
-    bool was_comma_array = in_comma_array;
-    in_comma_array = false;
-    s->selector()->perform(this);
-    in_comma_array = was_comma_array;
-    append_string(")");
-    in_wrapped = was;
+    if (s->name() == " ") {
+      append_string("");
+    } else {
+      bool was = in_wrapped;
+      in_wrapped = true;
+      append_token(s->name(), s);
+      append_string("(");
+      bool was_comma_array = in_comma_array;
+      in_comma_array = false;
+      s->selector()->perform(this);
+      in_comma_array = was_comma_array;
+      append_string(")");
+      in_wrapped = was;
+    }
   }
 
   void Inspect::operator()(Compound_Selector_Ptr s)
@@ -1014,6 +1068,7 @@
         if (tail) append_mandatory_space();
         else append_optional_space();
       break;
+      default: break;
     }
     if (tail && comb != Complex_Selector::ANCESTOR_OF) {
       if (c->has_line_break()) append_optional_linefeed();
@@ -1040,8 +1095,8 @@
     bool was_comma_array = in_comma_array;
     // probably ruby sass eqivalent of element_needs_parens
     if (output_style() == TO_SASS && g->length() == 1 &&
-      (!SASS_MEMORY_CAST(List, (*g)[0]) &&
-       !SASS_MEMORY_CAST(Selector_List, (*g)[0]))) {
+      (!Cast<List>((*g)[0]) &&
+       !Cast<Selector_List>((*g)[0]))) {
       append_string("(");
     }
     else if (!in_declaration && in_comma_array) {
@@ -1053,7 +1108,7 @@
     for (size_t i = 0, L = g->length(); i < L; ++i) {
       if (!in_wrapped && i == 0) append_indentation();
       if ((*g)[i] == 0) continue;
-      schedule_mapping(&g->at(i)->last());
+      schedule_mapping(g->at(i)->last());
       // add_open_mapping((*g)[i]->last());
       (*g)[i]->perform(this);
       // add_close_mapping((*g)[i]->last());
@@ -1066,8 +1121,8 @@
     in_comma_array = was_comma_array;
     // probably ruby sass eqivalent of element_needs_parens
     if (output_style() == TO_SASS && g->length() == 1 &&
-      (!SASS_MEMORY_CAST(List, (*g)[0]) &&
-       !SASS_MEMORY_CAST(Selector_List, (*g)[0]))) {
+      (!Cast<List>((*g)[0]) &&
+       !Cast<Selector_List>((*g)[0]))) {
       append_string(",)");
     }
     else if (!in_declaration && in_comma_array) {
diff --git a/libsass/src/inspect.hpp b/libsass/src/inspect.hpp
--- a/libsass/src/inspect.hpp
+++ b/libsass/src/inspect.hpp
@@ -17,7 +17,7 @@
 
   public:
 
-    Inspect(Emitter emi);
+    Inspect(const Emitter& emi);
     virtual ~Inspect();
 
     // statements
@@ -48,6 +48,7 @@
     virtual void operator()(Content_Ptr);
     // expressions
     virtual void operator()(Map_Ptr);
+    virtual void operator()(Function_Ptr);
     virtual void operator()(List_Ptr);
     virtual void operator()(Binary_Expression_Ptr);
     virtual void operator()(Unary_Expression_Ptr);
@@ -56,7 +57,6 @@
     // virtual void operator()(Custom_Warning_Ptr);
     // virtual void operator()(Custom_Error_Ptr);
     virtual void operator()(Variable_Ptr);
-    virtual void operator()(Textual_Ptr);
     virtual void operator()(Number_Ptr);
     virtual void operator()(Color_Ptr);
     virtual void operator()(Boolean_Ptr);
@@ -91,6 +91,9 @@
     virtual void operator()(Compound_Selector_Ptr);
     virtual void operator()(Complex_Selector_Ptr);
     virtual void operator()(Selector_List_Ptr);
+
+    virtual std::string lbracket(List_Ptr);
+    virtual std::string rbracket(List_Ptr);
 
     // template <typename U>
     // void fallback(U x) { fallback_impl(reinterpret_cast<AST_Node_Ptr>(x)); }
diff --git a/libsass/src/lexer.cpp b/libsass/src/lexer.cpp
--- a/libsass/src/lexer.cpp
+++ b/libsass/src/lexer.cpp
@@ -1,6 +1,5 @@
 #include "sass.hpp"
 #include <cctype>
-#include <cstddef>
 #include <iostream>
 #include <iomanip>
 #include "lexer.hpp"
@@ -50,6 +49,12 @@
       return unsigned(chr - '0') <= '9' - '0';
     }
 
+    bool is_number(const char& chr)
+    {
+      // adapted the technique from is_alpha
+      return is_digit(chr) || chr == '-' || chr == '+';
+    }
+
     bool is_xdigit(const char& chr)
     {
       // adapted the technique from is_alpha
@@ -80,10 +85,11 @@
     // but with specific ranges (copied from Ruby Sass)
     bool is_nonascii(const char& chr)
     {
+      unsigned int cmp = unsigned(chr);
       return (
-        (unsigned(chr) >= 128 && unsigned(chr) <= 15572911) ||
-        (unsigned(chr) >= 15630464 && unsigned(chr) <= 15712189) ||
-        (unsigned(chr) >= 4036001920)
+        (cmp >= 128 && cmp <= 15572911) ||
+        (cmp >= 15630464 && cmp <= 15712189) ||
+        (cmp >= 4036001920)
       );
     }
 
@@ -91,15 +97,17 @@
     // valid in a uri (copied from Ruby Sass)
     bool is_uri_character(const char& chr)
     {
-      return (unsigned(chr) > 41 && unsigned(chr) < 127) ||
-             unsigned(chr) == ':' || unsigned(chr) == '/';
+      unsigned int cmp = unsigned(chr);
+      return (cmp > 41 && cmp < 127) ||
+             cmp == ':' || cmp == '/';
     }
 
     // check if char is within a reduced ascii range
     // valid for escaping (copied from Ruby Sass)
     bool is_escapable_character(const char& chr)
     {
-      return unsigned(chr) > 31 && unsigned(chr) < 127;
+      unsigned int cmp = unsigned(chr);
+      return cmp > 31 && cmp < 127;
     }
 
     // Match word character (look ahead)
diff --git a/libsass/src/lexer.hpp b/libsass/src/lexer.hpp
--- a/libsass/src/lexer.hpp
+++ b/libsass/src/lexer.hpp
@@ -29,6 +29,7 @@
     bool is_alpha(const char& src);
     bool is_punct(const char& src);
     bool is_digit(const char& src);
+    bool is_number(const char& src);
     bool is_alnum(const char& src);
     bool is_xdigit(const char& src);
     bool is_unicode(const char& src);
@@ -96,9 +97,9 @@
     // Regex equivalent: /(?:literal)/
     template <const char* str>
     const char* exactly(const char* src) {
-      if (str == 0) return 0;
+      if (str == NULL) return 0;
       const char* pre = str;
-      if (src == 0) return 0;
+      if (src == NULL) return 0;
       // there is a small chance that the search string
       // is longer than the rest of the string to look at
       while (*pre && *src == *pre) {
@@ -109,14 +110,22 @@
     }
 
 
+    // Match a single character literal.
+    // Regex equivalent: /(?:x)/i
+    // only define lower case alpha chars
+    template <char chr>
+    const char* insensitive(const char* src) {
+      return *src == chr || *src+32 == chr ? src + 1 : 0;
+    }
+
     // Match the full string literal.
     // Regex equivalent: /(?:literal)/i
     // only define lower case alpha chars
     template <const char* str>
     const char* insensitive(const char* src) {
-      if (str == 0) return 0;
+      if (str == NULL) return 0;
       const char* pre = str;
-      if (src == 0) return 0;
+      if (src == NULL) return 0;
       // there is a small chance that the search string
       // is longer than the rest of the string to look at
       while (*pre && (*src == *pre || *src+32 == *pre)) {
diff --git a/libsass/src/listize.cpp b/libsass/src/listize.cpp
--- a/libsass/src/listize.cpp
+++ b/libsass/src/listize.cpp
@@ -64,13 +64,14 @@
       break;
       case Complex_Selector::ANCESTOR_OF:
       break;
+      default: break;
     }
 
     Complex_Selector_Obj tail = sel->tail();
     if (tail)
     {
       Expression_Obj tt = tail->perform(this);
-      if (List_Ptr ls = SASS_MEMORY_CAST(List, tt))
+      if (List_Ptr ls = Cast<List>(tt))
       { l->concat(ls); }
     }
     if (l->length() == 0) return 0;
@@ -79,7 +80,7 @@
 
   Expression_Ptr Listize::fallback_impl(AST_Node_Ptr n)
   {
-    return dynamic_cast<Expression_Ptr>(n);
+    return Cast<Expression>(n);
   }
 
 }
diff --git a/libsass/src/listize.hpp b/libsass/src/listize.hpp
--- a/libsass/src/listize.hpp
+++ b/libsass/src/listize.hpp
@@ -11,7 +11,6 @@
 
 namespace Sass {
 
-  typedef Environment<AST_Node_Obj> Env;
   struct Backtrace;
 
   class Listize : public Operation_CRTP<Expression_Ptr, Listize> {
diff --git a/libsass/src/memory/SharedPtr.cpp b/libsass/src/memory/SharedPtr.cpp
--- a/libsass/src/memory/SharedPtr.cpp
+++ b/libsass/src/memory/SharedPtr.cpp
@@ -17,8 +17,8 @@
       std::cerr << "###################################\n";
       std::cerr << "# REPORTING MISSING DEALLOCATIONS #\n";
       std::cerr << "###################################\n";
-      for (auto var : all) {
-        if (AST_Node_Ptr ast = SASS_MEMORY_CAST_PTR(AST_Node, var)) {
+      for (SharedObj* var : all) {
+        if (AST_Node_Ptr ast = dynamic_cast<AST_Node*>(var)) {
           debug_ast(ast);
         } else {
           std::cerr << "LEAKED " << var << "\n";
@@ -37,22 +37,20 @@
     , dbg(false)
     #endif
   {
-      refcounter = 0;
-      #ifdef DEBUG_SHARED_PTR
-        if (taint) all.push_back(this);
-      #endif
-    };
-
-    SharedObj::~SharedObj() {
-      #ifdef DEBUG_SHARED_PTR
-          if (dbg) std::cerr << "Destruct " << this << "\n";
-          if(!all.empty()) { // check needed for MSVC (no clue why?)
-            all.erase(std::remove(all.begin(), all.end(), this), all.end());
-          }
-      #endif
-    };
-
+    refcounter = 0;
+    #ifdef DEBUG_SHARED_PTR
+      if (taint) all.push_back(this);
+    #endif
+  };
 
+  SharedObj::~SharedObj() {
+    #ifdef DEBUG_SHARED_PTR
+      if (dbg) std::cerr << "Destruct " << this << "\n";
+      if(!all.empty()) { // check needed for MSVC (no clue why?)
+        all.erase(std::remove(all.begin(), all.end(), this), all.end());
+      }
+    #endif
+  };
 
   void SharedPtr::decRefCount() {
     if (node) {
@@ -62,7 +60,7 @@
       #endif
       if (node->refcounter == 0) {
         #ifdef DEBUG_SHARED_PTR
-          AST_Node_Ptr ptr = SASS_MEMORY_CAST_PTR(AST_Node, node);
+          // AST_Node_Ptr ast = dynamic_cast<AST_Node*>(node);
           if (node->dbg) std::cerr << "DELETE NODE " << node << "\n";
         #endif
         if (!node->detached) {
diff --git a/libsass/src/memory/SharedPtr.hpp b/libsass/src/memory/SharedPtr.hpp
--- a/libsass/src/memory/SharedPtr.hpp
+++ b/libsass/src/memory/SharedPtr.hpp
@@ -17,7 +17,7 @@
   #ifdef DEBUG_SHARED_PTR
 
     #define SASS_MEMORY_NEW(Class, ...) \
-      static_cast<Class##_Ptr>((new Class(__VA_ARGS__))->trace(__FILE__, __LINE__)) \
+      ((Class*)(new Class(__VA_ARGS__))->trace(__FILE__, __LINE__)) \
 
     #define SASS_MEMORY_COPY(obj) \
       ((obj)->copy(__FILE__, __LINE__)) \
@@ -38,12 +38,6 @@
 
   #endif
 
-  #define SASS_MEMORY_CAST(Class, obj) \
-    (dynamic_cast<Class##_Ptr>(&obj)) \
-
-  #define SASS_MEMORY_CAST_PTR(Class, ptr) \
-    (dynamic_cast<Class##_Ptr>(ptr)) \
-
   class SharedObj {
   protected:
   friend class SharedPtr;
@@ -92,9 +86,9 @@
 
 
   class SharedPtr {
-  private:
+  protected:
     SharedObj* node;
-  private:
+  protected:
     void decRefCount();
     void incRefCount();
   public:
@@ -103,24 +97,21 @@
     : node(NULL) {};
     // the create constructor
     SharedPtr(SharedObj* ptr);
-    // copy assignment operator
-    SharedPtr& operator=(const SharedPtr& rhs);
-    // move assignment operator
-    /* SharedPtr& operator=(SharedPtr&& rhs); */
     // the copy constructor
     SharedPtr(const SharedPtr& obj);
     // the move constructor
-    /* SharedPtr(SharedPtr&& obj); */
-    // destructor
-    ~SharedPtr();
+    SharedPtr(SharedPtr&& obj);
+    // copy assignment operator
+    SharedPtr& operator=(const SharedPtr& obj);
+    // move assignment operator
+    SharedPtr& operator=(SharedPtr&& obj);
+    // pure virtual destructor
+    virtual ~SharedPtr() = 0;
   public:
-    SharedObj* obj () {
-      return node;
-    };
     SharedObj* obj () const {
       return node;
     };
-    SharedObj* operator-> () {
+    SharedObj* operator-> () const {
       return node;
     };
     bool isNull () {
@@ -129,68 +120,81 @@
     bool isNull () const {
       return node == NULL;
     };
-    SharedObj* detach() {
-      node->detached = true;
-      return node;
-    };
     SharedObj* detach() const {
       if (node) {
         node->detached = true;
       }
       return node;
     };
-    operator bool() {
-      return node != NULL;
-    };
     operator bool() const {
       return node != NULL;
     };
 
   };
 
-  template < typename T >
+  template < class T >
   class SharedImpl : private SharedPtr {
   public:
     SharedImpl()
     : SharedPtr(NULL) {};
     SharedImpl(T* node)
     : SharedPtr(node) {};
+    template < class U >
+    SharedImpl(SharedImpl<U> obj)
+    : SharedPtr(static_cast<T*>(obj.ptr())) {}
     SharedImpl(T&& node)
     : SharedPtr(node) {};
     SharedImpl(const T& node)
     : SharedPtr(node) {};
+    // the copy constructor
+    SharedImpl(const SharedImpl<T>& impl)
+    : SharedPtr(impl.node) {};
+    // the move constructor
+    SharedImpl(SharedImpl<T>&& impl)
+    : SharedPtr(impl.node) {};
+    // copy assignment operator
+    SharedImpl<T>& operator=(const SharedImpl<T>& rhs) {
+      if (node) decRefCount();
+      node = rhs.node;
+      incRefCount();
+      return *this;
+    }
+    // move assignment operator
+    SharedImpl<T>& operator=(SharedImpl<T>&& rhs) {
+      // don't move our self
+      if (this != &rhs) {
+        if (node) decRefCount();
+        node = std::move(rhs.node);
+        rhs.node = NULL;
+      }
+      return *this;
+    }
     ~SharedImpl() {};
   public:
-    T* operator& () {
-      return static_cast<T*>(this->obj());
-    };
-    T* operator& () const {
+    operator T*() const {
       return static_cast<T*>(this->obj());
-    };
-    T& operator* () {
+    }
+    operator T&() const {
       return *static_cast<T*>(this->obj());
-    };
+    }
     T& operator* () const {
       return *static_cast<T*>(this->obj());
     };
-    T* operator-> () {
-      return static_cast<T*>(this->obj());
-    };
     T* operator-> () const {
       return static_cast<T*>(this->obj());
     };
-    T* ptr () {
+    T* ptr () const {
       return static_cast<T*>(this->obj());
     };
-    T* detach() {
+    T* detach() const {
       if (this->obj() == NULL) return NULL;
       return static_cast<T*>(SharedPtr::detach());
     }
-    bool isNull() {
+    bool isNull() const {
       return this->obj() == NULL;
     }
-    operator bool() {
-      return this->obj() != NULL;
+    bool operator<(const T& rhs) const {
+      return *this->ptr() < rhs;
     };
     operator bool() const {
       return this->obj() != NULL;
diff --git a/libsass/src/node.cpp b/libsass/src/node.cpp
--- a/libsass/src/node.cpp
+++ b/libsass/src/node.cpp
@@ -14,15 +14,15 @@
   }
 
 
-  Node Node::createSelector(Complex_Selector_Ptr pSelector, Context& ctx) {
+  Node Node::createSelector(const Complex_Selector& pSelector) {
     NodeDequePtr null;
 
-    Complex_Selector_Ptr pStripped = SASS_MEMORY_COPY(pSelector);
+    Complex_Selector_Ptr pStripped = SASS_MEMORY_COPY(&pSelector);
     pStripped->tail(NULL);
     pStripped->combinator(Complex_Selector::ANCESTOR_OF);
 
     Node n(SELECTOR, Complex_Selector::ANCESTOR_OF, pStripped, null /*pCollection*/);
-    if (pSelector) n.got_line_feed = pSelector->has_line_feed();
+    n.got_line_feed = pSelector.has_line_feed();
     return n;
   }
 
@@ -50,12 +50,12 @@
   { if (pSelector) got_line_feed = pSelector->has_line_feed(); }
 
 
-  Node Node::klone(Context& ctx) const {
+  Node Node::klone() const {
     NodeDequePtr pNewCollection = std::make_shared<NodeDeque>();
     if (mpCollection) {
       for (NodeDeque::iterator iter = mpCollection->begin(), iterEnd = mpCollection->end(); iter != iterEnd; iter++) {
         Node& toClone = *iter;
-        pNewCollection->push_back(toClone.klone(ctx));
+        pNewCollection->push_back(toClone.klone());
       }
     }
 
@@ -65,13 +65,13 @@
   }
 
 
-  bool Node::contains(const Node& potentialChild, bool simpleSelectorOrderDependent) const {
-  	bool found = false;
+  bool Node::contains(const Node& potentialChild) const {
+    bool found = false;
 
     for (NodeDeque::iterator iter = mpCollection->begin(), iterEnd = mpCollection->end(); iter != iterEnd; iter++) {
       Node& toTest = *iter;
 
-      if (nodesEqual(toTest, potentialChild, simpleSelectorOrderDependent)) {
+      if (toTest == potentialChild) {
         found = true;
         break;
       }
@@ -82,37 +82,32 @@
 
 
   bool Node::operator==(const Node& rhs) const {
-  	return nodesEqual(*this, rhs, true /*simpleSelectorOrderDependent*/);
-  }
-
-
-  bool nodesEqual(const Node& lhs, const Node& rhs, bool simpleSelectorOrderDependent) {
-    if (lhs.type() != rhs.type()) {
+    if (this->type() != rhs.type()) {
       return false;
     }
 
-    if (lhs.isCombinator()) {
+    if (this->isCombinator()) {
 
-    	return lhs.combinator() == rhs.combinator();
+      return this->combinator() == rhs.combinator();
 
-    } else if (lhs.isNil()) {
+    } else if (this->isNil()) {
 
       return true; // no state to check
 
-    } else if (lhs.isSelector()){
+    } else if (this->isSelector()){
 
-      return selectors_equal(*&lhs.selector(), *&rhs.selector(), simpleSelectorOrderDependent);
+      return *this->selector() == *rhs.selector();
 
-    } else if (lhs.isCollection()) {
+    } else if (this->isCollection()) {
 
-      if (lhs.collection()->size() != rhs.collection()->size()) {
+      if (this->collection()->size() != rhs.collection()->size()) {
         return false;
       }
 
-      for (NodeDeque::iterator lhsIter = lhs.collection()->begin(), lhsIterEnd = lhs.collection()->end(),
+      for (NodeDeque::iterator lhsIter = this->collection()->begin(), lhsIterEnd = this->collection()->end(),
            rhsIter = rhs.collection()->begin(); lhsIter != lhsIterEnd; lhsIter++, rhsIter++) {
 
-        if (!nodesEqual(*lhsIter, *rhsIter, simpleSelectorOrderDependent)) {
+        if (*lhsIter != *rhsIter) {
           return false;
         }
 
@@ -128,10 +123,10 @@
 
 
   void Node::plus(Node& rhs) {
-  	if (!this->isCollection() || !rhs.isCollection()) {
-    	throw "Both the current node and rhs must be collections.";
+    if (!this->isCollection() || !rhs.isCollection()) {
+      throw "Both the current node and rhs must be collections.";
     }
-  	this->collection()->insert(this->collection()->end(), rhs.collection()->begin(), rhs.collection()->end());
+    this->collection()->insert(this->collection()->end(), rhs.collection()->begin(), rhs.collection()->end());
   }
 
 #ifdef DEBUG
@@ -177,7 +172,7 @@
 #endif
 
 
-  Node complexSelectorToNode(Complex_Selector_Ptr pToConvert, Context& ctx) {
+  Node complexSelectorToNode(Complex_Selector_Ptr pToConvert) {
     if (pToConvert == NULL) {
       return Node::createNil();
     }
@@ -189,20 +184,22 @@
     if (pToConvert->head() && pToConvert->head()->has_parent_ref()) {
       Complex_Selector_Obj tail = pToConvert->tail();
       if (tail) tail->has_line_feed(pToConvert->has_line_feed());
-      pToConvert = &tail;
+      pToConvert = tail;
     }
 
     while (pToConvert) {
 
       bool empty_parent_ref = pToConvert->head() && pToConvert->head()->is_empty_reference();
 
-      if (pToConvert->head() || empty_parent_ref) {
-      }
-
       // the first Complex_Selector may contain a dummy head pointer, skip it.
       if (pToConvert->head() && !empty_parent_ref) {
-        node.collection()->push_back(Node::createSelector(pToConvert, ctx));
+        node.collection()->push_back(Node::createSelector(*pToConvert));
         if (has_lf) node.collection()->back().got_line_feed = has_lf;
+        if (pToConvert->head() || empty_parent_ref) {
+          if (pToConvert->tail()) {
+            pToConvert->tail()->has_line_feed(pToConvert->has_line_feed());
+          }
+        }
         has_lf = false;
       }
 
@@ -216,14 +213,14 @@
         // pToConvert->tail()->has_line_feed(pToConvert->has_line_feed());
       }
 
-      pToConvert = &pToConvert->tail();
+      pToConvert = pToConvert->tail();
     }
 
     return node;
   }
 
 
-  Complex_Selector_Ptr nodeToComplexSelector(const Node& toConvert, Context& ctx) {
+  Complex_Selector_Ptr nodeToComplexSelector(const Node& toConvert) {
     if (toConvert.isNil()) {
       return NULL;
     }
@@ -237,7 +234,6 @@
     NodeDeque& childNodes = *toConvert.collection();
 
     std::string noPath("");
-    Position noPosition(-1, -1, -1);
     Complex_Selector_Obj pFirst = SASS_MEMORY_NEW(Complex_Selector, ParserState("[NODE]"), Complex_Selector::ANCESTOR_OF, NULL, NULL);
 
     Complex_Selector_Obj pCurrent = pFirst;
@@ -254,7 +250,7 @@
         // collections, and can result in an infinite loop during the call to parentSuperselector()
         pCurrent->tail(SASS_MEMORY_COPY(child.selector()));
         // if (child.got_line_feed) pCurrent->has_line_feed(child.got_line_feed);
-        pCurrent = &pCurrent->tail();
+        pCurrent = pCurrent->tail();
       } else if (child.isCombinator()) {
         pCurrent->combinator(child.combinator());
         if (child.got_line_feed) pCurrent->has_line_feed(child.got_line_feed);
@@ -265,7 +261,7 @@
           if (nextNode.isCombinator()) {
             pCurrent->tail(SASS_MEMORY_NEW(Complex_Selector, ParserState("[NODE]"), Complex_Selector::ANCESTOR_OF, NULL, NULL));
             if (nextNode.got_line_feed) pCurrent->tail()->has_line_feed(nextNode.got_line_feed);
-            pCurrent = &pCurrent->tail();
+            pCurrent = pCurrent->tail();
           }
         }
       } else {
@@ -285,7 +281,7 @@
 
   // A very naive trim function, which removes duplicates in a node
   // This is only used in Complex_Selector::unify_with for now, may need modifications to fit other needs
-  Node Node::naiveTrim(Node& seqses, Context& ctx) {
+  Node Node::naiveTrim(Node& seqses) {
 
     std::vector<Node*> res;
     std::vector<Complex_Selector_Obj> known;
diff --git a/libsass/src/node.hpp b/libsass/src/node.hpp
--- a/libsass/src/node.hpp
+++ b/libsass/src/node.hpp
@@ -61,15 +61,15 @@
     static Node createCombinator(const Complex_Selector::Combinator& combinator);
 
     // This method will klone the selector, stripping off the tail and combinator
-    static Node createSelector(Complex_Selector_Ptr pSelector, Context& ctx);
+    static Node createSelector(const Complex_Selector& pSelector);
 
     static Node createCollection();
     static Node createCollection(const NodeDeque& values);
 
     static Node createNil();
-    static Node naiveTrim(Node& seqses, Context& ctx);
+    static Node naiveTrim(Node& seqses);
 
-    Node klone(Context& ctx) const;
+    Node klone() const;
 
     bool operator==(const Node& rhs) const;
     inline bool operator!=(const Node& rhs) const { return !(*this == rhs); }
@@ -91,7 +91,7 @@
     // potentialChild must be a node collection of selectors/combinators. this must be a collection
     // of collections of nodes/combinators. This method checks if potentialChild is a child of this
     // Node.
-    bool contains(const Node& potentialChild, bool simpleSelectorOrderDependent) const;
+    bool contains(const Node& potentialChild) const;
 
   private:
     // Private constructor; Use the static methods (like createCombinator and createSelector)
@@ -110,10 +110,8 @@
 #ifdef DEBUG
   std::ostream& operator<<(std::ostream& os, const Node& node);
 #endif
-  Node complexSelectorToNode(Complex_Selector_Ptr pToConvert, Context& ctx);
-  Complex_Selector_Ptr nodeToComplexSelector(const Node& toConvert, Context& ctx);
-
-  bool nodesEqual(const Node& one, const Node& two, bool simpleSelectorOrderDependent);
+  Node complexSelectorToNode(Complex_Selector_Ptr pToConvert);
+  Complex_Selector_Ptr nodeToComplexSelector(const Node& toConvert);
 
 }
 
diff --git a/libsass/src/operation.hpp b/libsass/src/operation.hpp
--- a/libsass/src/operation.hpp
+++ b/libsass/src/operation.hpp
@@ -40,6 +40,7 @@
     // expressions
     virtual T operator()(List_Ptr x)                   = 0;
     virtual T operator()(Map_Ptr x)                    = 0;
+    virtual T operator()(Function_Ptr x)               = 0;
     virtual T operator()(Binary_Expression_Ptr x)      = 0;
     virtual T operator()(Unary_Expression_Ptr x)       = 0;
     virtual T operator()(Function_Call_Ptr x)          = 0;
@@ -47,7 +48,6 @@
     virtual T operator()(Custom_Warning_Ptr x)         = 0;
     virtual T operator()(Custom_Error_Ptr x)           = 0;
     virtual T operator()(Variable_Ptr x)               = 0;
-    virtual T operator()(Textual_Ptr x)                = 0;
     virtual T operator()(Number_Ptr x)                 = 0;
     virtual T operator()(Color_Ptr x)                  = 0;
     virtual T operator()(Boolean_Ptr x)                = 0;
@@ -122,6 +122,7 @@
     // expressions
     T operator()(List_Ptr x)                   { return static_cast<D*>(this)->fallback(x); }
     T operator()(Map_Ptr x)                    { return static_cast<D*>(this)->fallback(x); }
+    T operator()(Function_Ptr x)               { return static_cast<D*>(this)->fallback(x); }
     T operator()(Binary_Expression_Ptr x)      { return static_cast<D*>(this)->fallback(x); }
     T operator()(Unary_Expression_Ptr x)       { return static_cast<D*>(this)->fallback(x); }
     T operator()(Function_Call_Ptr x)          { return static_cast<D*>(this)->fallback(x); }
@@ -129,7 +130,6 @@
     T operator()(Custom_Warning_Ptr x)         { return static_cast<D*>(this)->fallback(x); }
     T operator()(Custom_Error_Ptr x)           { return static_cast<D*>(this)->fallback(x); }
     T operator()(Variable_Ptr x)               { return static_cast<D*>(this)->fallback(x); }
-    T operator()(Textual_Ptr x)                { return static_cast<D*>(this)->fallback(x); }
     T operator()(Number_Ptr x)                 { return static_cast<D*>(this)->fallback(x); }
     T operator()(Color_Ptr x)                  { return static_cast<D*>(this)->fallback(x); }
     T operator()(Boolean_Ptr x)                { return static_cast<D*>(this)->fallback(x); }
diff --git a/libsass/src/operators.cpp b/libsass/src/operators.cpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/operators.cpp
@@ -0,0 +1,240 @@
+#include "sass.hpp"
+#include "operators.hpp"
+
+namespace Sass {
+
+  namespace Operators {
+
+    inline double add(double x, double y) { return x + y; }
+    inline double sub(double x, double y) { return x - y; }
+    inline double mul(double x, double y) { return x * y; }
+    inline double div(double x, double y) { return x / y; } // x/0 checked by caller
+
+    inline double mod(double x, double y) { // x/0 checked by caller
+      if ((x > 0 && y < 0) || (x < 0 && y > 0)) {
+        double ret = std::fmod(x, y);
+        return ret ? ret + y : ret;
+      } else {
+        return std::fmod(x, y);
+      }
+    }
+
+    typedef double (*bop)(double, double);
+    bop ops[Sass_OP::NUM_OPS] = {
+      0, 0, // and, or
+      0, 0, 0, 0, 0, 0, // eq, neq, gt, gte, lt, lte
+      add, sub, mul, div, mod
+    };
+
+    /* static function, has no pstate or traces */
+    bool eq(Expression_Obj lhs, Expression_Obj rhs)
+    {
+      // operation is undefined if one is not a number
+      if (!lhs || !rhs) throw Exception::UndefinedOperation(lhs, rhs, Sass_OP::EQ);
+      // use compare operator from ast node
+      return *lhs == *rhs;
+    }
+
+    /* static function, throws OperationError, has no pstate or traces */
+    bool cmp(Expression_Obj lhs, Expression_Obj rhs, const Sass_OP op)
+    {
+      // can only compare numbers!?
+      Number_Obj l = Cast<Number>(lhs);
+      Number_Obj r = Cast<Number>(rhs);
+      // operation is undefined if one is not a number
+      if (!l || !r) throw Exception::UndefinedOperation(lhs, rhs, op);
+      // use compare operator from ast node
+      return *l < *r;
+    }
+
+    /* static functions, throws OperationError, has no pstate or traces */
+    bool lt(Expression_Obj lhs, Expression_Obj rhs) { return cmp(lhs, rhs, Sass_OP::LT); }
+    bool neq(Expression_Obj lhs, Expression_Obj rhs) { return eq(lhs, rhs) == false; }
+    bool gt(Expression_Obj lhs, Expression_Obj rhs) { return !cmp(lhs, rhs, Sass_OP::GT) && neq(lhs, rhs); }
+    bool lte(Expression_Obj lhs, Expression_Obj rhs) { return cmp(lhs, rhs, Sass_OP::LTE) || eq(lhs, rhs); }
+    bool gte(Expression_Obj lhs, Expression_Obj rhs) { return !cmp(lhs, rhs, Sass_OP::GTE) || eq(lhs, rhs); }
+
+    /* static function, throws OperationError, has no traces but optional pstate for returned value */
+    Value_Ptr op_strings(Sass::Operand operand, Value& lhs, Value& rhs, struct Sass_Inspect_Options opt, const ParserState& pstate, bool delayed)
+    {
+      enum Sass_OP op = operand.operand;
+
+      String_Quoted_Ptr lqstr = Cast<String_Quoted>(&lhs);
+      String_Quoted_Ptr rqstr = Cast<String_Quoted>(&rhs);
+
+      std::string lstr(lqstr ? lqstr->value() : lhs.to_string(opt));
+      std::string rstr(rqstr ? rqstr->value() : rhs.to_string(opt));
+
+      if (Cast<Null>(&lhs)) throw Exception::InvalidNullOperation(&lhs, &rhs, op);
+      if (Cast<Null>(&rhs)) throw Exception::InvalidNullOperation(&lhs, &rhs, op);
+
+      std::string sep;
+      switch (op) {
+        case Sass_OP::ADD: sep = "";   break;
+        case Sass_OP::SUB: sep = "-";  break;
+        case Sass_OP::DIV: sep = "/";  break;
+        case Sass_OP::EQ:  sep = "=="; break;
+        case Sass_OP::NEQ: sep = "!="; break;
+        case Sass_OP::LT:  sep = "<";  break;
+        case Sass_OP::GT:  sep = ">";  break;
+        case Sass_OP::LTE: sep = "<="; break;
+        case Sass_OP::GTE: sep = ">="; break;
+        default:
+          throw Exception::UndefinedOperation(&lhs, &rhs, op);
+        break;
+      }
+
+      if (op == Sass_OP::ADD) {
+        // create string that might be quoted on output (but do not unquote what we pass)
+        return SASS_MEMORY_NEW(String_Quoted, pstate, lstr + rstr, 0, false, true);
+      }
+
+      // add whitespace around operator
+      // but only if result is not delayed
+      if (sep != "" && delayed == false) {
+        if (operand.ws_before) sep = " " + sep;
+        if (operand.ws_after) sep = sep + " ";
+      }
+
+      if (op == Sass_OP::SUB || op == Sass_OP::DIV) {
+        if (lqstr && lqstr->quote_mark()) lstr = quote(lstr);
+        if (rqstr && rqstr->quote_mark()) rstr = quote(rstr);
+      }
+
+      return SASS_MEMORY_NEW(String_Constant, pstate, lstr + sep + rstr);
+    }
+
+    /* static function, throws OperationError, has no traces but optional pstate for returned value */
+    Value_Ptr op_colors(enum Sass_OP op, const Color& lhs, const Color& rhs, struct Sass_Inspect_Options opt, const ParserState& pstate, bool delayed)
+    {
+      if (lhs.a() != rhs.a()) {
+        throw Exception::AlphaChannelsNotEqual(&lhs, &rhs, op);
+      }
+      if (op == Sass_OP::DIV && (!rhs.r() || !rhs.g() || !rhs.b())) {
+        throw Exception::ZeroDivisionError(lhs, rhs);
+      }
+      return SASS_MEMORY_NEW(Color,
+                             pstate,
+                             ops[op](lhs.r(), rhs.r()),
+                             ops[op](lhs.g(), rhs.g()),
+                             ops[op](lhs.b(), rhs.b()),
+                             lhs.a());
+    }
+
+    /* static function, throws OperationError, has no traces but optional pstate for returned value */
+    Value_Ptr op_numbers(enum Sass_OP op, const Number& lhs, const Number& rhs, struct Sass_Inspect_Options opt, const ParserState& pstate, bool delayed)
+    {
+      double lval = lhs.value();
+      double rval = rhs.value();
+
+      if (op == Sass_OP::DIV && rval == 0) {
+        std::string result(lval ? "Infinity" : "NaN");
+        return SASS_MEMORY_NEW(String_Quoted, pstate, result);
+      }
+
+      if (op == Sass_OP::MOD && rval == 0) {
+        throw Exception::ZeroDivisionError(lhs, rhs);
+      }
+
+      size_t l_n_units = lhs.numerators.size();
+      size_t l_d_units = lhs.numerators.size();
+      size_t r_n_units = rhs.denominators.size();
+      size_t r_d_units = rhs.denominators.size();
+      // optimize out the most common and simplest case
+      if (l_n_units == r_n_units && l_d_units == r_d_units) {
+        if (l_n_units + l_d_units <= 1 && r_n_units + r_d_units <= 1) {
+          if (lhs.numerators == rhs.numerators) {
+            if (lhs.denominators == rhs.denominators) {
+              Number_Ptr v = SASS_MEMORY_COPY(&lhs);
+              v->value(ops[op](lval, rval));
+              return v;
+            }
+          }
+        }
+      }
+
+      Number_Obj v = SASS_MEMORY_COPY(&lhs);
+
+      if (lhs.is_unitless() && (op == Sass_OP::ADD || op == Sass_OP::SUB || op == Sass_OP::MOD)) {
+        v->numerators = rhs.numerators;
+        v->denominators = rhs.denominators;
+      }
+
+      if (op == Sass_OP::MUL) {
+        v->value(ops[op](lval, rval));
+        v->numerators.insert(v->numerators.end(),
+          rhs.numerators.begin(), rhs.numerators.end()
+        );
+        v->denominators.insert(v->denominators.end(),
+          rhs.denominators.begin(), rhs.denominators.end()
+        );
+        v->reduce();
+      }
+      else if (op == Sass_OP::DIV) {
+        v->value(ops[op](lval, rval));
+        v->numerators.insert(v->numerators.end(),
+          rhs.denominators.begin(), rhs.denominators.end()
+        );
+        v->denominators.insert(v->denominators.end(),
+          rhs.numerators.begin(), rhs.numerators.end()
+        );
+        v->reduce();
+      }
+      else {
+        Number ln(lhs), rn(rhs);
+        ln.reduce(); rn.reduce();
+        double f(rn.convert_factor(ln));
+        v->value(ops[op](lval, rn.value() * f));
+      }
+
+      v->pstate(pstate);
+      return v.detach();
+    }
+
+    /* static function, throws OperationError, has no traces but optional pstate for returned value */
+    Value_Ptr op_number_color(enum Sass_OP op, const Number& lhs, const Color& rhs, struct Sass_Inspect_Options opt, const ParserState& pstate, bool delayed)
+    {
+      double lval = lhs.value();
+      switch (op) {
+        case Sass_OP::ADD:
+        case Sass_OP::MUL: {
+          return SASS_MEMORY_NEW(Color,
+                                pstate,
+                                ops[op](lval, rhs.r()),
+                                ops[op](lval, rhs.g()),
+                                ops[op](lval, rhs.b()),
+                                rhs.a());
+        }
+        case Sass_OP::SUB:
+        case Sass_OP::DIV: {
+          std::string color(rhs.to_string(opt));
+          return SASS_MEMORY_NEW(String_Quoted,
+                                pstate,
+                                lhs.to_string(opt)
+                                + sass_op_separator(op)
+                                + color);
+        }
+        default: break;
+      }
+      throw Exception::UndefinedOperation(&lhs, &rhs, op);
+    }
+
+    /* static function, throws OperationError, has no traces but optional pstate for returned value */
+    Value_Ptr op_color_number(enum Sass_OP op, const Color& lhs, const Number& rhs, struct Sass_Inspect_Options opt, const ParserState& pstate, bool delayed)
+    {
+      double rval = rhs.value();
+      if (op == Sass_OP::DIV && rval == 0) {
+        // comparison of Fixnum with Float failed?
+        throw Exception::ZeroDivisionError(lhs, rhs);
+      }
+      return SASS_MEMORY_NEW(Color,
+                            pstate,
+                            ops[op](lhs.r(), rval),
+                            ops[op](lhs.g(), rval),
+                            ops[op](lhs.b(), rval),
+                            lhs.a());
+    }
+
+  }
+
+}
diff --git a/libsass/src/operators.hpp b/libsass/src/operators.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/operators.hpp
@@ -0,0 +1,30 @@
+#ifndef SASS_OPERATORS_H
+#define SASS_OPERATORS_H
+
+#include "values.hpp"
+#include "sass/values.h"
+
+namespace Sass {
+
+  namespace Operators {
+
+    // equality operator using AST Node operator==
+    bool eq(Expression_Obj, Expression_Obj);
+    bool neq(Expression_Obj, Expression_Obj);
+    // specific operators based on cmp and eq
+    bool lt(Expression_Obj, Expression_Obj);
+    bool gt(Expression_Obj, Expression_Obj);
+    bool lte(Expression_Obj, Expression_Obj);
+    bool gte(Expression_Obj, Expression_Obj);
+    // arithmetic for all the combinations that matter
+    Value_Ptr op_strings(Sass::Operand, Value&, Value&, struct Sass_Inspect_Options opt, const ParserState& pstate, bool delayed = false);
+    Value_Ptr op_colors(enum Sass_OP, const Color&, const Color&, struct Sass_Inspect_Options opt, const ParserState& pstate, bool delayed = false);
+    Value_Ptr op_numbers(enum Sass_OP, const Number&, const Number&, struct Sass_Inspect_Options opt, const ParserState& pstate, bool delayed = false);
+    Value_Ptr op_number_color(enum Sass_OP, const Number&, const Color&, struct Sass_Inspect_Options opt, const ParserState& pstate, bool delayed = false);
+    Value_Ptr op_color_number(enum Sass_OP, const Color&, const Number&, struct Sass_Inspect_Options opt, const ParserState& pstate, bool delayed = false);
+
+  };
+
+}
+
+#endif
diff --git a/libsass/src/output.cpp b/libsass/src/output.cpp
--- a/libsass/src/output.cpp
+++ b/libsass/src/output.cpp
@@ -19,13 +19,14 @@
 
   void Output::operator()(Number_Ptr n)
   {
-    // use values to_string facility
-    std::string res = n->to_string(opt);
     // check for a valid unit here
     // includes result for reporting
     if (!n->is_valid_css_unit()) {
-      throw Exception::InvalidValue(*n);
+      // should be handle in check_expression
+      throw Exception::InvalidValue({}, *n);
     }
+    // use values to_string facility
+    std::string res = n->to_string(opt);
     // output the final token
     append_token(res, n);
   }
@@ -37,8 +38,8 @@
 
   void Output::operator()(Map_Ptr m)
   {
-    std::string dbg(m->to_string(opt));
-    error(dbg + " isn't a valid CSS value.", m->pstate());
+    // should be handle in check_expression
+    throw Exception::InvalidValue({}, *m);
   }
 
   OutputBuffer Output::get_buffer(void)
@@ -116,8 +117,8 @@
     if (!Util::isPrintable(r, output_style())) {
       for (size_t i = 0, L = b->length(); i < L; ++i) {
         const Statement_Obj& stm = b->at(i);
-        if (dynamic_cast<Has_Block_Ptr>(&stm)) {
-          if (!dynamic_cast<Declaration_Ptr>(&stm)) {
+        if (Cast<Has_Block>(stm)) {
+          if (!Cast<Declaration>(stm)) {
             stm->perform(this);
           }
         }
@@ -134,28 +135,29 @@
       append_string(ss.str());
       append_optional_linefeed();
     }
+    scheduled_crutch = s;
     if (s) s->perform(this);
-    append_scope_opener(&b);
+    append_scope_opener(b);
     for (size_t i = 0, L = b->length(); i < L; ++i) {
       Statement_Obj stm = b->at(i);
       bool bPrintExpression = true;
       // Check print conditions
-      if (Declaration_Ptr dec = SASS_MEMORY_CAST(Declaration, stm)) {
-        if (String_Constant_Ptr valConst = SASS_MEMORY_CAST(String_Constant, dec->value())) {
+      if (Declaration_Ptr dec = Cast<Declaration>(stm)) {
+        if (String_Constant_Ptr valConst = Cast<String_Constant>(dec->value())) {
           std::string val(valConst->value());
-          if (String_Quoted_Ptr qstr = SASS_MEMORY_CAST_PTR(String_Quoted, valConst)) {
+          if (String_Quoted_Ptr qstr = Cast<String_Quoted>(valConst)) {
             if (!qstr->quote_mark() && val.empty()) {
               bPrintExpression = false;
             }
           }
         }
-        else if (List_Ptr list = SASS_MEMORY_CAST(List, dec->value())) {
+        else if (List_Ptr list = Cast<List>(dec->value())) {
           bool all_invisible = true;
           for (size_t list_i = 0, list_L = list->length(); list_i < list_L; ++list_i) {
-            Expression_Ptr item = &list->at(list_i);
+            Expression_Ptr item = list->at(list_i);
             if (!item->is_invisible()) all_invisible = false;
           }
-          if (all_invisible) bPrintExpression = false;
+          if (all_invisible && !list->is_bracketed()) bPrintExpression = false;
         }
       }
       // Print if OK
@@ -164,7 +166,7 @@
       }
     }
     if (output_style() == NESTED) indentation -= r->tabs();
-    append_scope_closer(&b);
+    append_scope_closer(b);
 
   }
   void Output::operator()(Keyframe_Rule_Ptr r)
@@ -172,7 +174,7 @@
     Block_Obj b = r->block();
     Selector_Obj v = r->name();
 
-    if (&v) {
+    if (!v.isNull()) {
       v->perform(this);
     }
 
@@ -201,7 +203,7 @@
     if (!Util::isPrintable(f, output_style())) {
       for (size_t i = 0, L = b->length(); i < L; ++i) {
         Statement_Obj stm = b->at(i);
-        if (dynamic_cast<Has_Block_Ptr>(&stm)) {
+        if (Cast<Has_Block>(stm)) {
           stm->perform(this);
         }
       }
@@ -237,7 +239,7 @@
     if (!Util::isPrintable(m, output_style())) {
       for (size_t i = 0, L = b->length(); i < L; ++i) {
         Statement_Obj stm = b->at(i);
-        if (dynamic_cast<Has_Block_Ptr>(&stm)) {
+        if (Cast<Has_Block>(stm)) {
           stm->perform(this);
         }
       }
@@ -282,7 +284,7 @@
     if (v) {
       append_mandatory_space();
       // ruby sass bug? should use options?
-      append_token(v->to_string(/* opt */), &v);
+      append_token(v->to_string(/* opt */), v);
     }
     if (!b) {
       append_delimiter();
@@ -324,7 +326,7 @@
     if (s->can_compress_whitespace() && output_style() == COMPRESSED) {
       value.erase(std::remove_if(value.begin(), value.end(), ::isspace), value.end());
     }
-    if (!in_comment) {
+    if (!in_comment && !in_custom_property) {
       append_token(string_to_output(value), s);
     } else {
       append_token(value, s);
diff --git a/libsass/src/parser.cpp b/libsass/src/parser.cpp
--- a/libsass/src/parser.cpp
+++ b/libsass/src/parser.cpp
@@ -1,2776 +1,3121 @@
 #include "sass.hpp"
-#include <cstdlib>
-#include <iostream>
-#include <vector>
-#include "parser.hpp"
-#include "file.hpp"
-#include "inspect.hpp"
-#include "constants.hpp"
-#include "util.hpp"
-#include "prelexer.hpp"
-#include "color_maps.hpp"
-#include "sass/functions.h"
-#include "error_handling.hpp"
-
-// Notes about delayed: some ast nodes can have delayed evaluation so
-// they can preserve their original semantics if needed. This is most
-// prominently exhibited by the division operation, since it is not
-// only a valid operation, but also a valid css statement (i.e. for
-// fonts, as in `16px/24px`). When parsing lists and expression we
-// unwrap single items from lists and other operations. A nested list
-// must not be delayed, only the items of the first level sometimes
-// are delayed (as with argument lists). To achieve this we need to
-// pass status to the list parser, so this can be set correctly.
-// Another case with delayed values are colors. In compressed mode
-// only processed values get compressed (other are left as written).
-
-#include <typeinfo>
-#include <tuple>
-
-namespace Sass {
-  using namespace Constants;
-  using namespace Prelexer;
-
-  Parser Parser::from_c_str(const char* beg, Context& ctx, ParserState pstate, const char* source)
-  {
-    pstate.offset.column = 0;
-    pstate.offset.line = 0;
-    Parser p(ctx, pstate);
-    p.source   = source ? source : beg;
-    p.position = beg ? beg : p.source;
-    p.end      = p.position + strlen(p.position);
-    Block_Obj root = SASS_MEMORY_NEW(Block, pstate);
-    p.block_stack.push_back(root);
-    root->is_root(true);
-    return p;
-  }
-
-  Parser Parser::from_c_str(const char* beg, const char* end, Context& ctx, ParserState pstate, const char* source)
-  {
-    pstate.offset.column = 0;
-    pstate.offset.line = 0;
-    Parser p(ctx, pstate);
-    p.source   = source ? source : beg;
-    p.position = beg ? beg : p.source;
-    p.end      = end ? end : p.position + strlen(p.position);
-    Block_Obj root = SASS_MEMORY_NEW(Block, pstate);
-    p.block_stack.push_back(root);
-    root->is_root(true);
-    return p;
-  }
-
-   void Parser::advanceToNextToken() {
-      lex < css_comments >(false);
-      // advance to position
-      pstate += pstate.offset;
-      pstate.offset.column = 0;
-      pstate.offset.line = 0;
-    }
-
-  Selector_List_Obj Parser::parse_selector(const char* beg, Context& ctx, ParserState pstate, const char* source)
-  {
-    Parser p = Parser::from_c_str(beg, ctx, pstate, source);
-    // ToDo: ruby sass errors on parent references
-    // ToDo: remap the source-map entries somehow
-    return p.parse_selector_list(false);
-  }
-
-  bool Parser::peek_newline(const char* start)
-  {
-    return peek_linefeed(start ? start : position)
-           && ! peek_css<exactly<'{'>>(start);
-  }
-
-  Parser Parser::from_token(Token t, Context& ctx, ParserState pstate, const char* source)
-  {
-    Parser p(ctx, pstate);
-    p.source   = source ? source : t.begin;
-    p.position = t.begin ? t.begin : p.source;
-    p.end      = t.end ? t.end : p.position + strlen(p.position);
-    Block_Obj root = SASS_MEMORY_NEW(Block, pstate);
-    p.block_stack.push_back(root);
-    root->is_root(true);
-    return p;
-  }
-
-  /* main entry point to parse root block */
-  Block_Obj Parser::parse()
-  {
-    bool is_root = false;
-    Block_Obj root = SASS_MEMORY_NEW(Block, pstate, 0, true);
-    read_bom();
-
-    // custom headers
-    if (ctx.resources.size() == 1) {
-    is_root = true;
-      ctx.apply_custom_headers(&root, path, pstate);
-    }
-
-    block_stack.push_back(root);
-    /* bool rv = */ parse_block_nodes(is_root);
-    block_stack.pop_back();
-
-    // update for end position
-    root->update_pstate(pstate);
-
-    if (position != end) {
-      css_error("Invalid CSS", " after ", ": expected selector or at-rule, was ");
-    }
-
-    return root;
-  }
-
-
-  // convenience function for block parsing
-  // will create a new block ad-hoc for you
-  // this is the base block parsing function
-  Block_Obj Parser::parse_css_block(bool is_root)
-  {
-
-    // parse comments before block
-    // lex < optional_css_comments >();
-
-    // lex mandatory opener or error out
-    if (!lex_css < exactly<'{'> >()) {
-      css_error("Invalid CSS", " after ", ": expected \"{\", was ");
-    }
-    // create new block and push to the selector stack
-    Block_Obj block = SASS_MEMORY_NEW(Block, pstate, 0, is_root);
-    block_stack.push_back(block);
-
-    if (!parse_block_nodes()) css_error("Invalid CSS", " after ", ": expected \"}\", was ");
-
-    if (!lex_css < exactly<'}'> >()) {
-      css_error("Invalid CSS", " after ", ": expected \"}\", was ");
-    }
-
-    // update for end position
-    // this seems to be done somewhere else
-    // but that fixed selector schema issue
-    // block->update_pstate(pstate);
-
-    // parse comments after block
-    // lex < optional_css_comments >();
-
-    block_stack.pop_back();
-
-    return &block;
-  }
-
-  // convenience function for block parsing
-  // will create a new block ad-hoc for you
-  // also updates the `in_at_root` flag
-  Block_Obj Parser::parse_block(bool is_root)
-  {
-    LOCAL_FLAG(in_at_root, is_root);
-    return parse_css_block(is_root);
-  }
-
-  // the main block parsing function
-  // parses stuff between `{` and `}`
-  bool Parser::parse_block_nodes(bool is_root)
-  {
-
-    // loop until end of string
-    while (position < end) {
-
-      // we should be able to refactor this
-      parse_block_comments();
-      lex < css_whitespace >();
-
-      if (lex < exactly<';'> >()) continue;
-      if (peek < end_of_file >()) return true;
-      if (peek < exactly<'}'> >()) return true;
-
-      if (parse_block_node(is_root)) continue;
-
-      parse_block_comments();
-
-      if (lex_css < exactly<';'> >()) continue;
-      if (peek_css < end_of_file >()) return true;
-      if (peek_css < exactly<'}'> >()) return true;
-
-      // illegal sass
-      return false;
-    }
-    // return success
-    return true;
-  }
-
-  // parser for a single node in a block
-  // semicolons must be lexed beforehand
-  bool Parser::parse_block_node(bool is_root) {
-
-    Block_Obj block = block_stack.back();
-
-    parse_block_comments();
-
-    // throw away white-space
-    // includes line comments
-    lex < css_whitespace >();
-
-    Lookahead lookahead_result;
-
-    // also parse block comments
-
-    // first parse everything that is allowed in functions
-    if (lex < variable >(true)) { block->append(&parse_assignment()); }
-    else if (lex < kwd_err >(true)) { block->append(&parse_error()); }
-    else if (lex < kwd_dbg >(true)) { block->append(&parse_debug()); }
-    else if (lex < kwd_warn >(true)) { block->append(&parse_warning()); }
-    else if (lex < kwd_if_directive >(true)) { block->append(&parse_if_directive()); }
-    else if (lex < kwd_for_directive >(true)) { block->append(&parse_for_directive()); }
-    else if (lex < kwd_each_directive >(true)) { block->append(&parse_each_directive()); }
-    else if (lex < kwd_while_directive >(true)) { block->append(&parse_while_directive()); }
-    else if (lex < kwd_return_directive >(true)) { block->append(&parse_return_directive()); }
-
-    // parse imports to process later
-    else if (lex < kwd_import >(true)) {
-      Scope parent = stack.empty() ? Scope::Rules : stack.back();
-      if (parent != Scope::Function && parent != Scope::Root && parent != Scope::Rules && parent != Scope::Media) {
-        if (! peek_css< uri_prefix >(position)) { // this seems to go in ruby sass 3.4.20
-          error("Import directives may not be used within control directives or mixins.", pstate);
-        }
-      }
-      Import_Obj imp = parse_import();
-      // if it is a url, we only add the statement
-      if (!imp->urls().empty()) block->append(&imp);
-      // process all resources now (add Import_Stub nodes)
-      for (size_t i = 0, S = imp->incs().size(); i < S; ++i) {
-        block->append(SASS_MEMORY_NEW(Import_Stub, pstate, imp->incs()[i]));
-      }
-    }
-
-    else if (lex < kwd_extend >(true)) {
-      Lookahead lookahead = lookahead_for_include(position);
-      if (!lookahead.found) css_error("Invalid CSS", " after ", ": expected selector, was ");
-      Selector_Obj target;
-      if (lookahead.has_interpolants) target = &parse_selector_schema(lookahead.found);
-      else                            target = &parse_selector_list(true);
-      block->append(SASS_MEMORY_NEW(Extension, pstate, &target));
-    }
-
-    // selector may contain interpolations which need delayed evaluation
-    else if (!(lookahead_result = lookahead_for_selector(position)).error)
-    { block->append(&parse_ruleset(lookahead_result, is_root)); }
-
-    // parse multiple specific keyword directives
-    else if (lex < kwd_media >(true)) { block->append(&parse_media_block()); }
-    else if (lex < kwd_at_root >(true)) { block->append(&parse_at_root_block()); }
-    else if (lex < kwd_include_directive >(true)) { block->append(&parse_include_directive()); }
-    else if (lex < kwd_content_directive >(true)) { block->append(&parse_content_directive()); }
-    else if (lex < kwd_supports_directive >(true)) { block->append(&parse_supports_directive()); }
-    else if (lex < kwd_mixin >(true)) { block->append(&parse_definition(Definition::MIXIN)); }
-    else if (lex < kwd_function >(true)) { block->append(&parse_definition(Definition::FUNCTION)); }
-
-    // ignore the @charset directive for now
-    else if (lex< kwd_charset_directive >(true)) { parse_charset_directive(); }
-
-    // generic at keyword (keep last)
-    else if (lex< re_special_directive >(true)) { block->append(&parse_special_directive()); }
-    else if (lex< re_prefixed_directive >(true)) { block->append(&parse_prefixed_directive()); }
-    else if (lex< at_keyword >(true)) { block->append(&parse_directive()); }
-
-    else if (is_root /* && block->is_root() */) {
-      lex< css_whitespace >();
-      if (position >= end) return true;
-      css_error("Invalid CSS", " after ", ": expected 1 selector or at-rule, was ");
-    }
-    // parse a declaration
-    else
-    {
-      // ToDo: how does it handle parse errors?
-      // maybe we are expected to parse something?
-      Declaration_Obj decl = parse_declaration();
-      decl->tabs(indentation);
-      block->append(&decl);
-      // maybe we have a "sub-block"
-      if (peek< exactly<'{'> >()) {
-        if (decl->is_indented()) ++ indentation;
-        // parse a propset that rides on the declaration's property
-        stack.push_back(Scope::Properties);
-        decl->block(parse_block());
-        stack.pop_back();
-        if (decl->is_indented()) -- indentation;
-      }
-    }
-    // something matched
-    return true;
-  }
-  // EO parse_block_nodes
-
-  // parse imports inside the
-  Import_Obj Parser::parse_import()
-  {
-    Import_Obj imp = SASS_MEMORY_NEW(Import, pstate);
-    std::vector<std::pair<std::string,Function_Call_Obj>> to_import;
-    bool first = true;
-    do {
-      while (lex< block_comment >());
-      if (lex< quoted_string >()) {
-        to_import.push_back(std::pair<std::string,Function_Call_Obj>(std::string(lexed), 0));
-      }
-      else if (lex< uri_prefix >()) {
-        Arguments_Obj args = SASS_MEMORY_NEW(Arguments, pstate);
-        Function_Call_Obj result = SASS_MEMORY_NEW(Function_Call, pstate, "url", &args);
-
-        if (lex< quoted_string >()) {
-          Expression_Obj the_url = &parse_string();
-          args->append(SASS_MEMORY_NEW(Argument, the_url->pstate(), &the_url));
-        }
-        else if (String_Obj the_url = parse_url_function_argument()) {
-          args->append(SASS_MEMORY_NEW(Argument, the_url->pstate(), &the_url));
-        }
-        else if (peek < skip_over_scopes < exactly < '(' >, exactly < ')' > > >(position)) {
-          Expression_Obj the_url = parse_list(); // parse_interpolated_chunk(lexed);
-          args->append(SASS_MEMORY_NEW(Argument, the_url->pstate(), &the_url));
-        }
-        else {
-          error("malformed URL", pstate);
-        }
-        if (!lex< exactly<')'> >()) error("URI is missing ')'", pstate);
-        to_import.push_back(std::pair<std::string, Function_Call_Obj>("", &result));
-      }
-      else {
-        if (first) error("@import directive requires a url or quoted path", pstate);
-        else error("expecting another url or quoted path in @import list", pstate);
-      }
-      first = false;
-    } while (lex_css< exactly<','> >());
-
-    if (!peek_css< alternatives< exactly<';'>, exactly<'}'>, end_of_file > >()) {
-      List_Obj import_queries = parse_media_queries();
-      imp->import_queries(import_queries);
-    }
-
-    for(auto location : to_import) {
-      if (location.second) {
-        imp->urls().push_back(&location.second);
-      } else if (!ctx.call_importers(unquote(location.first), path, pstate, &imp)) {
-        ctx.import_url(&imp, location.first, path);
-      }
-    }
-
-    return imp;
-  }
-
-  Definition_Obj Parser::parse_definition(Definition::Type which_type)
-  {
-    std::string which_str(lexed);
-    if (!lex< identifier >()) error("invalid name in " + which_str + " definition", pstate);
-    std::string name(Util::normalize_underscores(lexed));
-    if (which_type == Definition::FUNCTION && (name == "and" || name == "or" || name == "not"))
-    { error("Invalid function name \"" + name + "\".", pstate); }
-    ParserState source_position_of_def = pstate;
-    Parameters_Obj params = parse_parameters();
-    if (which_type == Definition::MIXIN) stack.push_back(Scope::Mixin);
-    else stack.push_back(Scope::Function);
-    Block_Obj body = parse_block();
-    stack.pop_back();
-    return SASS_MEMORY_NEW(Definition, source_position_of_def, name, &params, &body, which_type);
-  }
-
-  Parameters_Obj Parser::parse_parameters()
-  {
-    std::string name(lexed);
-    Position position = after_token;
-    Parameters_Obj params = SASS_MEMORY_NEW(Parameters, pstate);
-    if (lex_css< exactly<'('> >()) {
-      // if there's anything there at all
-      if (!peek_css< exactly<')'> >()) {
-        do params->append(&parse_parameter());
-        while (lex_css< exactly<','> >());
-      }
-      if (!lex_css< exactly<')'> >()) error("expected a variable name (e.g. $x) or ')' for the parameter list for " + name, position);
-    }
-    return params;
-  }
-
-  Parameter_Obj Parser::parse_parameter()
-  {
-    while (lex< alternatives < spaces, block_comment > >());
-    lex < variable >();
-    std::string name(Util::normalize_underscores(lexed));
-    ParserState pos = pstate;
-    Expression_Obj val;
-    bool is_rest = false;
-    while (lex< alternatives < spaces, block_comment > >());
-    if (lex< exactly<':'> >()) { // there's a default value
-      while (lex< block_comment >());
-      val = parse_space_list();
-    }
-    else if (lex< exactly< ellipsis > >()) {
-      is_rest = true;
-    }
-    return SASS_MEMORY_NEW(Parameter, pos, name, &val, is_rest);
-  }
-
-  Arguments_Obj Parser::parse_arguments()
-  {
-    std::string name(lexed);
-    Position position = after_token;
-    Arguments_Obj args = SASS_MEMORY_NEW(Arguments, pstate);
-    if (lex_css< exactly<'('> >()) {
-      // if there's anything there at all
-      if (!peek_css< exactly<')'> >()) {
-        do args->append(&parse_argument());
-        while (lex_css< exactly<','> >());
-      }
-      if (!lex_css< exactly<')'> >()) error("expected a variable name (e.g. $x) or ')' for the parameter list for " + name, position);
-    }
-    return args;
-  }
-
-  Argument_Obj Parser::parse_argument()
-  {
-    if (peek_css< sequence < exactly< hash_lbrace >, exactly< rbrace > > >()) {
-      position += 2;
-      css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
-    }
-
-    Argument_Obj arg;
-    if (peek_css< sequence < variable, optional_css_comments, exactly<':'> > >()) {
-      lex_css< variable >();
-      std::string name(Util::normalize_underscores(lexed));
-      ParserState p = pstate;
-      lex_css< exactly<':'> >();
-      Expression_Obj val = parse_space_list();
-      arg = SASS_MEMORY_NEW(Argument, p, val, name);
-    }
-    else {
-      bool is_arglist = false;
-      bool is_keyword = false;
-      Expression_Obj val = parse_space_list();
-      List_Ptr l = SASS_MEMORY_CAST(List, val);
-      if (lex_css< exactly< ellipsis > >()) {
-        if (val->concrete_type() == Expression::MAP || (
-           (l != NULL && l->separator() == SASS_HASH)
-        )) is_keyword = true;
-        else is_arglist = true;
-      }
-      arg = SASS_MEMORY_NEW(Argument, pstate, val, "", is_arglist, is_keyword);
-    }
-    return arg;
-  }
-
-  Assignment_Obj Parser::parse_assignment()
-  {
-    std::string name(Util::normalize_underscores(lexed));
-    ParserState var_source_position = pstate;
-    if (!lex< exactly<':'> >()) error("expected ':' after " + name + " in assignment statement", pstate);
-    if (peek_css< alternatives < exactly<';'>, end_of_file > >()) {
-      css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
-    }
-    Expression_Obj val;
-    Lookahead lookahead = lookahead_for_value(position);
-    if (lookahead.has_interpolants && lookahead.found) {
-      val = &parse_value_schema(lookahead.found);
-    } else {
-      val = parse_list();
-    }
-    bool is_default = false;
-    bool is_global = false;
-    while (peek< alternatives < default_flag, global_flag > >()) {
-      if (lex< default_flag >()) is_default = true;
-      else if (lex< global_flag >()) is_global = true;
-    }
-    return SASS_MEMORY_NEW(Assignment, var_source_position, name, val, is_default, is_global);
-  }
-
-  // a ruleset connects a selector and a block
-  Ruleset_Obj Parser::parse_ruleset(Lookahead lookahead, bool is_root)
-  {
-    // make sure to move up the the last position
-    lex < optional_css_whitespace >(false, true);
-    // create the connector object (add parts later)
-    Ruleset_Obj ruleset = SASS_MEMORY_NEW(Ruleset, pstate);
-    // parse selector static or as schema to be evaluated later
-    if (lookahead.parsable) ruleset->selector(&parse_selector_list(is_root));
-    else ruleset->selector(&parse_selector_schema(lookahead.found));
-    // then parse the inner block
-    stack.push_back(Scope::Rules);
-    ruleset->block(parse_block());
-    stack.pop_back();
-    // update for end position
-    ruleset->update_pstate(pstate);
-    ruleset->block()->update_pstate(pstate);
-    // inherit is_root from parent block
-    // need this info for sanity checks
-    ruleset->is_root(is_root);
-    // return AST Node
-    return ruleset;
-  }
-
-  // parse a selector schema that will be evaluated in the eval stage
-  // uses a string schema internally to do the actual schema handling
-  // in the eval stage we will be re-parse it into an actual selector
-  Selector_Schema_Obj Parser::parse_selector_schema(const char* end_of_selector)
-  {
-    // move up to the start
-    lex< optional_spaces >();
-    const char* i = position;
-    // selector schema re-uses string schema implementation
-    String_Schema_Ptr schema = SASS_MEMORY_NEW(String_Schema, pstate);
-    // the selector schema is pretty much just a wrapper for the string schema
-    Selector_Schema_Ptr selector_schema = SASS_MEMORY_NEW(Selector_Schema, pstate, schema);
-    selector_schema->media_block(last_media_block);
-
-    // process until end
-    while (i < end_of_selector) {
-      // try to parse mutliple interpolants
-      if (const char* p = find_first_in_interval< exactly<hash_lbrace>, block_comment >(i, end_of_selector)) {
-        // accumulate the preceding segment if the position has advanced
-        if (i < p) {
-          std::string parsed(i, p);
-          String_Constant_Obj str = SASS_MEMORY_NEW(String_Constant, pstate, parsed);
-          pstate += Offset(parsed);
-          str->update_pstate(pstate);
-          schema->append(&str);
-        }
-
-        // check if the interpolation only contains white-space (error out)
-        if (peek < sequence < optional_spaces, exactly<rbrace> > >(p+2)) { position = p+2;
-          css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
-        }
-        // skip over all nested inner interpolations up to our own delimiter
-        const char* j = skip_over_scopes< exactly<hash_lbrace>, exactly<rbrace> >(p + 2, end_of_selector);
-        // pass inner expression to the parser to resolve nested interpolations
-        pstate.add(p, p+2);
-        Expression_Obj interpolant = Parser::from_c_str(p+2, j, ctx, pstate).parse_list();
-        // set status on the list expression
-        interpolant->is_interpolant(true);
-        // schema->has_interpolants(true);
-        // add to the string schema
-        schema->append(&interpolant);
-        // advance parser state
-        pstate.add(p+2, j);
-        // advance position
-        i = j;
-      }
-      // no more interpolants have been found
-      // add the last segment if there is one
-      else {
-        // make sure to add the last bits of the string up to the end (if any)
-        if (i < end_of_selector) {
-          std::string parsed(i, end_of_selector);
-          String_Constant_Obj str = SASS_MEMORY_NEW(String_Constant, pstate, parsed);
-          pstate += Offset(parsed);
-          str->update_pstate(pstate);
-          i = end_of_selector;
-          schema->append(&str);
-        }
-        // exit loop
-      }
-    }
-    // EO until eos
-
-    // update position
-    position = i;
-
-    // update for end position
-    selector_schema->update_pstate(pstate);
-    schema->update_pstate(pstate);
-
-    after_token = before_token = pstate;
-
-    // return parsed result
-    return selector_schema;
-  }
-  // EO parse_selector_schema
-
-  void Parser::parse_charset_directive()
-  {
-    lex <
-      sequence <
-        quoted_string,
-        optional_spaces,
-        exactly <';'>
-      >
-    >();
-  }
-
-  // called after parsing `kwd_include_directive`
-  Mixin_Call_Obj Parser::parse_include_directive()
-  {
-    // lex identifier into `lexed` var
-    lex_identifier(); // may error out
-    // normalize underscores to hyphens
-    std::string name(Util::normalize_underscores(lexed));
-    // create the initial mixin call object
-    Mixin_Call_Obj call = SASS_MEMORY_NEW(Mixin_Call, pstate, name, 0, 0);
-    // parse mandatory arguments
-    call->arguments(parse_arguments());
-    // parse optional block
-    if (peek < exactly <'{'> >()) {
-      call->block(parse_block());
-    }
-    // return ast node
-    return call.detach();
-  }
-  // EO parse_include_directive
-
-  // parse a list of complex selectors
-  // this is the main entry point for most
-  Selector_List_Obj Parser::parse_selector_list(bool in_root)
-  {
-    bool reloop = true;
-    bool had_linefeed = false;
-    Complex_Selector_Obj sel;
-    Selector_List_Obj group = SASS_MEMORY_NEW(Selector_List, pstate);
-    group->media_block(last_media_block);
-    do {
-      reloop = false;
-
-      had_linefeed = had_linefeed || peek_newline();
-
-      if (peek_css< class_char < selector_list_delims > >())
-        break; // in case there are superfluous commas at the end
-
-
-      // now parse the complex selector
-      sel = parse_complex_selector(in_root);
-
-      if (!sel) return group.detach();
-
-      sel->has_line_feed(had_linefeed);
-
-      had_linefeed = false;
-
-      while (peek_css< exactly<','> >())
-      {
-        lex< css_comments >(false);
-        // consume everything up and including the comma separator
-        reloop = lex< exactly<','> >() != 0;
-        // remember line break (also between some commas)
-        had_linefeed = had_linefeed || peek_newline();
-        // remember line break (also between some commas)
-      }
-      group->append(sel);
-    }
-    while (reloop);
-    while (lex_css< kwd_optional >()) {
-      group->is_optional(true);
-    }
-    // update for end position
-    group->update_pstate(pstate);
-    if (sel) sel->last()->has_line_break(false);
-    return group.detach();
-  }
-  // EO parse_selector_list
-
-  // a complex selector combines a compound selector with another
-  // complex selector, with one of four combinator operations.
-  // the compound selector (head) is optional, since the combinator
-  // can come first in the whole selector sequence (like `> DIV').
-  Complex_Selector_Obj Parser::parse_complex_selector(bool in_root)
-  {
-
-    String_Ptr reference = 0;
-    lex < block_comment >();
-    advanceToNextToken();
-    Complex_Selector_Obj sel = SASS_MEMORY_NEW(Complex_Selector, pstate);
-
-    // parse the left hand side
-    Compound_Selector_Obj lhs;
-    // special case if it starts with combinator ([+~>])
-    if (!peek_css< class_char < selector_combinator_ops > >()) {
-      // parse the left hand side
-      lhs = parse_compound_selector();
-    }
-
-    // check for end of file condition
-    if (peek < end_of_file >()) return 0;
-
-    // parse combinator between lhs and rhs
-    Complex_Selector::Combinator combinator;
-    if      (lex< exactly<'+'> >()) combinator = Complex_Selector::ADJACENT_TO;
-    else if (lex< exactly<'~'> >()) combinator = Complex_Selector::PRECEDES;
-    else if (lex< exactly<'>'> >()) combinator = Complex_Selector::PARENT_OF;
-    else if (lex< sequence < exactly<'/'>, negate < exactly < '*' > > > >()) {
-      // comments are allowed, but not spaces?
-      combinator = Complex_Selector::REFERENCE;
-      if (!lex < re_reference_combinator >()) return 0;
-      reference = SASS_MEMORY_NEW(String_Constant, pstate, lexed);
-      if (!lex < exactly < '/' > >()) return 0; // ToDo: error msg?
-    }
-    else /* if (lex< zero >()) */   combinator = Complex_Selector::ANCESTOR_OF;
-
-    if (!lhs && combinator == Complex_Selector::ANCESTOR_OF) return 0;
-
-    // lex < block_comment >();
-    sel->head(lhs);
-    sel->combinator(combinator);
-    sel->media_block(last_media_block);
-
-    if (combinator == Complex_Selector::REFERENCE) sel->reference(reference);
-    // has linfeed after combinator?
-    sel->has_line_break(peek_newline());
-    // sel->has_line_feed(has_line_feed);
-
-    // check if we got the abort condition (ToDo: optimize)
-    if (!peek_css< class_char < complex_selector_delims > >()) {
-      // parse next selector in sequence
-      sel->tail(parse_complex_selector(true));
-    }
-
-    // add a parent selector if we are not in a root
-    // also skip adding parent ref if we only have refs
-    if (!sel->has_parent_ref() && !in_at_root && !in_root) {
-      // create the objects to wrap parent selector reference
-      Compound_Selector_Obj head = SASS_MEMORY_NEW(Compound_Selector, pstate);
-      Parent_Selector_Ptr parent = SASS_MEMORY_NEW(Parent_Selector, pstate, false);
-      parent->media_block(last_media_block);
-      head->media_block(last_media_block);
-      // add simple selector
-      head->append(parent);
-      // selector may not have any head yet
-      if (!sel->head()) { sel->head(head); }
-      // otherwise we need to create a new complex selector and set the old one as its tail
-      else {
-        sel = SASS_MEMORY_NEW(Complex_Selector, pstate, Complex_Selector::ANCESTOR_OF, head, sel);
-        sel->media_block(last_media_block);
-      }
-      // peek for linefeed and remember result on head
-      // if (peek_newline()) head->has_line_break(true);
-    }
-
-    sel->update_pstate(pstate);
-    // complex selector
-    return sel;
-  }
-  // EO parse_complex_selector
-
-  // parse one compound selector, which is basically
-  // a list of simple selectors (directly adjacent)
-  // lex them exactly (without skipping white-space)
-  Compound_Selector_Obj Parser::parse_compound_selector()
-  {
-    // init an empty compound selector wrapper
-    Compound_Selector_Obj seq = SASS_MEMORY_NEW(Compound_Selector, pstate);
-    seq->media_block(last_media_block);
-
-    // skip initial white-space
-    lex< css_whitespace >();
-
-    // parse list
-    while (true)
-    {
-      // remove all block comments (don't skip white-space)
-      lex< delimited_by< slash_star, star_slash, false > >(false);
-      // parse functional
-      if (match < re_pseudo_selector >())
-      {
-        seq->append(&parse_simple_selector());
-      }
-      // parse parent selector
-      else if (lex< exactly<'&'> >(false))
-      {
-        // this produces a linefeed!?
-        seq->has_parent_reference(true);
-        seq->append(SASS_MEMORY_NEW(Parent_Selector, pstate));
-        // parent selector only allowed at start
-        // upcoming Sass may allow also trailing
-        if (seq->length() > 1) {
-          ParserState state(pstate);
-          Simple_Selector_Obj cur = (*seq)[seq->length()-1];
-          Simple_Selector_Obj prev = (*seq)[seq->length()-2];
-          std::string sel(prev->to_string({ NESTED, 5 }));
-          std::string found(cur->to_string({ NESTED, 5 }));
-          if (lex < identifier >()) { found += std::string(lexed); }
-          error("Invalid CSS after \"" + sel + "\": expected \"{\", was \"" + found + "\"\n\n"
-            "\"" + found + "\" may only be used at the beginning of a compound selector.", state);
-        }
-      }
-      // parse type selector
-      else if (lex< re_type_selector >(false))
-      {
-        seq->append(SASS_MEMORY_NEW(Element_Selector, pstate, lexed));
-      }
-      // peek for abort conditions
-      else if (peek< spaces >()) break;
-      else if (peek< end_of_file >()) { break; }
-      else if (peek_css < class_char < selector_combinator_ops > >()) break;
-      else if (peek_css < class_char < complex_selector_delims > >()) break;
-      // otherwise parse another simple selector
-      else {
-        Simple_Selector_Obj sel = parse_simple_selector();
-        if (!sel) return 0;
-        seq->append(&sel);
-      }
-    }
-
-    if (seq && !peek_css<exactly<'{'>>()) {
-      seq->has_line_break(peek_newline());
-    }
-
-    // EO while true
-    return seq;
-
-  }
-  // EO parse_compound_selector
-
-  Simple_Selector_Obj Parser::parse_simple_selector()
-  {
-    lex < css_comments >(false);
-    if (lex< class_name >()) {
-      return SASS_MEMORY_NEW(Class_Selector, pstate, lexed);
-    }
-    else if (lex< id_name >()) {
-      return SASS_MEMORY_NEW(Id_Selector, pstate, lexed);
-    }
-    else if (lex< quoted_string >()) {
-      return SASS_MEMORY_NEW(Element_Selector, pstate, unquote(lexed));
-    }
-    else if (lex< alternatives < variable, number, static_reference_combinator > >()) {
-      return SASS_MEMORY_NEW(Element_Selector, pstate, lexed);
-    }
-    else if (peek< pseudo_not >()) {
-      return &parse_negated_selector();
-    }
-    else if (peek< re_pseudo_selector >()) {
-      return &parse_pseudo_selector();
-    }
-    else if (peek< exactly<':'> >()) {
-      return &parse_pseudo_selector();
-    }
-    else if (lex < exactly<'['> >()) {
-      return &parse_attribute_selector();
-    }
-    else if (lex< placeholder >()) {
-      Placeholder_Selector_Ptr sel = SASS_MEMORY_NEW(Placeholder_Selector, pstate, lexed);
-      sel->media_block(last_media_block);
-      return sel;
-    }
-    // failed
-    return 0;
-  }
-
-  Wrapped_Selector_Obj Parser::parse_negated_selector()
-  {
-    lex< pseudo_not >();
-    std::string name(lexed);
-    ParserState nsource_position = pstate;
-    Selector_List_Obj negated = parse_selector_list(true);
-    if (!lex< exactly<')'> >()) {
-      error("negated selector is missing ')'", pstate);
-    }
-    name.erase(name.size() - 1);
-    return SASS_MEMORY_NEW(Wrapped_Selector, nsource_position, name, &negated);
-  }
-
-  // a pseudo selector often starts with one or two colons
-  // it can contain more selectors inside parentheses
-  Simple_Selector_Obj Parser::parse_pseudo_selector() {
-    if (lex< sequence<
-          optional < pseudo_prefix >,
-          // we keep the space within the name, strange enough
-          // ToDo: refactor output to schedule the space for it
-          // or do we really want to keep the real white-space?
-          sequence< identifier, optional < block_comment >, exactly<'('> >
-        > >())
-    {
-
-      std::string name(lexed);
-      name.erase(name.size() - 1);
-      ParserState p = pstate;
-
-      // specially parse static stuff
-      // ToDo: really everything static?
-      if (peek_css <
-            sequence <
-              alternatives <
-                static_value,
-                binomial
-              >,
-              optional_css_whitespace,
-              exactly<')'>
-            >
-          >()
-      ) {
-        lex_css< alternatives < static_value, binomial > >();
-        String_Constant_Ptr expr = SASS_MEMORY_NEW(String_Constant, pstate, lexed);
-        if (expr && lex_css< exactly<')'> >()) {
-          expr->can_compress_whitespace(true);
-          return SASS_MEMORY_NEW(Pseudo_Selector, p, name, expr);
-        }
-      }
-      else if (Selector_List_Obj wrapped = parse_selector_list(true)) {
-        if (wrapped && lex_css< exactly<')'> >()) {
-          return SASS_MEMORY_NEW(Wrapped_Selector, p, name, &wrapped);
-        }
-      }
-
-    }
-    // EO if pseudo selector
-
-    else if (lex < sequence< optional < pseudo_prefix >, identifier > >()) {
-      return SASS_MEMORY_NEW(Pseudo_Selector, pstate, lexed);
-    }
-    else if(lex < pseudo_prefix >()) {
-      css_error("Invalid CSS", " after ", ": expected pseudoclass or pseudoelement, was ");
-    }
-
-    css_error("Invalid CSS", " after ", ": expected \")\", was ");
-
-    // unreachable statement
-    return 0;
-  }
-
-  Attribute_Selector_Obj Parser::parse_attribute_selector()
-  {
-    ParserState p = pstate;
-    if (!lex_css< attribute_name >()) error("invalid attribute name in attribute selector", pstate);
-    std::string name(lexed);
-    if (lex_css< alternatives < exactly<']'>, exactly<'/'> > >()) return SASS_MEMORY_NEW(Attribute_Selector, p, name, "", 0);
-    if (!lex_css< alternatives< exact_match, class_match, dash_match,
-                                prefix_match, suffix_match, substring_match > >()) {
-      error("invalid operator in attribute selector for " + name, pstate);
-    }
-    std::string matcher(lexed);
-
-    String_Obj value = 0;
-    if (lex_css< identifier >()) {
-      value = SASS_MEMORY_NEW(String_Constant, p, lexed);
-    }
-    else if (lex_css< quoted_string >()) {
-      value = &parse_interpolated_chunk(lexed, true); // needed!
-    }
-    else {
-      error("expected a string constant or identifier in attribute selector for " + name, pstate);
-    }
-
-    if (!lex_css< alternatives < exactly<']'>, exactly<'/'> > >()) error("unterminated attribute selector for " + name, pstate);
-    return SASS_MEMORY_NEW(Attribute_Selector, p, name, matcher, value);
-  }
-
-  /* parse block comment and add to block */
-  void Parser::parse_block_comments()
-  {
-    Block_Obj block = block_stack.back();
-
-    while (lex< block_comment >()) {
-      bool is_important = lexed.begin[2] == '!';
-      // flag on second param is to skip loosely over comments
-      String_Obj contents = parse_interpolated_chunk(lexed, true);
-      block->append(SASS_MEMORY_NEW(Comment, pstate, contents, is_important));
-    }
-  }
-
-  Declaration_Obj Parser::parse_declaration() {
-    String_Obj prop;
-    if (lex< sequence< optional< exactly<'*'> >, identifier_schema > >()) {
-      prop = parse_identifier_schema();
-    }
-    else if (lex< sequence< optional< exactly<'*'> >, identifier, zero_plus< block_comment > > >()) {
-      prop = SASS_MEMORY_NEW(String_Constant, pstate, lexed);
-    }
-    else {
-      css_error("Invalid CSS", " after ", ": expected \"}\", was ");
-    }
-    bool is_indented = true;
-    const std::string property(lexed);
-    if (!lex_css< one_plus< exactly<':'> > >()) error("property \"" + property + "\" must be followed by a ':'", pstate);
-    lex < css_comments >(false);
-    if (peek_css< exactly<';'> >()) error("style declaration must contain a value", pstate);
-    if (peek_css< exactly<'{'> >()) is_indented = false; // don't indent if value is empty
-    if (peek_css< static_value >()) {
-      return SASS_MEMORY_NEW(Declaration, prop->pstate(), prop, &parse_static_value()/*, lex<kwd_important>()*/);
-    }
-    else {
-      Expression_Obj value;
-      Lookahead lookahead = lookahead_for_value(position);
-      if (lookahead.found) {
-        if (lookahead.has_interpolants) {
-          value = &parse_value_schema(lookahead.found);
-        } else {
-          value = &parse_list(DELAYED);
-        }
-      }
-      else {
-        value = &parse_list(DELAYED);
-        if (List_Ptr list = SASS_MEMORY_CAST(List, value)) {
-          if (list->length() == 0 && !peek< exactly <'{'> >()) {
-            css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
-          }
-        }
-      }
-      lex < css_comments >(false);
-      Declaration_Obj decl = SASS_MEMORY_NEW(Declaration, prop->pstate(), prop, value/*, lex<kwd_important>()*/);
-      decl->is_indented(is_indented);
-      decl->update_pstate(pstate);
-      return decl;
-    }
-  }
-
-  // parse +/- and return false if negative
-  bool Parser::parse_number_prefix()
-  {
-    bool positive = true;
-    while(true) {
-      if (lex < block_comment >()) continue;
-      if (lex < number_prefix >()) continue;
-      if (lex < exactly < '-' > >()) {
-        positive = !positive;
-        continue;
-      }
-      break;
-    }
-    return positive;
-  }
-
-  Expression_Obj Parser::parse_map()
-  {
-    Expression_Obj key = parse_list();
-    List_Obj map = SASS_MEMORY_NEW(List, pstate, 0, SASS_HASH);
-
-    // it's not a map so return the lexed value as a list value
-    if (!lex_css< exactly<':'> >())
-    { return key; }
-
-    Expression_Obj value = parse_space_list();
-
-    map->append(key);
-    map->append(value);
-
-    while (lex_css< exactly<','> >())
-    {
-      // allow trailing commas - #495
-      if (peek_css< exactly<')'> >(position))
-      { break; }
-
-      Expression_Obj key = parse_space_list();
-
-      if (!(lex< exactly<':'> >()))
-      { css_error("Invalid CSS", " after ", ": expected \":\", was "); }
-
-      Expression_Obj value = parse_space_list();
-
-      map->append(key);
-      map->append(value);
-    }
-
-    ParserState ps = map->pstate();
-    ps.offset = pstate - ps + pstate.offset;
-    map->pstate(ps);
-
-    return &map;
-  }
-
-  // parse list returns either a space separated list,
-  // a comma separated list or any bare expression found.
-  // so to speak: we unwrap items from lists if possible here!
-  Expression_Obj Parser::parse_list(bool delayed)
-  {
-    return parse_comma_list(delayed);
-  }
-
-  // will return singletons unwrapped
-  Expression_Obj Parser::parse_comma_list(bool delayed)
-  {
-    // check if we have an empty list
-    // return the empty list as such
-    if (peek_css< alternatives <
-          // exactly<'!'>,
-          exactly<';'>,
-          exactly<'}'>,
-          exactly<'{'>,
-          exactly<')'>,
-          exactly<':'>,
-          end_of_file,
-          exactly<ellipsis>,
-          default_flag,
-          global_flag
-        > >(position))
-    {
-      // return an empty list (nothing to delay)
-      return SASS_MEMORY_NEW(List, pstate, 0);
-    }
-
-    // now try to parse a space list
-    Expression_Obj list = parse_space_list();
-    // if it's a singleton, return it (don't wrap it)
-    if (!peek_css< exactly<','> >(position)) {
-      // set_delay doesn't apply to list children
-      // so this will only undelay single values
-      if (!delayed) list->set_delayed(false);
-      return list;
-    }
-
-    // if we got so far, we actually do have a comma list
-    List_Obj comma_list = SASS_MEMORY_NEW(List, pstate, 2, SASS_COMMA);
-    // wrap the first expression
-    comma_list->append(list);
-
-    while (lex_css< exactly<','> >())
-    {
-      // check for abort condition
-      if (peek_css< alternatives <
-            exactly<';'>,
-            exactly<'}'>,
-            exactly<'{'>,
-            exactly<')'>,
-            exactly<':'>,
-            end_of_file,
-            exactly<ellipsis>,
-            default_flag,
-            global_flag
-          > >(position)
-      ) { break; }
-      // otherwise add another expression
-      comma_list->append(parse_space_list());
-    }
-    // return the list
-    return &comma_list;
-  }
-  // EO parse_comma_list
-
-  // will return singletons unwrapped
-  Expression_Obj Parser::parse_space_list()
-  {
-    Expression_Obj disj1 = parse_disjunction();
-    // if it's a singleton, return it (don't wrap it)
-    if (peek_css< alternatives <
-          // exactly<'!'>,
-          exactly<';'>,
-          exactly<'}'>,
-          exactly<'{'>,
-          exactly<')'>,
-          exactly<','>,
-          exactly<':'>,
-          end_of_file,
-          exactly<ellipsis>,
-          default_flag,
-          global_flag
-        > >(position)
-    ) { return disj1; }
-
-    List_Obj space_list = SASS_MEMORY_NEW(List, pstate, 2, SASS_SPACE);
-    space_list->append(disj1);
-
-    while (!(peek_css< alternatives <
-               // exactly<'!'>,
-               exactly<';'>,
-               exactly<'}'>,
-               exactly<'{'>,
-               exactly<')'>,
-               exactly<','>,
-               exactly<':'>,
-               end_of_file,
-               exactly<ellipsis>,
-               default_flag,
-               global_flag
-           > >(position)) && peek_css< optional_css_whitespace >() != end
-    ) {
-      // the space is parsed implicitly?
-      space_list->append(parse_disjunction());
-    }
-    // return the list
-    return &space_list;
-  }
-  // EO parse_space_list
-
-  // parse logical OR operation
-  Expression_Obj Parser::parse_disjunction()
-  {
-    advanceToNextToken();
-    ParserState state(pstate);
-    // parse the left hand side conjunction
-    Expression_Obj conj = parse_conjunction();
-    // parse multiple right hand sides
-    std::vector<Expression_Obj> operands;
-    while (lex_css< kwd_or >())
-      operands.push_back(parse_conjunction());
-    // if it's a singleton, return it directly
-    if (operands.size() == 0) return conj;
-    // fold all operands into one binary expression
-    Expression_Obj ex = fold_operands(conj, operands, { Sass_OP::OR });
-    state.offset = pstate - state + pstate.offset;
-    ex->pstate(state);
-    return ex;
-  }
-  // EO parse_disjunction
-
-  // parse logical AND operation
-  Expression_Obj Parser::parse_conjunction()
-  {
-    advanceToNextToken();
-    ParserState state(pstate);
-    // parse the left hand side relation
-    Expression_Obj rel = parse_relation();
-    // parse multiple right hand sides
-    std::vector<Expression_Obj> operands;
-    while (lex_css< kwd_and >()) {
-      operands.push_back(&parse_relation());
-    }
-    // if it's a singleton, return it directly
-    if (operands.size() == 0) return rel;
-    // fold all operands into one binary expression
-    Expression_Obj ex = fold_operands(rel, operands, { Sass_OP::AND });
-    state.offset = pstate - state + pstate.offset;
-    ex->pstate(state);
-    return ex;
-  }
-  // EO parse_conjunction
-
-  // parse comparison operations
-  Expression_Obj Parser::parse_relation()
-  {
-    advanceToNextToken();
-    ParserState state(pstate);
-    // parse the left hand side expression
-    Expression_Obj lhs = parse_expression();
-    std::vector<Expression_Obj> operands;
-    std::vector<Operand> operators;
-    // if it's a singleton, return it (don't wrap it)
-    while (peek< alternatives <
-            kwd_eq,
-            kwd_neq,
-            kwd_gte,
-            kwd_gt,
-            kwd_lte,
-            kwd_lt
-          > >(position))
-    {
-      // is directly adjancent to expression?
-      bool left_ws = peek < css_comments >() != NULL;
-      // parse the operator
-      enum Sass_OP op
-      = lex<kwd_eq>()  ? Sass_OP::EQ
-      : lex<kwd_neq>() ? Sass_OP::NEQ
-      : lex<kwd_gte>() ? Sass_OP::GTE
-      : lex<kwd_lte>() ? Sass_OP::LTE
-      : lex<kwd_gt>()  ? Sass_OP::GT
-      : lex<kwd_lt>()  ? Sass_OP::LT
-      // we checked the possibilities on top of fn
-      :                  Sass_OP::EQ;
-      // is directly adjacent to expression?
-      bool right_ws = peek < css_comments >() != NULL;
-      operators.push_back({ op, left_ws, right_ws });
-      operands.push_back(&parse_expression());
-      left_ws = peek < css_comments >() != NULL;
-    }
-    // we are called recursively for list, so we first
-    // fold inner binary expression which has delayed
-    // correctly set to zero. After folding we also unwrap
-    // single nested items. So we cannot set delay on the
-    // returned result here, as we have lost nestings ...
-    Expression_Obj ex = fold_operands(lhs, operands, operators);
-    state.offset = pstate - state + pstate.offset;
-    ex->pstate(state);
-    return ex;
-  }
-  // parse_relation
-
-  // parse expression valid for operations
-  // called from parse_relation
-  // called from parse_for_directive
-  // called from parse_media_expression
-  // parse addition and subtraction operations
-  Expression_Obj Parser::parse_expression()
-  {
-    advanceToNextToken();
-    ParserState state(pstate);
-    // parses multiple add and subtract operations
-    // NOTE: make sure that identifiers starting with
-    // NOTE: dashes do NOT count as subtract operation
-    Expression_Obj lhs = parse_operators();
-    // if it's a singleton, return it (don't wrap it)
-    if (!(peek_css< exactly<'+'> >(position) ||
-          // condition is a bit misterious, but some combinations should not be counted as operations
-          (peek< no_spaces >(position) && peek< sequence< negate< unsigned_number >, exactly<'-'>, negate< space > > >(position)) ||
-          (peek< sequence< negate< unsigned_number >, exactly<'-'>, negate< unsigned_number > > >(position))) ||
-          peek< sequence < zero_plus < exactly <'-' > >, identifier > >(position))
-    { return lhs; }
-
-    std::vector<Expression_Obj> operands;
-    std::vector<Operand> operators;
-    bool left_ws = peek < css_comments >() != NULL;
-    while (
-      lex_css< exactly<'+'> >() ||
-
-      (
-      ! peek_css< sequence < zero_plus < exactly <'-' > >, identifier > >(position)
-      && lex_css< sequence< negate< digit >, exactly<'-'> > >()
-      )
-
-    ) {
-
-      bool right_ws = peek < css_comments >() != NULL;
-      operators.push_back({ lexed.to_string() == "+" ? Sass_OP::ADD : Sass_OP::SUB, left_ws, right_ws });
-      operands.push_back(&parse_operators());
-      left_ws = peek < css_comments >() != NULL;
-    }
-
-    if (operands.size() == 0) return lhs;
-    Expression_Obj ex = fold_operands(lhs, operands, operators);
-    state.offset = pstate - state + pstate.offset;
-    ex->pstate(state);
-    return ex;
-  }
-
-  // parse addition and subtraction operations
-  Expression_Obj Parser::parse_operators()
-  {
-    advanceToNextToken();
-    ParserState state(pstate);
-    Expression_Obj factor = parse_factor();
-    // if it's a singleton, return it (don't wrap it)
-    std::vector<Expression_Obj> operands; // factors
-    std::vector<Operand> operators; // ops
-    // lex operations to apply to lhs
-    const char* left_ws = peek < css_comments >();
-    while (lex_css< class_char< static_ops > >()) {
-      const char* right_ws = peek < css_comments >();
-      switch(*lexed.begin) {
-        case '*': operators.push_back({ Sass_OP::MUL, left_ws != 0, right_ws != 0 }); break;
-        case '/': operators.push_back({ Sass_OP::DIV, left_ws != 0, right_ws != 0 }); break;
-        case '%': operators.push_back({ Sass_OP::MOD, left_ws != 0, right_ws != 0 }); break;
-        default: throw std::runtime_error("unknown static op parsed"); break;
-      }
-      operands.push_back(parse_factor());
-      left_ws = peek < css_comments >();
-    }
-    // operands and operators to binary expression
-    Expression_Obj ex = fold_operands(factor, operands, operators);
-    state.offset = pstate - state + pstate.offset;
-    ex->pstate(state);
-    return ex;
-  }
-  // EO parse_operators
-
-
-  // called from parse_operators
-  // called from parse_value_schema
-  Expression_Obj Parser::parse_factor()
-  {
-    lex < css_comments >(false);
-    if (lex_css< exactly<'('> >()) {
-      // parse_map may return a list
-      Expression_Obj value = parse_map();
-      // lex the expected closing parenthesis
-      if (!lex_css< exactly<')'> >()) error("unclosed parenthesis", pstate);
-      // expression can be evaluated
-      return &value;
-    }
-    // string may be interpolated
-    // if (lex< quoted_string >()) {
-    //   return &parse_string();
-    // }
-    else if (peek< ie_property >()) {
-      return &parse_ie_property();
-    }
-    else if (peek< ie_keyword_arg >()) {
-      return &parse_ie_keyword_arg();
-    }
-    else if (peek< sequence < calc_fn_call, exactly <'('> > >()) {
-      return &parse_calc_function();
-    }
-    else if (lex < functional_schema >()) {
-      return &parse_function_call_schema();
-    }
-    else if (lex< identifier_schema >()) {
-      String_Obj string = parse_identifier_schema();
-      if (String_Schema_Ptr schema = SASS_MEMORY_CAST(String_Schema, string)) {
-        if (lex < exactly < '(' > >()) {
-          schema->append(&parse_list());
-          lex < exactly < ')' > >();
-        }
-      }
-      return &string;
-    }
-    else if (peek< sequence< uri_prefix, W, real_uri_value > >()) {
-      return &parse_url_function_string();
-    }
-    else if (peek< re_functional >()) {
-      return &parse_function_call();
-    }
-    else if (lex< exactly<'+'> >()) {
-      Unary_Expression_Ptr ex = SASS_MEMORY_NEW(Unary_Expression, pstate, Unary_Expression::PLUS, &parse_factor());
-      if (ex && ex->operand()) ex->is_delayed(ex->operand()->is_delayed());
-      return ex;
-    }
-    else if (lex< exactly<'-'> >()) {
-      Unary_Expression_Ptr ex = SASS_MEMORY_NEW(Unary_Expression, pstate, Unary_Expression::MINUS, &parse_factor());
-      if (ex && ex->operand()) ex->is_delayed(ex->operand()->is_delayed());
-      return ex;
-    }
-    else if (lex< sequence< kwd_not > >()) {
-      Unary_Expression_Ptr ex = SASS_MEMORY_NEW(Unary_Expression, pstate, Unary_Expression::NOT, &parse_factor());
-      if (ex && ex->operand()) ex->is_delayed(ex->operand()->is_delayed());
-      return ex;
-    }
-    else if (peek < sequence < one_plus < alternatives < css_whitespace, exactly<'-'>, exactly<'+'> > >, number > >()) {
-      if (parse_number_prefix()) return &parse_value(); // prefix is positive
-      Unary_Expression_Ptr ex = SASS_MEMORY_NEW(Unary_Expression, pstate, Unary_Expression::MINUS, &parse_value());
-      if (ex->operand()) ex->is_delayed(ex->operand()->is_delayed());
-      return ex;
-    }
-    else {
-      return parse_value();
-    }
-  }
-
-  // parse one value for a list
-  Expression_Obj Parser::parse_value()
-  {
-    lex< css_comments >(false);
-    if (lex< ampersand >())
-    {
-      return SASS_MEMORY_NEW(Parent_Selector, pstate); }
-
-    if (lex< kwd_important >())
-    { return SASS_MEMORY_NEW(String_Constant, pstate, "!important"); }
-
-    // parse `10%4px` into separated items and not a schema
-    if (lex< sequence < percentage, lookahead < number > > >())
-    { return SASS_MEMORY_NEW(Textual, pstate, Textual::PERCENTAGE, lexed); }
-
-    if (lex< sequence < number, lookahead< sequence < op, number > > > >())
-    { return SASS_MEMORY_NEW(Textual, pstate, Textual::NUMBER, lexed); }
-
-    // string may be interpolated
-    if (lex< sequence < quoted_string, lookahead < exactly <'-'> > > >())
-    { return &parse_string(); }
-
-    if (const char* stop = peek< value_schema >())
-    { return &parse_value_schema(stop); }
-
-    // string may be interpolated
-    if (lex< quoted_string >())
-    { return &parse_string(); }
-
-    if (lex< kwd_true >())
-    { return SASS_MEMORY_NEW(Boolean, pstate, true); }
-
-    if (lex< kwd_false >())
-    { return SASS_MEMORY_NEW(Boolean, pstate, false); }
-
-    if (lex< kwd_null >())
-    { return SASS_MEMORY_NEW(Null, pstate); }
-
-    if (lex< identifier >()) {
-      return SASS_MEMORY_NEW(String_Constant, pstate, lexed);
-    }
-
-    if (lex< percentage >())
-    { return SASS_MEMORY_NEW(Textual, pstate, Textual::PERCENTAGE, lexed); }
-
-    // match hex number first because 0x000 looks like a number followed by an identifier
-    if (lex< sequence < alternatives< hex, hex0 >, negate < exactly<'-'> > > >())
-    { return SASS_MEMORY_NEW(Textual, pstate, Textual::HEX, lexed); }
-
-    if (lex< sequence < exactly <'#'>, identifier > >())
-    { return SASS_MEMORY_NEW(String_Quoted, pstate, lexed); }
-
-    // also handle the 10em- foo special case
-    // alternatives < exactly < '.' >, .. > -- `1.5em-.75em` is split into a list, not a binary expression
-    if (lex< sequence< dimension, optional< sequence< exactly<'-'>, lookahead< alternatives < space > > > > > >())
-    { return SASS_MEMORY_NEW(Textual, pstate, Textual::DIMENSION, lexed); }
-
-    if (lex< sequence< static_component, one_plus< strict_identifier > > >())
-    { return SASS_MEMORY_NEW(String_Constant, pstate, lexed); }
-
-    if (lex< number >())
-    { return SASS_MEMORY_NEW(Textual, pstate, Textual::NUMBER, lexed); }
-
-    if (lex< variable >())
-    { return SASS_MEMORY_NEW(Variable, pstate, Util::normalize_underscores(lexed)); }
-
-    // Special case handling for `%` proceeding an interpolant.
-    if (lex< sequence< exactly<'%'>, optional< percentage > > >())
-    { return SASS_MEMORY_NEW(String_Constant, pstate, lexed); }
-
-    css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
-
-    // unreachable statement
-    return 0;
-  }
-
-  // this parses interpolation inside other strings
-  // means the result should later be quoted again
-  String_Obj Parser::parse_interpolated_chunk(Token chunk, bool constant)
-  {
-    const char* i = chunk.begin;
-    // see if there any interpolants
-    const char* p = constant ? find_first_in_interval< exactly<hash_lbrace> >(i, chunk.end) :
-                    find_first_in_interval< exactly<hash_lbrace>, block_comment >(i, chunk.end);
-
-    if (!p) {
-      String_Quoted_Ptr str_quoted = SASS_MEMORY_NEW(String_Quoted, pstate, std::string(i, chunk.end));
-      if (!constant && str_quoted->quote_mark()) str_quoted->quote_mark('*');
-      return str_quoted;
-    }
-
-    String_Schema_Ptr schema = SASS_MEMORY_NEW(String_Schema, pstate);
-    schema->is_interpolant(true);
-    while (i < chunk.end) {
-      p = constant ? find_first_in_interval< exactly<hash_lbrace> >(i, chunk.end) :
-          find_first_in_interval< exactly<hash_lbrace>, block_comment >(i, chunk.end);
-      if (p) {
-        if (i < p) {
-          // accumulate the preceding segment if it's nonempty
-          schema->append(SASS_MEMORY_NEW(String_Constant, pstate, std::string(i, p)));
-        }
-        // 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
-          Expression_Obj interp_node = Parser::from_token(Token(p+2, j), ctx, pstate, source).parse_list();
-          interp_node->is_interpolant(true);
-          schema->append(&interp_node);
-          i = j;
-        }
-        else {
-          // throw an error if the interpolant is unterminated
-          error("unterminated interpolant inside string constant " + chunk.to_string(), pstate);
-        }
-      }
-      else { // no interpolants left; add the last segment if nonempty
-        // check if we need quotes here (was not sure after merge)
-        if (i < chunk.end) schema->append(SASS_MEMORY_NEW(String_Constant, pstate, std::string(i, chunk.end)));
-        break;
-      }
-      ++ i;
-    }
-
-    return schema;
-  }
-
-  String_Constant_Obj Parser::parse_static_value()
-  {
-    lex< static_value >();
-    Token str(lexed);
-    // static values always have trailing white-
-    // space and end delimiter (\s*[;]$) included
-    -- pstate.offset.column;
-    --str.end;
-    --position;
-
-    String_Constant_Ptr str_node = SASS_MEMORY_NEW(String_Constant, pstate, str.time_wspace());
-    return str_node;
-  }
-
-  String_Obj Parser::parse_string()
-  {
-    return parse_interpolated_chunk(Token(lexed));
-  }
-
-  String_Obj Parser::parse_ie_property()
-  {
-    lex< ie_property >();
-    Token str(lexed);
-    const char* i = str.begin;
-    // see if there any interpolants
-    const char* p = find_first_in_interval< exactly<hash_lbrace>, block_comment >(str.begin, str.end);
-    if (!p) {
-      return SASS_MEMORY_NEW(String_Quoted, pstate, std::string(str.begin, str.end));
-    }
-
-    String_Schema_Ptr schema = SASS_MEMORY_NEW(String_Schema, pstate);
-    while (i < str.end) {
-      p = find_first_in_interval< exactly<hash_lbrace>, block_comment >(i, str.end);
-      if (p) {
-        if (i < p) {
-          schema->append(SASS_MEMORY_NEW(String_Constant, pstate, std::string(i, p))); // accumulate the preceding segment if it's nonempty
-        }
-        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
-          Expression_Obj interp_node = Parser::from_token(Token(p+2, j), ctx, pstate, source).parse_list();
-          interp_node->is_interpolant(true);
-          schema->append(&interp_node);
-          i = j;
-        }
-        else {
-          // throw an error if the interpolant is unterminated
-          error("unterminated interpolant inside IE function " + str.to_string(), pstate);
-        }
-      }
-      else { // no interpolants left; add the last segment if nonempty
-        if (i < str.end) {
-          schema->append(SASS_MEMORY_NEW(String_Constant, pstate, std::string(i, str.end)));
-        }
-        break;
-      }
-    }
-    return schema;
-  }
-
-  String_Obj Parser::parse_ie_keyword_arg()
-  {
-    String_Schema_Ptr kwd_arg = SASS_MEMORY_NEW(String_Schema, pstate, 3);
-    if (lex< variable >()) {
-      kwd_arg->append(SASS_MEMORY_NEW(Variable, pstate, Util::normalize_underscores(lexed)));
-    } else {
-      lex< alternatives< identifier_schema, identifier > >();
-      kwd_arg->append(SASS_MEMORY_NEW(String_Constant, pstate, lexed));
-    }
-    lex< exactly<'='> >();
-    kwd_arg->append(SASS_MEMORY_NEW(String_Constant, pstate, lexed));
-    if (peek< variable >()) kwd_arg->append(&parse_list());
-    else if (lex< number >()) kwd_arg->append(SASS_MEMORY_NEW(Textual, pstate, Textual::NUMBER, Util::normalize_decimals(lexed)));
-    else if (peek < ie_keyword_arg_value >()) { kwd_arg->append(&parse_list()); }
-    return kwd_arg;
-  }
-
-  String_Schema_Obj Parser::parse_value_schema(const char* stop)
-  {
-    // initialize the string schema object to add tokens
-    String_Schema_Obj schema = SASS_MEMORY_NEW(String_Schema, pstate);
-
-    if (peek<exactly<'}'>>()) {
-      css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
-    }
-
-    const char* e = 0;
-    const char* ee = end;
-    end = stop;
-    size_t num_items = 0;
-    bool need_space = false;
-    while (position < stop) {
-      // parse space between tokens
-      if (lex< spaces >() && num_items) {
-        need_space = true;
-      }
-      if (need_space) {
-        need_space = false;
-        // schema->append(SASS_MEMORY_NEW(String_Constant, pstate, " "));
-      }
-      if ((e = peek< re_functional >()) && e < stop) {
-        schema->append(&parse_function_call());
-      }
-      // lex an interpolant /#{...}/
-      else if (lex< exactly < hash_lbrace > >()) {
-        // Try to lex static expression first
-        if (peek< exactly< rbrace > >()) {
-          css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
-        }
-        Expression_Obj ex = 0;
-        if (lex< re_static_expression >()) {
-          ex = SASS_MEMORY_NEW(String_Constant, pstate, lexed);
-        } else {
-          ex = parse_list();
-        }
-        ex->is_interpolant(true);
-        schema->append(ex);
-        if (!lex < exactly < rbrace > >()) {
-          css_error("Invalid CSS", " after ", ": expected \"}\", was ");
-        }
-      }
-      // lex some string constants or other valid token
-      // Note: [-+] chars are left over from i.e. `#{3}+3`
-      else if (lex< alternatives < exactly<'%'>, exactly < '-' >, exactly < '+' > > >()) {
-        schema->append(SASS_MEMORY_NEW(String_Constant, pstate, lexed));
-      }
-      // lex a quoted string
-      else if (lex< quoted_string >()) {
-        // need_space = true;
-        // if (schema->length()) schema->append(SASS_MEMORY_NEW(String_Constant, pstate, " "));
-        // else need_space = true;
-        schema->append(&parse_string());
-        if ((*position == '"' || *position == '\'') || peek < alternatives < alpha > >()) {
-          // need_space = true;
-        }
-        if (peek < exactly < '-' > >()) break;
-      }
-      else if (lex< sequence < identifier > >()) {
-        schema->append(SASS_MEMORY_NEW(String_Constant, pstate, lexed));
-        if ((*position == '"' || *position == '\'') || peek < alternatives < alpha > >()) {
-           // need_space = true;
-        }
-      }
-      // lex (normalized) variable
-      else if (lex< variable >()) {
-        std::string name(Util::normalize_underscores(lexed));
-        schema->append(SASS_MEMORY_NEW(Variable, pstate, name));
-      }
-      // lex percentage value
-      else if (lex< percentage >()) {
-        schema->append(SASS_MEMORY_NEW(Textual, pstate, Textual::PERCENTAGE, lexed));
-      }
-      // lex dimension value
-      else if (lex< dimension >()) {
-        schema->append(SASS_MEMORY_NEW(Textual, pstate, Textual::DIMENSION, lexed));
-      }
-      // lex number value
-      else if (lex< number >()) {
-        schema->append( SASS_MEMORY_NEW(Textual, pstate, Textual::NUMBER, lexed));
-      }
-      // lex hex color value
-      else if (lex< sequence < hex, negate < exactly < '-' > > > >()) {
-        schema->append(SASS_MEMORY_NEW(Textual, pstate, Textual::HEX, lexed));
-      }
-      else if (lex< sequence < exactly <'#'>, identifier > >()) {
-        schema->append(SASS_MEMORY_NEW(String_Quoted, pstate, lexed));
-      }
-      // lex a value in parentheses
-      else if (peek< parenthese_scope >()) {
-        schema->append(&parse_factor());
-      }
-      else {
-        break;
-      }
-      ++num_items;
-    }
-    if (position != stop) {
-      schema->append(SASS_MEMORY_NEW(String_Constant, pstate, std::string(position, stop)));
-      position = stop;
-    }
-    end = ee;
-    return schema;
-  }
-
-  // this parses interpolation outside other strings
-  // means the result must not be quoted again later
-  String_Obj Parser::parse_identifier_schema()
-  {
-    Token id(lexed);
-    const char* i = id.begin;
-    // see if there any interpolants
-    const char* p = find_first_in_interval< exactly<hash_lbrace>, block_comment >(id.begin, id.end);
-    if (!p) {
-      return SASS_MEMORY_NEW(String_Constant, pstate, std::string(id.begin, id.end));
-    }
-
-    String_Schema_Obj schema = SASS_MEMORY_NEW(String_Schema, pstate);
-    while (i < id.end) {
-      p = find_first_in_interval< exactly<hash_lbrace>, block_comment >(i, id.end);
-      if (p) {
-        if (i < p) {
-          // accumulate the preceding segment if it's nonempty
-          const char* o = position; position = i;
-          schema->append(&parse_value_schema(p));
-          position = o;
-        }
-        // 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;
-          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
-          Expression_Obj interp_node = Parser::from_token(Token(p+2, j), ctx, pstate, source).parse_list(DELAYED);
-          interp_node->is_interpolant(true);
-          schema->append(interp_node);
-          // schema->has_interpolants(true);
-          i = j;
-        }
-        else {
-          // throw an error if the interpolant is unterminated
-          error("unterminated interpolant inside interpolated identifier " + id.to_string(), pstate);
-        }
-      }
-      else { // no interpolants left; add the last segment if nonempty
-        if (i < end) {
-          const char* o = position; position = i;
-          schema->append(&parse_value_schema(id.end));
-          position = o;
-        }
-        break;
-      }
-    }
-    return schema ? schema.detach() : 0;
-  }
-
-  // calc functions should preserve arguments
-  Function_Call_Obj Parser::parse_calc_function()
-  {
-    lex< identifier >();
-    std::string name(lexed);
-    ParserState call_pos = pstate;
-    lex< exactly<'('> >();
-    ParserState arg_pos = pstate;
-    const char* arg_beg = position;
-    parse_list();
-    const char* arg_end = position;
-    lex< skip_over_scopes <
-          exactly < '(' >,
-          exactly < ')' >
-        > >();
-
-    Argument_Obj arg = SASS_MEMORY_NEW(Argument, arg_pos, &parse_interpolated_chunk(Token(arg_beg, arg_end)));
-    Arguments_Obj args = SASS_MEMORY_NEW(Arguments, arg_pos);
-    args->append(&arg);
-    return SASS_MEMORY_NEW(Function_Call, call_pos, name, args);
-  }
-
-  String_Obj Parser::parse_url_function_string()
-  {
-    std::string prefix("");
-    if (lex< uri_prefix >()) {
-      prefix = std::string(lexed);
-    }
-
-    lex < optional_spaces >();
-    String_Obj url_string = parse_url_function_argument();
-
-    std::string suffix("");
-    if (lex< real_uri_suffix >()) {
-      suffix = std::string(lexed);
-    }
-
-    std::string uri("");
-    if (&url_string) {
-      uri = url_string->to_string({ NESTED, 5 });
-    }
-
-    if (String_Schema_Ptr schema = dynamic_cast<String_Schema_Ptr>(&url_string)) {
-      String_Schema_Obj res = SASS_MEMORY_NEW(String_Schema, pstate);
-      res->append(SASS_MEMORY_NEW(String_Constant, pstate, prefix));
-      res->append(schema);
-      res->append(SASS_MEMORY_NEW(String_Constant, pstate, suffix));
-      return &res;
-    } else {
-      std::string res = prefix + uri + suffix;
-      return SASS_MEMORY_NEW(String_Constant, pstate, res);
-    }
-  }
-
-  String_Obj Parser::parse_url_function_argument()
-  {
-    const char* p = position;
-
-    std::string uri("");
-    if (lex< real_uri_value >(false)) {
-      uri = lexed.to_string();
-    }
-
-    if (peek< exactly< hash_lbrace > >()) {
-      const char* pp = position;
-      // TODO: error checking for unclosed interpolants
-      while (pp && peek< exactly< hash_lbrace > >(pp)) {
-        pp = sequence< interpolant, real_uri_value >(pp);
-      }
-      position = pp;
-      return &parse_interpolated_chunk(Token(p, position));
-    }
-    else if (uri != "") {
-      std::string res = Util::rtrim(uri);
-      return SASS_MEMORY_NEW(String_Constant, pstate, res);
-    }
-
-    return 0;
-  }
-
-  Function_Call_Obj Parser::parse_function_call()
-  {
-    lex< identifier >();
-    std::string name(lexed);
-
-    ParserState call_pos = pstate;
-    Arguments_Obj args = parse_arguments();
-    return SASS_MEMORY_NEW(Function_Call, call_pos, name, args);
-  }
-
-  Function_Call_Schema_Obj Parser::parse_function_call_schema()
-  {
-    String_Obj name = parse_identifier_schema();
-    ParserState source_position_of_call = pstate;
-    Arguments_Obj args = parse_arguments();
-
-    return SASS_MEMORY_NEW(Function_Call_Schema, source_position_of_call, name, args);
-  }
-
-  Content_Obj Parser::parse_content_directive()
-  {
-    return SASS_MEMORY_NEW(Content, pstate);
-  }
-
-  If_Obj Parser::parse_if_directive(bool else_if)
-  {
-    stack.push_back(Scope::Control);
-    ParserState if_source_position = pstate;
-    bool root = block_stack.back()->is_root();
-    Expression_Obj predicate = parse_list();
-    Block_Obj block = parse_block(root);
-    Block_Obj alternative = NULL;
-
-    // only throw away comment if we parse a case
-    // we want all other comments to be parsed
-    if (lex_css< elseif_directive >()) {
-      alternative = SASS_MEMORY_NEW(Block, pstate);
-      alternative->append(&parse_if_directive(true));
-    }
-    else if (lex_css< kwd_else_directive >()) {
-      alternative = &parse_block(root);
-    }
-    stack.pop_back();
-    return SASS_MEMORY_NEW(If, if_source_position, predicate, block, alternative);
-  }
-
-  For_Obj Parser::parse_for_directive()
-  {
-    stack.push_back(Scope::Control);
-    ParserState for_source_position = pstate;
-    bool root = block_stack.back()->is_root();
-    lex_variable();
-    std::string var(Util::normalize_underscores(lexed));
-    if (!lex< kwd_from >()) error("expected 'from' keyword in @for directive", pstate);
-    Expression_Obj lower_bound = parse_expression();
-    bool inclusive = false;
-    if (lex< kwd_through >()) inclusive = true;
-    else if (lex< kwd_to >()) inclusive = false;
-    else                  error("expected 'through' or 'to' keyword in @for directive", pstate);
-    Expression_Obj upper_bound = parse_expression();
-    Block_Obj body = parse_block(root);
-    stack.pop_back();
-    return SASS_MEMORY_NEW(For, for_source_position, var, lower_bound, upper_bound, body, inclusive);
-  }
-
-  // helper to parse a var token
-  Token Parser::lex_variable()
-  {
-    // peek for dollar sign first
-    if (!peek< exactly <'$'> >()) {
-      css_error("Invalid CSS", " after ", ": expected \"$\", was ");
-    }
-    // we expect a simple identifier as the call name
-    if (!lex< sequence < exactly <'$'>, identifier > >()) {
-      lex< exactly <'$'> >(); // move pstate and position up
-      css_error("Invalid CSS", " after ", ": expected identifier, was ");
-    }
-    // return object
-    return token;
-  }
-  // helper to parse identifier
-  Token Parser::lex_identifier()
-  {
-    // we expect a simple identifier as the call name
-    if (!lex< identifier >()) { // ToDo: pstate wrong?
-      css_error("Invalid CSS", " after ", ": expected identifier, was ");
-    }
-    // return object
-    return token;
-  }
-
-  Each_Obj Parser::parse_each_directive()
-  {
-    stack.push_back(Scope::Control);
-    ParserState each_source_position = pstate;
-    bool root = block_stack.back()->is_root();
-    std::vector<std::string> vars;
-    lex_variable();
-    vars.push_back(Util::normalize_underscores(lexed));
-    while (lex< exactly<','> >()) {
-      if (!lex< variable >()) error("@each directive requires an iteration variable", pstate);
-      vars.push_back(Util::normalize_underscores(lexed));
-    }
-    if (!lex< kwd_in >()) error("expected 'in' keyword in @each directive", pstate);
-    Expression_Obj list = parse_list();
-    Block_Obj body = parse_block(root);
-    stack.pop_back();
-    return SASS_MEMORY_NEW(Each, each_source_position, vars, list, body);
-  }
-
-  // called after parsing `kwd_while_directive`
-  While_Obj Parser::parse_while_directive()
-  {
-    stack.push_back(Scope::Control);
-    bool root = block_stack.back()->is_root();
-    // create the initial while call object
-    While_Obj call = SASS_MEMORY_NEW(While, pstate, 0, 0);
-    // parse mandatory predicate
-    Expression_Obj predicate = parse_list();
-    call->predicate(predicate);
-    // parse mandatory block
-    call->block(parse_block(root));
-    // return ast node
-    stack.pop_back();
-    // return ast node
-    return call.detach();
-  }
-
-  // EO parse_while_directive
-  Media_Block_Obj Parser::parse_media_block()
-  {
-    stack.push_back(Scope::Media);
-    Media_Block_Obj media_block = SASS_MEMORY_NEW(Media_Block, pstate, 0, 0);
-
-    media_block->media_queries(parse_media_queries());
-
-    Media_Block_Obj prev_media_block = last_media_block;
-    last_media_block = &media_block;
-    media_block->block(parse_css_block());
-    last_media_block = &prev_media_block;
-    stack.pop_back();
-    return media_block.detach();
-  }
-
-  List_Obj Parser::parse_media_queries()
-  {
-    advanceToNextToken();
-    List_Obj queries = SASS_MEMORY_NEW(List, pstate, 0, SASS_COMMA);
-    if (!peek_css < exactly <'{'> >()) queries->append(&parse_media_query());
-    while (lex_css < exactly <','> >()) queries->append(&parse_media_query());
-    queries->update_pstate(pstate);
-    return queries.detach();
-  }
-
-  // Expression_Ptr Parser::parse_media_query()
-  Media_Query_Obj Parser::parse_media_query()
-  {
-    advanceToNextToken();
-    Media_Query_Obj media_query = SASS_MEMORY_NEW(Media_Query, pstate);
-    if (lex < kwd_not >()) { media_query->is_negated(true); lex < css_comments >(false); }
-    else if (lex < kwd_only >()) { media_query->is_restricted(true); lex < css_comments >(false); }
-
-    if (lex < identifier_schema >())  media_query->media_type(&parse_identifier_schema());
-    else if (lex < identifier >())    media_query->media_type(&parse_interpolated_chunk(lexed));
-    else                             media_query->append(&parse_media_expression());
-
-    while (lex_css < kwd_and >()) media_query->append(&parse_media_expression());
-    if (lex < identifier_schema >()) {
-      String_Schema_Ptr schema = SASS_MEMORY_NEW(String_Schema, pstate);
-      schema->append(&media_query->media_type());
-      schema->append(SASS_MEMORY_NEW(String_Constant, pstate, " "));
-      schema->append(&parse_identifier_schema());
-      media_query->media_type(schema);
-    }
-    while (lex_css < kwd_and >()) media_query->append(&parse_media_expression());
-
-    media_query->update_pstate(pstate);
-
-    return media_query;
-  }
-
-  Media_Query_Expression_Obj Parser::parse_media_expression()
-  {
-    if (lex < identifier_schema >()) {
-      String_Obj ss = parse_identifier_schema();
-      return SASS_MEMORY_NEW(Media_Query_Expression, pstate, &ss, 0, true);
-    }
-    if (!lex_css< exactly<'('> >()) {
-      error("media query expression must begin with '('", pstate);
-    }
-    Expression_Obj feature = 0;
-    if (peek_css< exactly<')'> >()) {
-      error("media feature required in media query expression", pstate);
-    }
-    feature = &parse_expression();
-    Expression_Obj expression = 0;
-    if (lex_css< exactly<':'> >()) {
-      expression = &parse_list(DELAYED);
-    }
-    if (!lex_css< exactly<')'> >()) {
-      error("unclosed parenthesis in media query expression", pstate);
-    }
-    return SASS_MEMORY_NEW(Media_Query_Expression, feature->pstate(), feature, expression);
-  }
-
-  // lexed after `kwd_supports_directive`
-  // these are very similar to media blocks
-  Supports_Block_Obj Parser::parse_supports_directive()
-  {
-    Supports_Condition_Obj cond = parse_supports_condition();
-    // create the ast node object for the support queries
-    Supports_Block_Obj query = SASS_MEMORY_NEW(Supports_Block, pstate, cond);
-    // additional block is mandatory
-    // parse inner block
-    query->block(parse_block());
-    // return ast node
-    return query;
-  }
-
-  // parse one query operation
-  // may encounter nested queries
-  Supports_Condition_Obj Parser::parse_supports_condition()
-  {
-    lex < css_whitespace >();
-    Supports_Condition_Obj cond = 0;
-    if ((cond = parse_supports_negation())) return cond;
-    if ((cond = parse_supports_operator())) return cond;
-    if ((cond = parse_supports_interpolation())) return cond;
-    return cond;
-  }
-
-  Supports_Condition_Obj Parser::parse_supports_negation()
-  {
-    if (!lex < kwd_not >()) return 0;
-    Supports_Condition_Obj cond = parse_supports_condition_in_parens();
-    return SASS_MEMORY_NEW(Supports_Negation, pstate, &cond);
-  }
-
-  Supports_Condition_Obj Parser::parse_supports_operator()
-  {
-    Supports_Condition_Obj cond = parse_supports_condition_in_parens();
-    if (!&cond) return 0;
-
-    while (true) {
-      Supports_Operator::Operand op = Supports_Operator::OR;
-      if (lex < kwd_and >()) { op = Supports_Operator::AND; }
-      else if(!lex < kwd_or >()) { break; }
-
-      lex < css_whitespace >();
-      Supports_Condition_Obj right = parse_supports_condition_in_parens();
-
-      // Supports_Condition_Ptr cc = SASS_MEMORY_NEW(Supports_Condition, *static_cast<Supports_Condition_Ptr>(cond));
-      cond = SASS_MEMORY_NEW(Supports_Operator, pstate, &cond, &right, op);
-    }
-    return cond;
-  }
-
-  Supports_Condition_Obj Parser::parse_supports_interpolation()
-  {
-    if (!lex < interpolant >()) return 0;
-
-    String_Obj interp = parse_interpolated_chunk(lexed);
-    if (!interp) return 0;
-
-    return SASS_MEMORY_NEW(Supports_Interpolation, pstate, &interp);
-  }
-
-  // TODO: This needs some major work. Although feature conditions
-  // look like declarations their semantics differ significantly
-  Supports_Condition_Obj Parser::parse_supports_declaration()
-  {
-    Supports_Condition_Ptr cond = 0;
-    // parse something declaration like
-    Declaration_Obj declaration = parse_declaration();
-    if (!declaration) error("@supports condition expected declaration", pstate);
-    cond = SASS_MEMORY_NEW(Supports_Declaration,
-                     declaration->pstate(),
-                     &declaration->property(),
-                     declaration->value());
-    // ToDo: maybe we need an additional error condition?
-    return cond;
-  }
-
-  Supports_Condition_Obj Parser::parse_supports_condition_in_parens()
-  {
-    Supports_Condition_Obj interp = parse_supports_interpolation();
-    if (&interp != 0) return interp;
-
-    if (!lex < exactly <'('> >()) return 0;
-    lex < css_whitespace >();
-
-    Supports_Condition_Obj cond = parse_supports_condition();
-    if (&cond != 0) {
-      if (!lex < exactly <')'> >()) error("unclosed parenthesis in @supports declaration", pstate);
-    } else {
-      cond = parse_supports_declaration();
-      if (!lex < exactly <')'> >()) error("unclosed parenthesis in @supports declaration", pstate);
-    }
-    lex < css_whitespace >();
-    return cond;
-  }
-
-  At_Root_Block_Obj Parser::parse_at_root_block()
-  {
-    ParserState at_source_position = pstate;
-    Block_Obj body = 0;
-    At_Root_Query_Obj expr;
-    Lookahead lookahead_result;
-    LOCAL_FLAG(in_at_root, true);
-    if (lex_css< exactly<'('> >()) {
-      expr = parse_at_root_query();
-    }
-    if (peek_css < exactly<'{'> >()) {
-      lex <optional_spaces>();
-      body = &parse_block(true);
-    }
-    else if ((lookahead_result = lookahead_for_selector(position)).found) {
-      Ruleset_Obj r = parse_ruleset(lookahead_result, false);
-      body = SASS_MEMORY_NEW(Block, r->pstate(), 1, true);
-      body->append(&r);
-    }
-    At_Root_Block_Obj at_root = SASS_MEMORY_NEW(At_Root_Block, at_source_position, body);
-    if (&expr) at_root->expression(&expr);
-    return at_root;
-  }
-
-  At_Root_Query_Obj Parser::parse_at_root_query()
-  {
-    if (peek< exactly<')'> >()) error("at-root feature required in at-root expression", pstate);
-
-    if (!peek< alternatives< kwd_with_directive, kwd_without_directive > >()) {
-      css_error("Invalid CSS", " after ", ": expected \"with\" or \"without\", was ");
-    }
-
-    Expression_Obj feature = parse_list();
-    if (!lex_css< exactly<':'> >()) error("style declaration must contain a value", pstate);
-    Expression_Obj expression = parse_list();
-    List_Obj value = SASS_MEMORY_NEW(List, feature->pstate(), 1);
-
-    if (expression->concrete_type() == Expression::LIST) {
-        value = SASS_MEMORY_CAST(List, expression);
-    }
-    else value->append(expression);
-
-    At_Root_Query_Obj cond = SASS_MEMORY_NEW(At_Root_Query,
-                                          value->pstate(),
-                                          feature,
-                                          &value);
-    if (!lex_css< exactly<')'> >()) error("unclosed parenthesis in @at-root expression", pstate);
-    return cond;
-  }
-
-  Directive_Obj Parser::parse_special_directive()
-  {
-    std::string kwd(lexed);
-
-    if (lexed == "@else") error("Invalid CSS: @else must come after @if", pstate);
-
-    Directive_Ptr at_rule = SASS_MEMORY_NEW(Directive, pstate, kwd);
-    Lookahead lookahead = lookahead_for_include(position);
-    if (lookahead.found && !lookahead.has_interpolants) {
-      at_rule->selector(&parse_selector_list(true));
-    }
-
-    lex < css_comments >(false);
-
-    if (lex < static_property >()) {
-      at_rule->value(&parse_interpolated_chunk(Token(lexed)));
-    } else if (!(peek < alternatives < exactly<'{'>, exactly<'}'>, exactly<';'> > >())) {
-      at_rule->value(parse_list());
-    }
-
-    lex < css_comments >(false);
-
-    if (peek< exactly<'{'> >()) {
-      at_rule->block(parse_block());
-    }
-
-    return at_rule;
-  }
-
-  Directive_Obj Parser::parse_prefixed_directive()
-  {
-    std::string kwd(lexed);
-
-    if (lexed == "@else") error("Invalid CSS: @else must come after @if", pstate);
-
-    Directive_Obj at_rule = SASS_MEMORY_NEW(Directive, pstate, kwd);
-    Lookahead lookahead = lookahead_for_include(position);
-    if (lookahead.found && !lookahead.has_interpolants) {
-      at_rule->selector(&parse_selector_list(true));
-    }
-
-    lex < css_comments >(false);
-
-    if (lex < static_property >()) {
-      at_rule->value(&parse_interpolated_chunk(Token(lexed)));
-    } else if (!(peek < alternatives < exactly<'{'>, exactly<'}'>, exactly<';'> > >())) {
-      at_rule->value(&parse_list());
-    }
-
-    lex < css_comments >(false);
-
-    if (peek< exactly<'{'> >()) {
-      at_rule->block(parse_block());
-    }
-
-    return at_rule;
-  }
-
-
-  Directive_Obj Parser::parse_directive()
-  {
-    Directive_Obj directive = SASS_MEMORY_NEW(Directive, pstate, lexed);
-    String_Schema_Obj val = parse_almost_any_value();
-    // strip left and right if they are of type string
-    directive->value(&val);
-    if (peek< exactly<'{'> >()) {
-      directive->block(parse_block());
-    }
-    return directive;
-  }
-
-  Expression_Obj Parser::lex_interpolation()
-  {
-    if (lex < interpolant >(true) != NULL) {
-      return &parse_interpolated_chunk(lexed, true);
-    }
-    return 0;
-  }
-
-  Expression_Obj Parser::lex_interp_uri()
-  {
-    // create a string schema by lexing optional interpolations
-    return lex_interp< re_string_uri_open, re_string_uri_close >();
-  }
-
-  Expression_Obj Parser::lex_interp_string()
-  {
-    Expression_Obj rv = 0;
-    if ((rv = lex_interp< re_string_double_open, re_string_double_close >())) return rv;
-    if ((rv = lex_interp< re_string_single_open, re_string_single_close >())) return rv;
-    return rv;
-  }
-
-  Expression_Obj Parser::lex_almost_any_value_chars()
-  {
-    const char* match =
-    lex <
-      one_plus <
-        alternatives <
-          sequence <
-            exactly <'\\'>,
-            any_char
-          >,
-          sequence <
-            negate <
-              sequence <
-                exactly < url_kwd >,
-                exactly <'('>
-              >
-            >,
-            neg_class_char <
-              almost_any_value_class
-            >
-          >,
-          sequence <
-            exactly <'/'>,
-            negate <
-              alternatives <
-                exactly <'/'>,
-                exactly <'*'>
-              >
-            >
-          >,
-          sequence <
-            exactly <'\\'>,
-            exactly <'#'>,
-            negate <
-              exactly <'{'>
-            >
-          >,
-          sequence <
-            exactly <'!'>,
-            negate <
-              alpha
-            >
-          >
-        >
-      >
-    >(false);
-    if (match) {
-      return SASS_MEMORY_NEW(String_Constant, pstate, lexed);
-    }
-    return NULL;
-  }
-
-  Expression_Obj Parser::lex_almost_any_value_token()
-  {
-    Expression_Obj rv = 0;
-    if (*position == 0) return 0;
-    if ((rv = &lex_almost_any_value_chars())) return rv;
-    // if ((rv = lex_block_comment())) return rv;
-    // if ((rv = lex_single_line_comment())) return rv;
-    if ((rv = &lex_interp_string())) return rv;
-    if ((rv = &lex_interp_uri())) return rv;
-    if ((rv = &lex_interpolation())) return rv;
-    return rv;
-  }
-
-  String_Schema_Obj Parser::parse_almost_any_value()
-  {
-
-    String_Schema_Obj schema = SASS_MEMORY_NEW(String_Schema, pstate);
-    if (*position == 0) return 0;
-    lex < spaces >(false);
-    Expression_Obj token = lex_almost_any_value_token();
-    if (!token) return 0;
-    schema->append(token);
-    if (*position == 0) {
-      schema->rtrim();
-      return schema.detach();
-    }
-
-    while ((token = &lex_almost_any_value_token())) {
-      schema->append(token);
-    }
-
-    lex < css_whitespace >();
-
-    schema->rtrim();
-
-    return schema.detach();
-  }
-
-  Warning_Obj Parser::parse_warning()
-  {
-    if (stack.back() != Scope::Root &&
-        stack.back() != Scope::Function &&
-        stack.back() != Scope::Mixin &&
-        stack.back() != Scope::Control &&
-        stack.back() != Scope::Rules) {
-      error("Illegal nesting: Only properties may be nested beneath properties.", pstate);
-    }
-    return SASS_MEMORY_NEW(Warning, pstate, parse_list(DELAYED));
-  }
-
-  Error_Obj Parser::parse_error()
-  {
-    if (stack.back() != Scope::Root &&
-        stack.back() != Scope::Function &&
-        stack.back() != Scope::Mixin &&
-        stack.back() != Scope::Control &&
-        stack.back() != Scope::Rules) {
-      error("Illegal nesting: Only properties may be nested beneath properties.", pstate);
-    }
-    return SASS_MEMORY_NEW(Error, pstate, parse_list(DELAYED));
-  }
-
-  Debug_Obj Parser::parse_debug()
-  {
-    if (stack.back() != Scope::Root &&
-        stack.back() != Scope::Function &&
-        stack.back() != Scope::Mixin &&
-        stack.back() != Scope::Control &&
-        stack.back() != Scope::Rules) {
-      error("Illegal nesting: Only properties may be nested beneath properties.", pstate);
-    }
-    return SASS_MEMORY_NEW(Debug, pstate, parse_list(DELAYED));
-  }
-
-  Return_Obj Parser::parse_return_directive()
-  {
-    // check that we do not have an empty list (ToDo: check if we got all cases)
-    if (peek_css < alternatives < exactly < ';' >, exactly < '}' >, end_of_file > >())
-    { css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was "); }
-    return SASS_MEMORY_NEW(Return, pstate, &parse_list());
-  }
-
-  Lookahead Parser::lookahead_for_selector(const char* start)
-  {
-    // init result struct
-    Lookahead rv = Lookahead();
-    // get start position
-    const char* p = start ? start : position;
-    // match in one big "regex"
-    rv.error = p;
-    if (const char* q =
-      peek <
-        re_selector_list
-      >(p)
-    ) {
-      while (p < q) {
-        // did we have interpolations?
-        if (*p == '#' && *(p+1) == '{') {
-          rv.has_interpolants = true;
-          p = q; break;
-        }
-        ++ p;
-      }
-      // store anyway  }
-
-
-      // ToDo: remove
-      rv.error = q;
-      rv.position = q;
-      // check expected opening bracket
-      // only after successfull matching
-      if (peek < exactly<'{'> >(q)) rv.found = q;
-      else if (peek < exactly<'('> >(q)) rv.found = q;
-      // else if (peek < exactly<';'> >(q)) rv.found = q;
-      // else if (peek < exactly<'}'> >(q)) rv.found = q;
-      if (rv.found || *p == 0) rv.error = 0;
-    }
-
-    rv.parsable = ! rv.has_interpolants;
-
-    // return result
-    return rv;
-
-  }
-  // EO lookahead_for_selector
-
-  // used in parse_block_nodes and parse_special_directive
-  // ToDo: actual usage is still not really clear to me?
-  Lookahead Parser::lookahead_for_include(const char* start)
-  {
-    // we actually just lookahead for a selector
-    Lookahead rv = lookahead_for_selector(start);
-    // but the "found" rules are different
-    if (const char* p = rv.position) {
-      // check for additional abort condition
-      if (peek < exactly<';'> >(p)) rv.found = p;
-      else if (peek < exactly<'}'> >(p)) rv.found = p;
-    }
-    // return result
-    return rv;
-  }
-  // EO lookahead_for_include
-
-  // look ahead for a token with interpolation in it
-  // we mostly use the result if there is an interpolation
-  // everything that passes here gets parsed as one schema
-  // meaning it will not be parsed as a space separated list
-  Lookahead Parser::lookahead_for_value(const char* start)
-  {
-    // init result struct
-    Lookahead rv = Lookahead();
-    // get start position
-    const char* p = start ? start : position;
-    // match in one big "regex"
-    if (const char* q =
-      peek <
-        non_greedy <
-          alternatives <
-            // consume whitespace
-            block_comment, // spaces,
-            // main tokens
-            sequence <
-              interpolant,
-              optional <
-                quoted_string
-              >
-            >,
-            identifier,
-            variable,
-            // issue #442
-            sequence <
-              parenthese_scope,
-              interpolant,
-              optional <
-                quoted_string
-              >
-            >
-          >,
-          sequence <
-            // optional_spaces,
-            alternatives <
-              exactly<'{'>,
-              exactly<'}'>,
-              exactly<';'>
-            >
-          >
-        >
-      >(p)
-    ) {
-      if (p == q) return rv;
-      while (p < q) {
-        // did we have interpolations?
-        if (*p == '#' && *(p+1) == '{') {
-          rv.has_interpolants = true;
-          p = q; break;
-        }
-        ++ p;
-      }
-      // store anyway
-      // ToDo: remove
-      rv.position = q;
-      // check expected opening bracket
-      // only after successful matching
-      if (peek < exactly<'{'> >(q)) rv.found = q;
-      else if (peek < exactly<';'> >(q)) rv.found = q;
-      else if (peek < exactly<'}'> >(q)) rv.found = q;
-    }
-
-    // return result
-    return rv;
-  }
-  // EO lookahead_for_value
-
-  void Parser::read_bom()
-  {
-    size_t skip = 0;
-    std::string encoding;
-    bool utf_8 = false;
-    switch ((unsigned char) source[0]) {
-    case 0xEF:
-      skip = check_bom_chars(source, end, utf_8_bom, 3);
-      encoding = "UTF-8";
-      utf_8 = true;
-      break;
-    case 0xFE:
-      skip = check_bom_chars(source, end, utf_16_bom_be, 2);
-      encoding = "UTF-16 (big endian)";
-      break;
-    case 0xFF:
-      skip = check_bom_chars(source, end, utf_16_bom_le, 2);
-      skip += (skip ? check_bom_chars(source, end, utf_32_bom_le, 4) : 0);
-      encoding = (skip == 2 ? "UTF-16 (little endian)" : "UTF-32 (little endian)");
-      break;
-    case 0x00:
-      skip = check_bom_chars(source, end, utf_32_bom_be, 4);
-      encoding = "UTF-32 (big endian)";
-      break;
-    case 0x2B:
-      skip = check_bom_chars(source, end, utf_7_bom_1, 4)
-           | check_bom_chars(source, end, utf_7_bom_2, 4)
-           | check_bom_chars(source, end, utf_7_bom_3, 4)
-           | check_bom_chars(source, end, utf_7_bom_4, 4)
-           | check_bom_chars(source, end, utf_7_bom_5, 5);
-      encoding = "UTF-7";
-      break;
-    case 0xF7:
-      skip = check_bom_chars(source, end, utf_1_bom, 3);
-      encoding = "UTF-1";
-      break;
-    case 0xDD:
-      skip = check_bom_chars(source, end, utf_ebcdic_bom, 4);
-      encoding = "UTF-EBCDIC";
-      break;
-    case 0x0E:
-      skip = check_bom_chars(source, end, scsu_bom, 3);
-      encoding = "SCSU";
-      break;
-    case 0xFB:
-      skip = check_bom_chars(source, end, bocu_1_bom, 3);
-      encoding = "BOCU-1";
-      break;
-    case 0x84:
-      skip = check_bom_chars(source, end, gb_18030_bom, 4);
-      encoding = "GB-18030";
-      break;
-    }
-    if (skip > 0 && !utf_8) error("only UTF-8 documents are currently supported; your document appears to be " + encoding, pstate);
-    position += skip;
-  }
-
-  size_t check_bom_chars(const char* src, const char *end, const unsigned char* bom, size_t len)
-  {
-    size_t skip = 0;
-    if (src + len > end) return 0;
-    for (size_t i = 0; i < len; ++i, ++skip) {
-      if ((unsigned char) src[i] != bom[i]) return 0;
-    }
-    return skip;
-  }
-
-
-  Expression_Obj Parser::fold_operands(Expression_Obj base, std::vector<Expression_Obj>& operands, Operand op)
-  {
-    for (size_t i = 0, S = operands.size(); i < S; ++i) {
-      base = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), op, &base, operands[i]);
-    }
-    return base;
-  }
-
-  Expression_Obj Parser::fold_operands(Expression_Obj base, std::vector<Expression_Obj>& operands, std::vector<Operand>& ops, size_t i)
-  {
-    if (String_Schema_Ptr schema = dynamic_cast<String_Schema_Ptr>(&base)) {
-      // return schema;
-      if (schema->has_interpolants()) {
-        if (i + 1 < operands.size() && (
-             (ops[0].operand == Sass_OP::EQ)
-          || (ops[0].operand == Sass_OP::ADD)
-          || (ops[0].operand == Sass_OP::DIV)
-          || (ops[0].operand == Sass_OP::MUL)
-          || (ops[0].operand == Sass_OP::NEQ)
-          || (ops[0].operand == Sass_OP::LT)
-          || (ops[0].operand == Sass_OP::GT)
-          || (ops[0].operand == Sass_OP::LTE)
-          || (ops[0].operand == Sass_OP::GTE)
-        )) {
-          Expression_Obj rhs = fold_operands(operands[i], operands, ops, i + 1);
-          rhs = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), ops[0], schema, &rhs);
-          return rhs;
-        }
-        // return schema;
-      }
-    }
-
-    for (size_t S = operands.size(); i < S; ++i) {
-      if (String_Schema_Ptr schema = dynamic_cast<String_Schema_Ptr>(&operands[i])) {
-        if (schema->has_interpolants()) {
-          if (i + 1 < S) {
-            Expression_Obj rhs = fold_operands(operands[i+1], operands, ops, i + 2);
-            rhs = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), ops[i], schema, &rhs);
-            base = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), ops[i], &base, &rhs);
-            return base;
-          }
-          base = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), ops[i], &base, operands[i]);
-          return base;
-        } else {
-          base = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), ops[i], &base, operands[i]);
-        }
-      } else {
-        base = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), ops[i], &base, operands[i]);
-      }
-      Binary_Expression_Ptr b = static_cast<Binary_Expression_Ptr>(&base);
-      if (b && ops[i].operand == Sass_OP::DIV && b->left()->is_delayed() && b->right()->is_delayed()) {
-        base->is_delayed(true);
-      }
-    }
-    // nested binary expression are never to be delayed
-    if (Binary_Expression_Ptr b = dynamic_cast<Binary_Expression_Ptr>(&base)) {
-      if (SASS_MEMORY_CAST(Binary_Expression, b->left())) base->set_delayed(false);
-      if (SASS_MEMORY_CAST(Binary_Expression, b->right())) base->set_delayed(false);
-    }
-    return base;
-  }
-
-  void Parser::error(std::string msg, Position pos)
-  {
-    throw Exception::InvalidSass(ParserState(path, source, pos.line ? pos : before_token, Offset(0, 0)), msg);
-  }
-
-  // print a css parsing error with actual context information from parsed source
-  void Parser::css_error(const std::string& msg, const std::string& prefix, const std::string& middle)
-  {
-    int max_len = 18;
-    const char* end = this->end;
-    while (*end != 0) ++ end;
-    const char* pos = peek < optional_spaces >();
-
-    const char* last_pos(pos);
-    if (last_pos > source) {
-      utf8::prior(last_pos, source);
-    }
-    // backup position to last significant char
-    while (last_pos > source && last_pos < end) {
-      if (!Prelexer::is_space(*last_pos)) break;
-      utf8::prior(last_pos, source);
-    }
-
-    bool ellipsis_left = false;
-    const char* pos_left(last_pos);
-    const char* end_left(last_pos);
-
-    utf8::next(pos_left, end);
-    utf8::next(end_left, end);
-    while (pos_left > source) {
-      if (utf8::distance(pos_left, end_left) >= max_len) {
-        utf8::prior(pos_left, source);
-        ellipsis_left = *(pos_left) != '\n' &&
-                        *(pos_left) != '\r';
-        utf8::next(pos_left, end);
-        break;
-      }
-
-      const char* prev = pos_left;
-      utf8::prior(prev, source);
-      if (*prev == '\r') break;
-      if (*prev == '\n') break;
-      pos_left = prev;
-    }
-    if (pos_left < source) {
-      pos_left = source;
-    }
-
-    bool ellipsis_right = false;
-    const char* end_right(pos);
-    const char* pos_right(pos);
-    while (end_right < end) {
-      if (utf8::distance(pos_right, end_right) > max_len) {
-        ellipsis_left = *(pos_right) != '\n' &&
-                        *(pos_right) != '\r';
-        break;
-      }
-      if (*end_right == '\r') break;
-      if (*end_right == '\n') break;
-      utf8::next(end_right, end);
-    }
-    // if (*end_right == 0) end_right ++;
-
-    std::string left(pos_left, end_left);
-    std::string right(pos_right, end_right);
-    size_t left_subpos = left.size() > 15 ? left.size() - 15 : 0;
-    size_t right_subpos = right.size() > 15 ? right.size() - 15 : 0;
-    if (left_subpos && ellipsis_left) left = ellipsis + left.substr(left_subpos);
-    if (right_subpos && ellipsis_right) right = right.substr(right_subpos) + ellipsis;
-    // now pass new message to the more generic error function
-    error(msg + prefix + quote(left) + middle + quote(right), pstate);
+#include "parser.hpp"
+#include "file.hpp"
+#include "inspect.hpp"
+#include "constants.hpp"
+#include "util.hpp"
+#include "prelexer.hpp"
+#include "color_maps.hpp"
+#include "sass/functions.h"
+#include "error_handling.hpp"
+
+// Notes about delayed: some ast nodes can have delayed evaluation so
+// they can preserve their original semantics if needed. This is most
+// prominently exhibited by the division operation, since it is not
+// only a valid operation, but also a valid css statement (i.e. for
+// fonts, as in `16px/24px`). When parsing lists and expression we
+// unwrap single items from lists and other operations. A nested list
+// must not be delayed, only the items of the first level sometimes
+// are delayed (as with argument lists). To achieve this we need to
+// pass status to the list parser, so this can be set correctly.
+// Another case with delayed values are colors. In compressed mode
+// only processed values get compressed (other are left as written).
+
+#include <cstdlib>
+#include <iostream>
+#include <vector>
+#include <typeinfo>
+
+namespace Sass {
+  using namespace Constants;
+  using namespace Prelexer;
+
+  Parser Parser::from_c_str(const char* beg, Context& ctx, Backtraces traces, ParserState pstate, const char* source)
+  {
+    pstate.offset.column = 0;
+    pstate.offset.line = 0;
+    Parser p(ctx, pstate, traces);
+    p.source   = source ? source : beg;
+    p.position = beg ? beg : p.source;
+    p.end      = p.position + strlen(p.position);
+    Block_Obj root = SASS_MEMORY_NEW(Block, pstate);
+    p.block_stack.push_back(root);
+    root->is_root(true);
+    return p;
+  }
+
+  Parser Parser::from_c_str(const char* beg, const char* end, Context& ctx, Backtraces traces, ParserState pstate, const char* source)
+  {
+    pstate.offset.column = 0;
+    pstate.offset.line = 0;
+    Parser p(ctx, pstate, traces);
+    p.source   = source ? source : beg;
+    p.position = beg ? beg : p.source;
+    p.end      = end ? end : p.position + strlen(p.position);
+    Block_Obj root = SASS_MEMORY_NEW(Block, pstate);
+    p.block_stack.push_back(root);
+    root->is_root(true);
+    return p;
+  }
+
+   void Parser::advanceToNextToken() {
+      lex < css_comments >(false);
+      // advance to position
+      pstate += pstate.offset;
+      pstate.offset.column = 0;
+      pstate.offset.line = 0;
+    }
+
+  Selector_List_Obj Parser::parse_selector(const char* beg, Context& ctx, Backtraces traces, ParserState pstate, const char* source)
+  {
+    Parser p = Parser::from_c_str(beg, ctx, traces, pstate, source);
+    // ToDo: ruby sass errors on parent references
+    // ToDo: remap the source-map entries somehow
+    return p.parse_selector_list(false);
+  }
+
+  bool Parser::peek_newline(const char* start)
+  {
+    return peek_linefeed(start ? start : position)
+           && ! peek_css<exactly<'{'>>(start);
+  }
+
+  Parser Parser::from_token(Token t, Context& ctx, Backtraces traces, ParserState pstate, const char* source)
+  {
+    Parser p(ctx, pstate, traces);
+    p.source   = source ? source : t.begin;
+    p.position = t.begin ? t.begin : p.source;
+    p.end      = t.end ? t.end : p.position + strlen(p.position);
+    Block_Obj root = SASS_MEMORY_NEW(Block, pstate);
+    p.block_stack.push_back(root);
+    root->is_root(true);
+    return p;
+  }
+
+  /* main entry point to parse root block */
+  Block_Obj Parser::parse()
+  {
+
+    // consume unicode BOM
+    read_bom();
+
+    // scan the input to find invalid utf8 sequences
+    const char* it = utf8::find_invalid(position, end);
+
+    // report invalid utf8
+    if (it != end) {
+      pstate += Offset::init(position, it);
+      traces.push_back(Backtrace(pstate));
+      throw Exception::InvalidSass(pstate, traces, "Invalid UTF-8 sequence");
+    }
+
+    // create a block AST node to hold children
+    Block_Obj root = SASS_MEMORY_NEW(Block, pstate, 0, true);
+
+    // check seems a bit esoteric but works
+    if (ctx.resources.size() == 1) {
+      // apply headers only on very first include
+      ctx.apply_custom_headers(root, path, pstate);
+    }
+
+    // parse children nodes
+    block_stack.push_back(root);
+    parse_block_nodes(true);
+    block_stack.pop_back();
+
+    // update final position
+    root->update_pstate(pstate);
+
+    if (position != end) {
+      css_error("Invalid CSS", " after ", ": expected selector or at-rule, was ");
+    }
+
+    return root;
+  }
+
+
+  // convenience function for block parsing
+  // will create a new block ad-hoc for you
+  // this is the base block parsing function
+  Block_Obj Parser::parse_css_block(bool is_root)
+  {
+
+    // parse comments before block
+    // lex < optional_css_comments >();
+
+    // lex mandatory opener or error out
+    if (!lex_css < exactly<'{'> >()) {
+      css_error("Invalid CSS", " after ", ": expected \"{\", was ");
+    }
+    // create new block and push to the selector stack
+    Block_Obj block = SASS_MEMORY_NEW(Block, pstate, 0, is_root);
+    block_stack.push_back(block);
+
+    if (!parse_block_nodes(is_root)) css_error("Invalid CSS", " after ", ": expected \"}\", was ");
+
+    if (!lex_css < exactly<'}'> >()) {
+      css_error("Invalid CSS", " after ", ": expected \"}\", was ");
+    }
+
+    // update for end position
+    // this seems to be done somewhere else
+    // but that fixed selector schema issue
+    // block->update_pstate(pstate);
+
+    // parse comments after block
+    // lex < optional_css_comments >();
+
+    block_stack.pop_back();
+
+    return block;
+  }
+
+  // convenience function for block parsing
+  // will create a new block ad-hoc for you
+  // also updates the `in_at_root` flag
+  Block_Obj Parser::parse_block(bool is_root)
+  {
+    return parse_css_block(is_root);
+  }
+
+  // the main block parsing function
+  // parses stuff between `{` and `}`
+  bool Parser::parse_block_nodes(bool is_root)
+  {
+
+    // loop until end of string
+    while (position < end) {
+
+      // we should be able to refactor this
+      parse_block_comments();
+      lex < css_whitespace >();
+
+      if (lex < exactly<';'> >()) continue;
+      if (peek < end_of_file >()) return true;
+      if (peek < exactly<'}'> >()) return true;
+
+      if (parse_block_node(is_root)) continue;
+
+      parse_block_comments();
+
+      if (lex_css < exactly<';'> >()) continue;
+      if (peek_css < end_of_file >()) return true;
+      if (peek_css < exactly<'}'> >()) return true;
+
+      // illegal sass
+      return false;
+    }
+    // return success
+    return true;
+  }
+
+  // parser for a single node in a block
+  // semicolons must be lexed beforehand
+  bool Parser::parse_block_node(bool is_root) {
+
+    Block_Obj block = block_stack.back();
+
+    parse_block_comments();
+
+    // throw away white-space
+    // includes line comments
+    lex < css_whitespace >();
+
+    Lookahead lookahead_result;
+
+    // also parse block comments
+
+    // first parse everything that is allowed in functions
+    if (lex < variable >(true)) { block->append(parse_assignment()); }
+    else if (lex < kwd_err >(true)) { block->append(parse_error()); }
+    else if (lex < kwd_dbg >(true)) { block->append(parse_debug()); }
+    else if (lex < kwd_warn >(true)) { block->append(parse_warning()); }
+    else if (lex < kwd_if_directive >(true)) { block->append(parse_if_directive()); }
+    else if (lex < kwd_for_directive >(true)) { block->append(parse_for_directive()); }
+    else if (lex < kwd_each_directive >(true)) { block->append(parse_each_directive()); }
+    else if (lex < kwd_while_directive >(true)) { block->append(parse_while_directive()); }
+    else if (lex < kwd_return_directive >(true)) { block->append(parse_return_directive()); }
+
+    // parse imports to process later
+    else if (lex < kwd_import >(true)) {
+      Scope parent = stack.empty() ? Scope::Rules : stack.back();
+      if (parent != Scope::Function && parent != Scope::Root && parent != Scope::Rules && parent != Scope::Media) {
+        if (! peek_css< uri_prefix >(position)) { // this seems to go in ruby sass 3.4.20
+          error("Import directives may not be used within control directives or mixins.");
+        }
+      }
+      // this puts the parsed doc into sheets
+      // import stub will fetch this in expand
+      Import_Obj imp = parse_import();
+      // if it is a url, we only add the statement
+      if (!imp->urls().empty()) block->append(imp);
+      // process all resources now (add Import_Stub nodes)
+      for (size_t i = 0, S = imp->incs().size(); i < S; ++i) {
+        block->append(SASS_MEMORY_NEW(Import_Stub, pstate, imp->incs()[i]));
+      }
+    }
+
+    else if (lex < kwd_extend >(true)) {
+      Lookahead lookahead = lookahead_for_include(position);
+      if (!lookahead.found) css_error("Invalid CSS", " after ", ": expected selector, was ");
+      Selector_List_Obj target;
+      if (!lookahead.has_interpolants) {
+        target = parse_selector_list(true);
+      }
+      else {
+        target = SASS_MEMORY_NEW(Selector_List, pstate);
+        target->schema(parse_selector_schema(lookahead.found, true));
+      }
+
+      block->append(SASS_MEMORY_NEW(Extension, pstate, target));
+    }
+
+    // selector may contain interpolations which need delayed evaluation
+    else if (
+      !(lookahead_result = lookahead_for_selector(position)).error &&
+      !lookahead_result.is_custom_property
+    )
+    {
+      block->append(parse_ruleset(lookahead_result));
+    }
+
+    // parse multiple specific keyword directives
+    else if (lex < kwd_media >(true)) { block->append(parse_media_block()); }
+    else if (lex < kwd_at_root >(true)) { block->append(parse_at_root_block()); }
+    else if (lex < kwd_include_directive >(true)) { block->append(parse_include_directive()); }
+    else if (lex < kwd_content_directive >(true)) { block->append(parse_content_directive()); }
+    else if (lex < kwd_supports_directive >(true)) { block->append(parse_supports_directive()); }
+    else if (lex < kwd_mixin >(true)) { block->append(parse_definition(Definition::MIXIN)); }
+    else if (lex < kwd_function >(true)) { block->append(parse_definition(Definition::FUNCTION)); }
+
+    // ignore the @charset directive for now
+    else if (lex< kwd_charset_directive >(true)) { parse_charset_directive(); }
+
+    // generic at keyword (keep last)
+    else if (lex< re_special_directive >(true)) { block->append(parse_special_directive()); }
+    else if (lex< re_prefixed_directive >(true)) { block->append(parse_prefixed_directive()); }
+    else if (lex< at_keyword >(true)) { block->append(parse_directive()); }
+
+    else if (is_root && stack.back() != Scope::AtRoot /* && block->is_root() */) {
+      lex< css_whitespace >();
+      if (position >= end) return true;
+      css_error("Invalid CSS", " after ", ": expected 1 selector or at-rule, was ");
+    }
+    // parse a declaration
+    else
+    {
+      // ToDo: how does it handle parse errors?
+      // maybe we are expected to parse something?
+      Declaration_Obj decl = parse_declaration();
+      decl->tabs(indentation);
+      block->append(decl);
+      // maybe we have a "sub-block"
+      if (peek< exactly<'{'> >()) {
+        if (decl->is_indented()) ++ indentation;
+        // parse a propset that rides on the declaration's property
+        stack.push_back(Scope::Properties);
+        decl->block(parse_block());
+        stack.pop_back();
+        if (decl->is_indented()) -- indentation;
+      }
+    }
+    // something matched
+    return true;
+  }
+  // EO parse_block_nodes
+
+  // parse imports inside the
+  Import_Obj Parser::parse_import()
+  {
+    Import_Obj imp = SASS_MEMORY_NEW(Import, pstate);
+    std::vector<std::pair<std::string,Function_Call_Obj>> to_import;
+    bool first = true;
+    do {
+      while (lex< block_comment >());
+      if (lex< quoted_string >()) {
+        to_import.push_back(std::pair<std::string,Function_Call_Obj>(std::string(lexed), 0));
+      }
+      else if (lex< uri_prefix >()) {
+        Arguments_Obj args = SASS_MEMORY_NEW(Arguments, pstate);
+        Function_Call_Obj result = SASS_MEMORY_NEW(Function_Call, pstate, "url", args);
+
+        if (lex< quoted_string >()) {
+          Expression_Obj quoted_url = parse_string();
+          args->append(SASS_MEMORY_NEW(Argument, quoted_url->pstate(), quoted_url));
+        }
+        else if (String_Obj string_url = parse_url_function_argument()) {
+          args->append(SASS_MEMORY_NEW(Argument, string_url->pstate(), string_url));
+        }
+        else if (peek < skip_over_scopes < exactly < '(' >, exactly < ')' > > >(position)) {
+          Expression_Obj braced_url = parse_list(); // parse_interpolated_chunk(lexed);
+          args->append(SASS_MEMORY_NEW(Argument, braced_url->pstate(), braced_url));
+        }
+        else {
+          error("malformed URL");
+        }
+        if (!lex< exactly<')'> >()) error("URI is missing ')'");
+        to_import.push_back(std::pair<std::string, Function_Call_Obj>("", result));
+      }
+      else {
+        if (first) error("@import directive requires a url or quoted path");
+        else error("expecting another url or quoted path in @import list");
+      }
+      first = false;
+    } while (lex_css< exactly<','> >());
+
+    if (!peek_css< alternatives< exactly<';'>, exactly<'}'>, end_of_file > >()) {
+      List_Obj import_queries = parse_media_queries();
+      imp->import_queries(import_queries);
+    }
+
+    for(auto location : to_import) {
+      if (location.second) {
+        imp->urls().push_back(location.second);
+      }
+      // check if custom importers want to take over the handling
+      else if (!ctx.call_importers(unquote(location.first), path, pstate, imp)) {
+        // nobody wants it, so we do our import
+        ctx.import_url(imp, location.first, path);
+      }
+    }
+
+    return imp;
+  }
+
+  Definition_Obj Parser::parse_definition(Definition::Type which_type)
+  {
+    std::string which_str(lexed);
+    if (!lex< identifier >()) error("invalid name in " + which_str + " definition");
+    std::string name(Util::normalize_underscores(lexed));
+    if (which_type == Definition::FUNCTION && (name == "and" || name == "or" || name == "not"))
+    { error("Invalid function name \"" + name + "\"."); }
+    ParserState source_position_of_def = pstate;
+    Parameters_Obj params = parse_parameters();
+    if (which_type == Definition::MIXIN) stack.push_back(Scope::Mixin);
+    else stack.push_back(Scope::Function);
+    Block_Obj body = parse_block();
+    stack.pop_back();
+    return SASS_MEMORY_NEW(Definition, source_position_of_def, name, params, body, which_type);
+  }
+
+  Parameters_Obj Parser::parse_parameters()
+  {
+    Parameters_Obj params = SASS_MEMORY_NEW(Parameters, pstate);
+    if (lex_css< exactly<'('> >()) {
+      // if there's anything there at all
+      if (!peek_css< exactly<')'> >()) {
+        do {
+          if (peek< exactly<')'> >()) break;
+          params->append(parse_parameter());
+        } while (lex_css< exactly<','> >());
+      }
+      if (!lex_css< exactly<')'> >()) {
+        css_error("Invalid CSS", " after ", ": expected \")\", was ");
+      }
+    }
+    return params;
+  }
+
+  Parameter_Obj Parser::parse_parameter()
+  {
+    if (peek< alternatives< exactly<','>, exactly< '{' >, exactly<';'> > >()) {
+      css_error("Invalid CSS", " after ", ": expected variable (e.g. $foo), was ");
+    }
+    while (lex< alternatives < spaces, block_comment > >());
+    lex < variable >();
+    std::string name(Util::normalize_underscores(lexed));
+    ParserState pos = pstate;
+    Expression_Obj val;
+    bool is_rest = false;
+    while (lex< alternatives < spaces, block_comment > >());
+    if (lex< exactly<':'> >()) { // there's a default value
+      while (lex< block_comment >());
+      val = parse_space_list();
+    }
+    else if (lex< exactly< ellipsis > >()) {
+      is_rest = true;
+    }
+    return SASS_MEMORY_NEW(Parameter, pos, name, val, is_rest);
+  }
+
+  Arguments_Obj Parser::parse_arguments()
+  {
+    Arguments_Obj args = SASS_MEMORY_NEW(Arguments, pstate);
+    if (lex_css< exactly<'('> >()) {
+      // if there's anything there at all
+      if (!peek_css< exactly<')'> >()) {
+        do {
+          if (peek< exactly<')'> >()) break;
+          args->append(parse_argument());
+        } while (lex_css< exactly<','> >());
+      }
+      if (!lex_css< exactly<')'> >()) {
+        css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
+      }
+    }
+    return args;
+  }
+
+  Argument_Obj Parser::parse_argument()
+  {
+    if (peek< alternatives< exactly<','>, exactly< '{' >, exactly<';'> > >()) {
+      css_error("Invalid CSS", " after ", ": expected \")\", was ");
+    }
+    if (peek_css< sequence < exactly< hash_lbrace >, exactly< rbrace > > >()) {
+      position += 2;
+      css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
+    }
+
+    Argument_Obj arg;
+    if (peek_css< sequence < variable, optional_css_comments, exactly<':'> > >()) {
+      lex_css< variable >();
+      std::string name(Util::normalize_underscores(lexed));
+      ParserState p = pstate;
+      lex_css< exactly<':'> >();
+      Expression_Obj val = parse_space_list();
+      arg = SASS_MEMORY_NEW(Argument, p, val, name);
+    }
+    else {
+      bool is_arglist = false;
+      bool is_keyword = false;
+      Expression_Obj val = parse_space_list();
+      List_Ptr l = Cast<List>(val);
+      if (lex_css< exactly< ellipsis > >()) {
+        if (val->concrete_type() == Expression::MAP || (
+           (l != NULL && l->separator() == SASS_HASH)
+        )) is_keyword = true;
+        else is_arglist = true;
+      }
+      arg = SASS_MEMORY_NEW(Argument, pstate, val, "", is_arglist, is_keyword);
+    }
+    return arg;
+  }
+
+  Assignment_Obj Parser::parse_assignment()
+  {
+    std::string name(Util::normalize_underscores(lexed));
+    ParserState var_source_position = pstate;
+    if (!lex< exactly<':'> >()) error("expected ':' after " + name + " in assignment statement");
+    if (peek_css< alternatives < exactly<';'>, end_of_file > >()) {
+      css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
+    }
+    Expression_Obj val;
+    Lookahead lookahead = lookahead_for_value(position);
+    if (lookahead.has_interpolants && lookahead.found) {
+      val = parse_value_schema(lookahead.found);
+    } else {
+      val = parse_list();
+    }
+    bool is_default = false;
+    bool is_global = false;
+    while (peek< alternatives < default_flag, global_flag > >()) {
+      if (lex< default_flag >()) is_default = true;
+      else if (lex< global_flag >()) is_global = true;
+    }
+    return SASS_MEMORY_NEW(Assignment, var_source_position, name, val, is_default, is_global);
+  }
+
+  // a ruleset connects a selector and a block
+  Ruleset_Obj Parser::parse_ruleset(Lookahead lookahead)
+  {
+    NESTING_GUARD(nestings);
+    // inherit is_root from parent block
+    Block_Obj parent = block_stack.back();
+    bool is_root = parent && parent->is_root();
+    // make sure to move up the the last position
+    lex < optional_css_whitespace >(false, true);
+    // create the connector object (add parts later)
+    Ruleset_Obj ruleset = SASS_MEMORY_NEW(Ruleset, pstate);
+    // parse selector static or as schema to be evaluated later
+    if (lookahead.parsable) ruleset->selector(parse_selector_list(false));
+    else {
+      Selector_List_Obj list = SASS_MEMORY_NEW(Selector_List, pstate);
+      list->schema(parse_selector_schema(lookahead.position, false));
+      ruleset->selector(list);
+    }
+    // then parse the inner block
+    stack.push_back(Scope::Rules);
+    ruleset->block(parse_block());
+    stack.pop_back();
+    // update for end position
+    ruleset->update_pstate(pstate);
+    ruleset->block()->update_pstate(pstate);
+    // need this info for sanity checks
+    ruleset->is_root(is_root);
+    // return AST Node
+    return ruleset;
+  }
+
+  // parse a selector schema that will be evaluated in the eval stage
+  // uses a string schema internally to do the actual schema handling
+  // in the eval stage we will be re-parse it into an actual selector
+  Selector_Schema_Obj Parser::parse_selector_schema(const char* end_of_selector, bool chroot)
+  {
+    NESTING_GUARD(nestings);
+    // move up to the start
+    lex< optional_spaces >();
+    const char* i = position;
+    // selector schema re-uses string schema implementation
+    String_Schema_Ptr schema = SASS_MEMORY_NEW(String_Schema, pstate);
+    // the selector schema is pretty much just a wrapper for the string schema
+    Selector_Schema_Obj selector_schema = SASS_MEMORY_NEW(Selector_Schema, pstate, schema);
+    selector_schema->connect_parent(chroot == false);
+    selector_schema->media_block(last_media_block);
+
+    // process until end
+    while (i < end_of_selector) {
+      // try to parse mutliple interpolants
+      if (const char* p = find_first_in_interval< exactly<hash_lbrace>, block_comment >(i, end_of_selector)) {
+        // accumulate the preceding segment if the position has advanced
+        if (i < p) {
+          std::string parsed(i, p);
+          String_Constant_Obj str = SASS_MEMORY_NEW(String_Constant, pstate, parsed);
+          pstate += Offset(parsed);
+          str->update_pstate(pstate);
+          schema->append(str);
+        }
+
+        // skip over all nested inner interpolations up to our own delimiter
+        const char* j = skip_over_scopes< exactly<hash_lbrace>, exactly<rbrace> >(p + 2, end_of_selector);
+        // check if the interpolation never ends of only contains white-space (error out)
+        if (!j || peek < sequence < optional_spaces, exactly<rbrace> > >(p+2)) {
+          position = p+2;
+          css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
+        }
+        // pass inner expression to the parser to resolve nested interpolations
+        pstate.add(p, p+2);
+        Expression_Obj interpolant = Parser::from_c_str(p+2, j, ctx, traces, pstate).parse_list();
+        // set status on the list expression
+        interpolant->is_interpolant(true);
+        // schema->has_interpolants(true);
+        // add to the string schema
+        schema->append(interpolant);
+        // advance parser state
+        pstate.add(p+2, j);
+        // advance position
+        i = j;
+      }
+      // no more interpolants have been found
+      // add the last segment if there is one
+      else {
+        // make sure to add the last bits of the string up to the end (if any)
+        if (i < end_of_selector) {
+          std::string parsed(i, end_of_selector);
+          String_Constant_Obj str = SASS_MEMORY_NEW(String_Constant, pstate, parsed);
+          pstate += Offset(parsed);
+          str->update_pstate(pstate);
+          i = end_of_selector;
+          schema->append(str);
+        }
+        // exit loop
+      }
+    }
+    // EO until eos
+
+    // update position
+    position = i;
+
+    // update for end position
+    selector_schema->update_pstate(pstate);
+    schema->update_pstate(pstate);
+
+    after_token = before_token = pstate;
+
+    // return parsed result
+    return selector_schema.detach();
+  }
+  // EO parse_selector_schema
+
+  void Parser::parse_charset_directive()
+  {
+    lex <
+      sequence <
+        quoted_string,
+        optional_spaces,
+        exactly <';'>
+      >
+    >();
+  }
+
+  // called after parsing `kwd_include_directive`
+  Mixin_Call_Obj Parser::parse_include_directive()
+  {
+    // lex identifier into `lexed` var
+    lex_identifier(); // may error out
+    // normalize underscores to hyphens
+    std::string name(Util::normalize_underscores(lexed));
+    // create the initial mixin call object
+    Mixin_Call_Obj call = SASS_MEMORY_NEW(Mixin_Call, pstate, name, 0, 0);
+    // parse mandatory arguments
+    call->arguments(parse_arguments());
+    // parse optional block
+    if (peek < exactly <'{'> >()) {
+      call->block(parse_block());
+    }
+    // return ast node
+    return call.detach();
+  }
+  // EO parse_include_directive
+
+  // parse a list of complex selectors
+  // this is the main entry point for most
+  Selector_List_Obj Parser::parse_selector_list(bool chroot)
+  {
+    bool reloop;
+    bool had_linefeed = false;
+    NESTING_GUARD(nestings);
+    Complex_Selector_Obj sel;
+    Selector_List_Obj group = SASS_MEMORY_NEW(Selector_List, pstate);
+    group->media_block(last_media_block);
+
+    if (peek_css< alternatives < end_of_file, exactly <'{'>, exactly <','> > >()) {
+      css_error("Invalid CSS", " after ", ": expected selector, was ");
+    }
+
+    do {
+      reloop = false;
+
+      had_linefeed = had_linefeed || peek_newline();
+
+      if (peek_css< alternatives < class_char < selector_list_delims > > >())
+        break; // in case there are superfluous commas at the end
+
+      // now parse the complex selector
+      sel = parse_complex_selector(chroot);
+
+      if (!sel) return group.detach();
+
+      sel->has_line_feed(had_linefeed);
+
+      had_linefeed = false;
+
+      while (peek_css< exactly<','> >())
+      {
+        lex< css_comments >(false);
+        // consume everything up and including the comma separator
+        reloop = lex< exactly<','> >() != 0;
+        // remember line break (also between some commas)
+        had_linefeed = had_linefeed || peek_newline();
+        // remember line break (also between some commas)
+      }
+      group->append(sel);
+    }
+    while (reloop);
+    while (lex_css< kwd_optional >()) {
+      group->is_optional(true);
+    }
+    // update for end position
+    group->update_pstate(pstate);
+    if (sel) sel->last()->has_line_break(false);
+    return group.detach();
+  }
+  // EO parse_selector_list
+
+  // a complex selector combines a compound selector with another
+  // complex selector, with one of four combinator operations.
+  // the compound selector (head) is optional, since the combinator
+  // can come first in the whole selector sequence (like `> DIV').
+  Complex_Selector_Obj Parser::parse_complex_selector(bool chroot)
+  {
+
+    NESTING_GUARD(nestings);
+    String_Obj reference = 0;
+    lex < block_comment >();
+    advanceToNextToken();
+    Complex_Selector_Obj sel = SASS_MEMORY_NEW(Complex_Selector, pstate);
+
+    if (peek < end_of_file >()) return 0;
+
+    // parse the left hand side
+    Compound_Selector_Obj lhs;
+    // special case if it starts with combinator ([+~>])
+    if (!peek_css< class_char < selector_combinator_ops > >()) {
+      // parse the left hand side
+      lhs = parse_compound_selector();
+    }
+
+
+    // parse combinator between lhs and rhs
+    Complex_Selector::Combinator combinator = Complex_Selector::ANCESTOR_OF;
+    if      (lex< exactly<'+'> >()) combinator = Complex_Selector::ADJACENT_TO;
+    else if (lex< exactly<'~'> >()) combinator = Complex_Selector::PRECEDES;
+    else if (lex< exactly<'>'> >()) combinator = Complex_Selector::PARENT_OF;
+    else if (lex< sequence < exactly<'/'>, negate < exactly < '*' > > > >()) {
+      // comments are allowed, but not spaces?
+      combinator = Complex_Selector::REFERENCE;
+      if (!lex < re_reference_combinator >()) return 0;
+      reference = SASS_MEMORY_NEW(String_Constant, pstate, lexed);
+      if (!lex < exactly < '/' > >()) return 0; // ToDo: error msg?
+    }
+
+    if (!lhs && combinator == Complex_Selector::ANCESTOR_OF) return 0;
+
+    // lex < block_comment >();
+    sel->head(lhs);
+    sel->combinator(combinator);
+    sel->media_block(last_media_block);
+
+    if (combinator == Complex_Selector::REFERENCE) sel->reference(reference);
+    // has linfeed after combinator?
+    sel->has_line_break(peek_newline());
+    // sel->has_line_feed(has_line_feed);
+
+    // check if we got the abort condition (ToDo: optimize)
+    if (!peek_css< class_char < complex_selector_delims > >()) {
+      // parse next selector in sequence
+      sel->tail(parse_complex_selector(true));
+    }
+
+    // add a parent selector if we are not in a root
+    // also skip adding parent ref if we only have refs
+    if (!sel->has_parent_ref() && !chroot) {
+      // create the objects to wrap parent selector reference
+      Compound_Selector_Obj head = SASS_MEMORY_NEW(Compound_Selector, pstate);
+      Parent_Selector_Ptr parent = SASS_MEMORY_NEW(Parent_Selector, pstate, false);
+      parent->media_block(last_media_block);
+      head->media_block(last_media_block);
+      // add simple selector
+      head->append(parent);
+      // selector may not have any head yet
+      if (!sel->head()) { sel->head(head); }
+      // otherwise we need to create a new complex selector and set the old one as its tail
+      else {
+        sel = SASS_MEMORY_NEW(Complex_Selector, pstate, Complex_Selector::ANCESTOR_OF, head, sel);
+        sel->media_block(last_media_block);
+      }
+      // peek for linefeed and remember result on head
+      // if (peek_newline()) head->has_line_break(true);
+    }
+
+    sel->update_pstate(pstate);
+    // complex selector
+    return sel;
+  }
+  // EO parse_complex_selector
+
+  // parse one compound selector, which is basically
+  // a list of simple selectors (directly adjacent)
+  // lex them exactly (without skipping white-space)
+  Compound_Selector_Obj Parser::parse_compound_selector()
+  {
+    // init an empty compound selector wrapper
+    Compound_Selector_Obj seq = SASS_MEMORY_NEW(Compound_Selector, pstate);
+    seq->media_block(last_media_block);
+
+    // skip initial white-space
+    lex< css_whitespace >();
+
+    // parse list
+    while (true)
+    {
+      // remove all block comments (don't skip white-space)
+      lex< delimited_by< slash_star, star_slash, false > >(false);
+      // parse functional
+      if (match < re_pseudo_selector >())
+      {
+        seq->append(parse_simple_selector());
+      }
+      // parse parent selector
+      else if (lex< exactly<'&'> >(false))
+      {
+        // this produces a linefeed!?
+        seq->has_parent_reference(true);
+        seq->append(SASS_MEMORY_NEW(Parent_Selector, pstate));
+        // parent selector only allowed at start
+        // upcoming Sass may allow also trailing
+        if (seq->length() > 1) {
+          ParserState state(pstate);
+          Simple_Selector_Obj cur = (*seq)[seq->length()-1];
+          Simple_Selector_Obj prev = (*seq)[seq->length()-2];
+          std::string sel(prev->to_string({ NESTED, 5 }));
+          std::string found(cur->to_string({ NESTED, 5 }));
+          if (lex < identifier >()) { found += std::string(lexed); }
+          error("Invalid CSS after \"" + sel + "\": expected \"{\", was \"" + found + "\"\n\n"
+            "\"" + found + "\" may only be used at the beginning of a compound selector.", state);
+        }
+      }
+      // parse type selector
+      else if (lex< re_type_selector >(false))
+      {
+        seq->append(SASS_MEMORY_NEW(Element_Selector, pstate, lexed));
+      }
+      // peek for abort conditions
+      else if (peek< spaces >()) break;
+      else if (peek< end_of_file >()) { break; }
+      else if (peek_css < class_char < selector_combinator_ops > >()) break;
+      else if (peek_css < class_char < complex_selector_delims > >()) break;
+      // otherwise parse another simple selector
+      else {
+        Simple_Selector_Obj sel = parse_simple_selector();
+        if (!sel) return 0;
+        seq->append(sel);
+      }
+    }
+
+    if (seq && !peek_css<alternatives<end_of_file,exactly<'{'>>>()) {
+      seq->has_line_break(peek_newline());
+    }
+
+    // EO while true
+    return seq;
+
+  }
+  // EO parse_compound_selector
+
+  Simple_Selector_Obj Parser::parse_simple_selector()
+  {
+    lex < css_comments >(false);
+    if (lex< class_name >()) {
+      return SASS_MEMORY_NEW(Class_Selector, pstate, lexed);
+    }
+    else if (lex< id_name >()) {
+      return SASS_MEMORY_NEW(Id_Selector, pstate, lexed);
+    }
+    else if (lex< alternatives < variable, number, static_reference_combinator > >()) {
+      return SASS_MEMORY_NEW(Element_Selector, pstate, lexed);
+    }
+    else if (peek< pseudo_not >()) {
+      return parse_negated_selector();
+    }
+    else if (peek< re_pseudo_selector >()) {
+      return parse_pseudo_selector();
+    }
+    else if (peek< exactly<':'> >()) {
+      return parse_pseudo_selector();
+    }
+    else if (lex < exactly<'['> >()) {
+      return parse_attribute_selector();
+    }
+    else if (lex< placeholder >()) {
+      Placeholder_Selector_Ptr sel = SASS_MEMORY_NEW(Placeholder_Selector, pstate, lexed);
+      sel->media_block(last_media_block);
+      return sel;
+    }
+    else {
+      css_error("Invalid CSS", " after ", ": expected selector, was ");
+    }
+    // failed
+    return 0;
+  }
+
+  Wrapped_Selector_Obj Parser::parse_negated_selector()
+  {
+    lex< pseudo_not >();
+    std::string name(lexed);
+    ParserState nsource_position = pstate;
+    Selector_List_Obj negated = parse_selector_list(true);
+    if (!lex< exactly<')'> >()) {
+      error("negated selector is missing ')'");
+    }
+    name.erase(name.size() - 1);
+    return SASS_MEMORY_NEW(Wrapped_Selector, nsource_position, name, negated);
+  }
+
+  // a pseudo selector often starts with one or two colons
+  // it can contain more selectors inside parentheses
+  Simple_Selector_Obj Parser::parse_pseudo_selector() {
+    if (lex< sequence<
+          optional < pseudo_prefix >,
+          // we keep the space within the name, strange enough
+          // ToDo: refactor output to schedule the space for it
+          // or do we really want to keep the real white-space?
+          sequence< identifier, optional < block_comment >, exactly<'('> >
+        > >())
+    {
+
+      std::string name(lexed);
+      name.erase(name.size() - 1);
+      ParserState p = pstate;
+
+      // specially parse static stuff
+      // ToDo: really everything static?
+      if (peek_css <
+            sequence <
+              alternatives <
+                static_value,
+                binomial
+              >,
+              optional_css_whitespace,
+              exactly<')'>
+            >
+          >()
+      ) {
+        lex_css< alternatives < static_value, binomial > >();
+        String_Constant_Obj expr = SASS_MEMORY_NEW(String_Constant, pstate, lexed);
+        if (lex_css< exactly<')'> >()) {
+          expr->can_compress_whitespace(true);
+          return SASS_MEMORY_NEW(Pseudo_Selector, p, name, expr);
+        }
+      }
+      else if (Selector_List_Obj wrapped = parse_selector_list(true)) {
+        if (wrapped && lex_css< exactly<')'> >()) {
+          return SASS_MEMORY_NEW(Wrapped_Selector, p, name, wrapped);
+        }
+      }
+
+    }
+    // EO if pseudo selector
+
+    else if (lex < sequence< optional < pseudo_prefix >, identifier > >()) {
+      return SASS_MEMORY_NEW(Pseudo_Selector, pstate, lexed);
+    }
+    else if(lex < pseudo_prefix >()) {
+      css_error("Invalid CSS", " after ", ": expected pseudoclass or pseudoelement, was ");
+    }
+
+    css_error("Invalid CSS", " after ", ": expected \")\", was ");
+
+    // unreachable statement
+    return 0;
+  }
+
+  const char* Parser::re_attr_sensitive_close(const char* src)
+  {
+    return alternatives < exactly<']'>, exactly<'/'> >(src);
+  }
+
+  const char* Parser::re_attr_insensitive_close(const char* src)
+  {
+    return sequence < insensitive<'i'>, re_attr_sensitive_close >(src);
+  }
+
+  Attribute_Selector_Obj Parser::parse_attribute_selector()
+  {
+    ParserState p = pstate;
+    if (!lex_css< attribute_name >()) error("invalid attribute name in attribute selector");
+    std::string name(lexed);
+    if (lex_css< re_attr_sensitive_close >()) {
+      return SASS_MEMORY_NEW(Attribute_Selector, p, name, "", 0, 0);
+    }
+    else if (lex_css< re_attr_insensitive_close >()) {
+      char modifier = lexed.begin[0];
+      return SASS_MEMORY_NEW(Attribute_Selector, p, name, "", 0, modifier);
+    }
+    if (!lex_css< alternatives< exact_match, class_match, dash_match,
+                                prefix_match, suffix_match, substring_match > >()) {
+      error("invalid operator in attribute selector for " + name);
+    }
+    std::string matcher(lexed);
+
+    String_Obj value = 0;
+    if (lex_css< identifier >()) {
+      value = SASS_MEMORY_NEW(String_Constant, p, lexed);
+    }
+    else if (lex_css< quoted_string >()) {
+      value = parse_interpolated_chunk(lexed, true); // needed!
+    }
+    else {
+      error("expected a string constant or identifier in attribute selector for " + name);
+    }
+
+    if (lex_css< re_attr_sensitive_close >()) {
+      return SASS_MEMORY_NEW(Attribute_Selector, p, name, matcher, value, 0);
+    }
+    else if (lex_css< re_attr_insensitive_close >()) {
+      char modifier = lexed.begin[0];
+      return SASS_MEMORY_NEW(Attribute_Selector, p, name, matcher, value, modifier);
+    }
+    error("unterminated attribute selector for " + name);
+    return NULL; // to satisfy compilers (error must not return)
+  }
+
+  /* parse block comment and add to block */
+  void Parser::parse_block_comments()
+  {
+    Block_Obj block = block_stack.back();
+
+    while (lex< block_comment >()) {
+      bool is_important = lexed.begin[2] == '!';
+      // flag on second param is to skip loosely over comments
+      String_Obj contents = parse_interpolated_chunk(lexed, true, false);
+      block->append(SASS_MEMORY_NEW(Comment, pstate, contents, is_important));
+    }
+  }
+
+  Declaration_Obj Parser::parse_declaration() {
+    String_Obj prop;
+    bool is_custom_property = false;
+    if (lex< sequence< optional< exactly<'*'> >, identifier_schema > >()) {
+      const std::string property(lexed);
+      is_custom_property = property.compare(0, 2, "--") == 0;
+      prop = parse_identifier_schema();
+    }
+    else if (lex< sequence< optional< exactly<'*'> >, identifier, zero_plus< block_comment > > >()) {
+      const std::string property(lexed);
+      is_custom_property = property.compare(0, 2, "--") == 0;
+      prop = SASS_MEMORY_NEW(String_Constant, pstate, lexed);
+    }
+    else {
+      css_error("Invalid CSS", " after ", ": expected \"}\", was ");
+    }
+    bool is_indented = true;
+    const std::string property(lexed);
+    if (!lex_css< one_plus< exactly<':'> > >()) error("property \"" + escape_string(property)  + "\" must be followed by a ':'");
+    if (!is_custom_property && match< sequence< optional_css_comments, exactly<';'> > >()) error("style declaration must contain a value");
+    if (match< sequence< optional_css_comments, exactly<'{'> > >()) is_indented = false; // don't indent if value is empty
+    if (is_custom_property) {
+      return SASS_MEMORY_NEW(Declaration, prop->pstate(), prop, parse_css_variable_value(), false, true);
+    }
+    lex < css_comments >(false);
+    if (peek_css< static_value >()) {
+      return SASS_MEMORY_NEW(Declaration, prop->pstate(), prop, parse_static_value()/*, lex<kwd_important>()*/);
+    }
+    else {
+      Expression_Obj value;
+      Lookahead lookahead = lookahead_for_value(position);
+      if (lookahead.found) {
+        if (lookahead.has_interpolants) {
+          value = parse_value_schema(lookahead.found);
+        } else {
+          value = parse_list(DELAYED);
+        }
+      }
+      else {
+        value = parse_list(DELAYED);
+        if (List_Ptr list = Cast<List>(value)) {
+          if (!list->is_bracketed() && list->length() == 0 && !peek< exactly <'{'> >()) {
+            css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
+          }
+        }
+      }
+      lex < css_comments >(false);
+      Declaration_Obj decl = SASS_MEMORY_NEW(Declaration, prop->pstate(), prop, value/*, lex<kwd_important>()*/);
+      decl->is_indented(is_indented);
+      decl->update_pstate(pstate);
+      return decl;
+    }
+  }
+
+  // parse +/- and return false if negative
+  // this is never hit via spec tests
+  bool Parser::parse_number_prefix()
+  {
+    bool positive = true;
+    while(true) {
+      if (lex < block_comment >()) continue;
+      if (lex < number_prefix >()) continue;
+      if (lex < exactly < '-' > >()) {
+        positive = !positive;
+        continue;
+      }
+      break;
+    }
+    return positive;
+  }
+
+  Expression_Obj Parser::parse_map()
+  {
+    NESTING_GUARD(nestings);
+    Expression_Obj key = parse_list();
+    List_Obj map = SASS_MEMORY_NEW(List, pstate, 0, SASS_HASH);
+
+    // it's not a map so return the lexed value as a list value
+    if (!lex_css< exactly<':'> >())
+    { return key; }
+
+    List_Obj l = Cast<List>(key);
+    if (l && l->separator() == SASS_COMMA) {
+      css_error("Invalid CSS", " after ", ": expected \")\", was ");
+    }
+
+    Expression_Obj value = parse_space_list();
+
+    map->append(key);
+    map->append(value);
+
+    while (lex_css< exactly<','> >())
+    {
+      // allow trailing commas - #495
+      if (peek_css< exactly<')'> >(position))
+      { break; }
+
+      key = parse_space_list();
+
+      if (!(lex< exactly<':'> >()))
+      { css_error("Invalid CSS", " after ", ": expected \":\", was "); }
+
+      value = parse_space_list();
+
+      map->append(key);
+      map->append(value);
+    }
+
+    ParserState ps = map->pstate();
+    ps.offset = pstate - ps + pstate.offset;
+    map->pstate(ps);
+
+    return map;
+  }
+
+  Expression_Obj Parser::parse_bracket_list()
+  {
+    NESTING_GUARD(nestings);
+    // check if we have an empty list
+    // return the empty list as such
+    if (peek_css< list_terminator >(position))
+    {
+      // return an empty list (nothing to delay)
+      return SASS_MEMORY_NEW(List, pstate, 0, SASS_SPACE, false, true);
+    }
+
+    bool has_paren = peek_css< exactly<'('> >() != NULL;
+
+    // now try to parse a space list
+    Expression_Obj list = parse_space_list();
+    // if it's a singleton, return it (don't wrap it)
+    if (!peek_css< exactly<','> >(position)) {
+      List_Obj l = Cast<List>(list);
+      if (!l || l->is_bracketed() || has_paren) {
+        List_Obj bracketed_list = SASS_MEMORY_NEW(List, pstate, 1, SASS_SPACE, false, true);
+        bracketed_list->append(list);
+        return bracketed_list;
+      }
+      l->is_bracketed(true);
+      return l;
+    }
+
+    // if we got so far, we actually do have a comma list
+    List_Obj bracketed_list = SASS_MEMORY_NEW(List, pstate, 2, SASS_COMMA, false, true);
+    // wrap the first expression
+    bracketed_list->append(list);
+
+    while (lex_css< exactly<','> >())
+    {
+      // check for abort condition
+      if (peek_css< list_terminator >(position)
+      ) { break; }
+      // otherwise add another expression
+      bracketed_list->append(parse_space_list());
+    }
+    // return the list
+    return bracketed_list;
+  }
+
+  // parse list returns either a space separated list,
+  // a comma separated list or any bare expression found.
+  // so to speak: we unwrap items from lists if possible here!
+  Expression_Obj Parser::parse_list(bool delayed)
+  {
+    NESTING_GUARD(nestings);
+    return parse_comma_list(delayed);
+  }
+
+  // will return singletons unwrapped
+  Expression_Obj Parser::parse_comma_list(bool delayed)
+  {
+    NESTING_GUARD(nestings);
+    // check if we have an empty list
+    // return the empty list as such
+    if (peek_css< list_terminator >(position))
+    {
+      // return an empty list (nothing to delay)
+      return SASS_MEMORY_NEW(List, pstate, 0);
+    }
+
+    // now try to parse a space list
+    Expression_Obj list = parse_space_list();
+    // if it's a singleton, return it (don't wrap it)
+    if (!peek_css< exactly<','> >(position)) {
+      // set_delay doesn't apply to list children
+      // so this will only undelay single values
+      if (!delayed) list->set_delayed(false);
+      return list;
+    }
+
+    // if we got so far, we actually do have a comma list
+    List_Obj comma_list = SASS_MEMORY_NEW(List, pstate, 2, SASS_COMMA);
+    // wrap the first expression
+    comma_list->append(list);
+
+    while (lex_css< exactly<','> >())
+    {
+      // check for abort condition
+      if (peek_css< list_terminator >(position)
+      ) { break; }
+      // otherwise add another expression
+      comma_list->append(parse_space_list());
+    }
+    // return the list
+    return comma_list;
+  }
+  // EO parse_comma_list
+
+  // will return singletons unwrapped
+  Expression_Obj Parser::parse_space_list()
+  {
+    NESTING_GUARD(nestings);
+    Expression_Obj disj1 = parse_disjunction();
+    // if it's a singleton, return it (don't wrap it)
+    if (peek_css< space_list_terminator >(position)
+    ) {
+      return disj1; }
+
+    List_Obj space_list = SASS_MEMORY_NEW(List, pstate, 2, SASS_SPACE);
+    space_list->append(disj1);
+
+    while (
+      !(peek_css< space_list_terminator >(position)) &&
+      peek_css< optional_css_whitespace >() != end
+    ) {
+      // the space is parsed implicitly?
+      space_list->append(parse_disjunction());
+    }
+    // return the list
+    return space_list;
+  }
+  // EO parse_space_list
+
+  // parse logical OR operation
+  Expression_Obj Parser::parse_disjunction()
+  {
+    NESTING_GUARD(nestings);
+    advanceToNextToken();
+    ParserState state(pstate);
+    // parse the left hand side conjunction
+    Expression_Obj conj = parse_conjunction();
+    // parse multiple right hand sides
+    std::vector<Expression_Obj> operands;
+    while (lex_css< kwd_or >())
+      operands.push_back(parse_conjunction());
+    // if it's a singleton, return it directly
+    if (operands.size() == 0) return conj;
+    // fold all operands into one binary expression
+    Expression_Obj ex = fold_operands(conj, operands, { Sass_OP::OR });
+    state.offset = pstate - state + pstate.offset;
+    ex->pstate(state);
+    return ex;
+  }
+  // EO parse_disjunction
+
+  // parse logical AND operation
+  Expression_Obj Parser::parse_conjunction()
+  {
+    NESTING_GUARD(nestings);
+    advanceToNextToken();
+    ParserState state(pstate);
+    // parse the left hand side relation
+    Expression_Obj rel = parse_relation();
+    // parse multiple right hand sides
+    std::vector<Expression_Obj> operands;
+    while (lex_css< kwd_and >()) {
+      operands.push_back(parse_relation());
+    }
+    // if it's a singleton, return it directly
+    if (operands.size() == 0) return rel;
+    // fold all operands into one binary expression
+    Expression_Obj ex = fold_operands(rel, operands, { Sass_OP::AND });
+    state.offset = pstate - state + pstate.offset;
+    ex->pstate(state);
+    return ex;
+  }
+  // EO parse_conjunction
+
+  // parse comparison operations
+  Expression_Obj Parser::parse_relation()
+  {
+    NESTING_GUARD(nestings);
+    advanceToNextToken();
+    ParserState state(pstate);
+    // parse the left hand side expression
+    Expression_Obj lhs = parse_expression();
+    std::vector<Expression_Obj> operands;
+    std::vector<Operand> operators;
+    // if it's a singleton, return it (don't wrap it)
+    while (peek< alternatives <
+            kwd_eq,
+            kwd_neq,
+            kwd_gte,
+            kwd_gt,
+            kwd_lte,
+            kwd_lt
+          > >(position))
+    {
+      // is directly adjancent to expression?
+      bool left_ws = peek < css_comments >() != NULL;
+      // parse the operator
+      enum Sass_OP op
+      = lex<kwd_eq>()  ? Sass_OP::EQ
+      : lex<kwd_neq>() ? Sass_OP::NEQ
+      : lex<kwd_gte>() ? Sass_OP::GTE
+      : lex<kwd_lte>() ? Sass_OP::LTE
+      : lex<kwd_gt>()  ? Sass_OP::GT
+      : lex<kwd_lt>()  ? Sass_OP::LT
+      // we checked the possibilities on top of fn
+      :                  Sass_OP::EQ;
+      // is directly adjacent to expression?
+      bool right_ws = peek < css_comments >() != NULL;
+      operators.push_back({ op, left_ws, right_ws });
+      operands.push_back(parse_expression());
+    }
+    // we are called recursively for list, so we first
+    // fold inner binary expression which has delayed
+    // correctly set to zero. After folding we also unwrap
+    // single nested items. So we cannot set delay on the
+    // returned result here, as we have lost nestings ...
+    Expression_Obj ex = fold_operands(lhs, operands, operators);
+    state.offset = pstate - state + pstate.offset;
+    ex->pstate(state);
+    return ex;
+  }
+  // parse_relation
+
+  // parse expression valid for operations
+  // called from parse_relation
+  // called from parse_for_directive
+  // called from parse_media_expression
+  // parse addition and subtraction operations
+  Expression_Obj Parser::parse_expression()
+  {
+    NESTING_GUARD(nestings);
+    advanceToNextToken();
+    ParserState state(pstate);
+    // parses multiple add and subtract operations
+    // NOTE: make sure that identifiers starting with
+    // NOTE: dashes do NOT count as subtract operation
+    Expression_Obj lhs = parse_operators();
+    // if it's a singleton, return it (don't wrap it)
+    if (!(peek_css< exactly<'+'> >(position) ||
+          // condition is a bit misterious, but some combinations should not be counted as operations
+          (peek< no_spaces >(position) && peek< sequence< negate< unsigned_number >, exactly<'-'>, negate< space > > >(position)) ||
+          (peek< sequence< negate< unsigned_number >, exactly<'-'>, negate< unsigned_number > > >(position))) ||
+          peek< sequence < zero_plus < exactly <'-' > >, identifier > >(position))
+    { return lhs; }
+
+    std::vector<Expression_Obj> operands;
+    std::vector<Operand> operators;
+    bool left_ws = peek < css_comments >() != NULL;
+    while (
+      lex_css< exactly<'+'> >() ||
+
+      (
+      ! peek_css< sequence < zero_plus < exactly <'-' > >, identifier > >(position)
+      && lex_css< sequence< negate< digit >, exactly<'-'> > >()
+      )
+
+    ) {
+
+      bool right_ws = peek < css_comments >() != NULL;
+      operators.push_back({ lexed.to_string() == "+" ? Sass_OP::ADD : Sass_OP::SUB, left_ws, right_ws });
+      operands.push_back(parse_operators());
+      left_ws = peek < css_comments >() != NULL;
+    }
+
+    if (operands.size() == 0) return lhs;
+    Expression_Obj ex = fold_operands(lhs, operands, operators);
+    state.offset = pstate - state + pstate.offset;
+    ex->pstate(state);
+    return ex;
+  }
+
+  // parse addition and subtraction operations
+  Expression_Obj Parser::parse_operators()
+  {
+    NESTING_GUARD(nestings);
+    advanceToNextToken();
+    ParserState state(pstate);
+    Expression_Obj factor = parse_factor();
+    // if it's a singleton, return it (don't wrap it)
+    std::vector<Expression_Obj> operands; // factors
+    std::vector<Operand> operators; // ops
+    // lex operations to apply to lhs
+    const char* left_ws = peek < css_comments >();
+    while (lex_css< class_char< static_ops > >()) {
+      const char* right_ws = peek < css_comments >();
+      switch(*lexed.begin) {
+        case '*': operators.push_back({ Sass_OP::MUL, left_ws != 0, right_ws != 0 }); break;
+        case '/': operators.push_back({ Sass_OP::DIV, left_ws != 0, right_ws != 0 }); break;
+        case '%': operators.push_back({ Sass_OP::MOD, left_ws != 0, right_ws != 0 }); break;
+        default: throw std::runtime_error("unknown static op parsed");
+      }
+      operands.push_back(parse_factor());
+      left_ws = peek < css_comments >();
+    }
+    // operands and operators to binary expression
+    Expression_Obj ex = fold_operands(factor, operands, operators);
+    state.offset = pstate - state + pstate.offset;
+    ex->pstate(state);
+    return ex;
+  }
+  // EO parse_operators
+
+
+  // called from parse_operators
+  // called from parse_value_schema
+  Expression_Obj Parser::parse_factor()
+  {
+    NESTING_GUARD(nestings);
+    lex < css_comments >(false);
+    if (lex_css< exactly<'('> >()) {
+      // parse_map may return a list
+      Expression_Obj value = parse_map();
+      // lex the expected closing parenthesis
+      if (!lex_css< exactly<')'> >()) error("unclosed parenthesis");
+      // expression can be evaluated
+      return value;
+    }
+    else if (lex_css< exactly<'['> >()) {
+      // explicit bracketed
+      Expression_Obj value = parse_bracket_list();
+      // lex the expected closing square bracket
+      if (!lex_css< exactly<']'> >()) error("unclosed squared bracket");
+      return value;
+    }
+    // string may be interpolated
+    // if (lex< quoted_string >()) {
+    //   return &parse_string();
+    // }
+    else if (peek< ie_property >()) {
+      return parse_ie_property();
+    }
+    else if (peek< ie_keyword_arg >()) {
+      return parse_ie_keyword_arg();
+    }
+    else if (peek< sequence < calc_fn_call, exactly <'('> > >()) {
+      return parse_calc_function();
+    }
+    else if (lex < functional_schema >()) {
+      return parse_function_call_schema();
+    }
+    else if (lex< identifier_schema >()) {
+      String_Obj string = parse_identifier_schema();
+      if (String_Schema_Ptr schema = Cast<String_Schema>(string)) {
+        if (lex < exactly < '(' > >()) {
+          schema->append(parse_list());
+          lex < exactly < ')' > >();
+        }
+      }
+      return string;
+    }
+    else if (peek< sequence< uri_prefix, W, real_uri_value > >()) {
+      return parse_url_function_string();
+    }
+    else if (peek< re_functional >()) {
+      return parse_function_call();
+    }
+    else if (lex< exactly<'+'> >()) {
+      Unary_Expression_Ptr ex = SASS_MEMORY_NEW(Unary_Expression, pstate, Unary_Expression::PLUS, parse_factor());
+      if (ex && ex->operand()) ex->is_delayed(ex->operand()->is_delayed());
+      return ex;
+    }
+    else if (lex< exactly<'-'> >()) {
+      Unary_Expression_Ptr ex = SASS_MEMORY_NEW(Unary_Expression, pstate, Unary_Expression::MINUS, parse_factor());
+      if (ex && ex->operand()) ex->is_delayed(ex->operand()->is_delayed());
+      return ex;
+    }
+    else if (lex< exactly<'/'> >()) {
+      Unary_Expression_Ptr ex = SASS_MEMORY_NEW(Unary_Expression, pstate, Unary_Expression::SLASH, parse_factor());
+      if (ex && ex->operand()) ex->is_delayed(ex->operand()->is_delayed());
+      return ex;
+    }
+    else if (lex< sequence< kwd_not > >()) {
+      Unary_Expression_Ptr ex = SASS_MEMORY_NEW(Unary_Expression, pstate, Unary_Expression::NOT, parse_factor());
+      if (ex && ex->operand()) ex->is_delayed(ex->operand()->is_delayed());
+      return ex;
+    }
+    // this whole branch is never hit via spec tests
+    else if (peek < sequence < one_plus < alternatives < css_whitespace, exactly<'-'>, exactly<'+'> > >, number > >()) {
+      if (parse_number_prefix()) return parse_value(); // prefix is positive
+      Unary_Expression_Ptr ex = SASS_MEMORY_NEW(Unary_Expression, pstate, Unary_Expression::MINUS, parse_value());
+      if (ex->operand()) ex->is_delayed(ex->operand()->is_delayed());
+      return ex;
+    }
+    else {
+      return parse_value();
+    }
+  }
+
+  bool number_has_zero(const std::string& parsed)
+  {
+    size_t L = parsed.length();
+    return !( (L > 0 && parsed.substr(0, 1) == ".") ||
+              (L > 1 && parsed.substr(0, 2) == "0.") ||
+              (L > 1 && parsed.substr(0, 2) == "-.")  ||
+              (L > 2 && parsed.substr(0, 3) == "-0.") );
+  }
+
+  Number_Ptr Parser::lexed_number(const ParserState& pstate, const std::string& parsed)
+  {
+    Number_Ptr nr = SASS_MEMORY_NEW(Number,
+                                    pstate,
+                                    sass_strtod(parsed.c_str()),
+                                    "",
+                                    number_has_zero(parsed));
+    nr->is_interpolant(false);
+    nr->is_delayed(true);
+    return nr;
+  }
+
+  Number_Ptr Parser::lexed_percentage(const ParserState& pstate, const std::string& parsed)
+  {
+    Number_Ptr nr = SASS_MEMORY_NEW(Number,
+                                    pstate,
+                                    sass_strtod(parsed.c_str()),
+                                    "%",
+                                    true);
+    nr->is_interpolant(false);
+    nr->is_delayed(true);
+    return nr;
+  }
+
+  Number_Ptr Parser::lexed_dimension(const ParserState& pstate, const std::string& parsed)
+  {
+    size_t L = parsed.length();
+    size_t num_pos = parsed.find_first_not_of(" \n\r\t");
+    if (num_pos == std::string::npos) num_pos = L;
+    size_t unit_pos = parsed.find_first_not_of("-+0123456789.", num_pos);
+    if (parsed[unit_pos] == 'e' && is_number(parsed[unit_pos+1]) ) {
+      unit_pos = parsed.find_first_not_of("-+0123456789.", ++ unit_pos);
+    }
+    if (unit_pos == std::string::npos) unit_pos = L;
+    const std::string& num = parsed.substr(num_pos, unit_pos - num_pos);
+    Number_Ptr nr = SASS_MEMORY_NEW(Number,
+                                    pstate,
+                                    sass_strtod(num.c_str()),
+                                    Token(number(parsed.c_str())),
+                                    number_has_zero(parsed));
+    nr->is_interpolant(false);
+    nr->is_delayed(true);
+    return nr;
+  }
+
+  Expression_Ptr Parser::lexed_hex_color(const ParserState& pstate, const std::string& parsed)
+  {
+    Color_Ptr color = NULL;
+    if (parsed[0] != '#') {
+      return SASS_MEMORY_NEW(String_Quoted, pstate, parsed);
+    }
+    // chop off the '#'
+    std::string hext(parsed.substr(1));
+    if (parsed.length() == 4) {
+      std::string r(2, parsed[1]);
+      std::string g(2, parsed[2]);
+      std::string b(2, parsed[3]);
+      color = SASS_MEMORY_NEW(Color,
+                               pstate,
+                               static_cast<double>(strtol(r.c_str(), NULL, 16)),
+                               static_cast<double>(strtol(g.c_str(), NULL, 16)),
+                               static_cast<double>(strtol(b.c_str(), NULL, 16)),
+                               1, // alpha channel
+                               parsed);
+    }
+    else if (parsed.length() == 7) {
+      std::string r(parsed.substr(1,2));
+      std::string g(parsed.substr(3,2));
+      std::string b(parsed.substr(5,2));
+      color = SASS_MEMORY_NEW(Color,
+                               pstate,
+                               static_cast<double>(strtol(r.c_str(), NULL, 16)),
+                               static_cast<double>(strtol(g.c_str(), NULL, 16)),
+                               static_cast<double>(strtol(b.c_str(), NULL, 16)),
+                               1, // alpha channel
+                               parsed);
+    }
+    else if (parsed.length() == 9) {
+      std::string r(parsed.substr(1,2));
+      std::string g(parsed.substr(3,2));
+      std::string b(parsed.substr(5,2));
+      std::string a(parsed.substr(7,2));
+      color = SASS_MEMORY_NEW(Color,
+                               pstate,
+                               static_cast<double>(strtol(r.c_str(), NULL, 16)),
+                               static_cast<double>(strtol(g.c_str(), NULL, 16)),
+                               static_cast<double>(strtol(b.c_str(), NULL, 16)),
+                               static_cast<double>(strtol(a.c_str(), NULL, 16)) / 255,
+                               parsed);
+    }
+    color->is_interpolant(false);
+    color->is_delayed(false);
+    return color;
+  }
+
+  // parse one value for a list
+  Expression_Obj Parser::parse_value()
+  {
+    lex< css_comments >(false);
+    if (lex< ampersand >())
+    {
+      if (match< ampersand >()) {
+        warning("In Sass, \"&&\" means two copies of the parent selector. You probably want to use \"and\" instead.", pstate);
+      }
+      return SASS_MEMORY_NEW(Parent_Selector, pstate); }
+
+    if (lex< kwd_important >())
+    { return SASS_MEMORY_NEW(String_Constant, pstate, "!important"); }
+
+    // parse `10%4px` into separated items and not a schema
+    if (lex< sequence < percentage, lookahead < number > > >())
+    { return lexed_percentage(lexed); }
+
+    if (lex< sequence < number, lookahead< sequence < op, number > > > >())
+    { return lexed_number(lexed); }
+
+    // string may be interpolated
+    if (lex< sequence < quoted_string, lookahead < exactly <'-'> > > >())
+    { return parse_string(); }
+
+    if (const char* stop = peek< value_schema >())
+    { return parse_value_schema(stop); }
+
+    // string may be interpolated
+    if (lex< quoted_string >())
+    { return parse_string(); }
+
+    if (lex< kwd_true >())
+    { return SASS_MEMORY_NEW(Boolean, pstate, true); }
+
+    if (lex< kwd_false >())
+    { return SASS_MEMORY_NEW(Boolean, pstate, false); }
+
+    if (lex< kwd_null >())
+    { return SASS_MEMORY_NEW(Null, pstate); }
+
+    if (lex< identifier >()) {
+      return SASS_MEMORY_NEW(String_Constant, pstate, lexed);
+    }
+
+    if (lex< percentage >())
+    { return lexed_percentage(lexed); }
+
+    // match hex number first because 0x000 looks like a number followed by an identifier
+    if (lex< sequence < alternatives< hex, hex0 >, negate < exactly<'-'> > > >())
+    { return lexed_hex_color(lexed); }
+
+    if (lex< hexa >())
+    {
+      std::string s = lexed.to_string();
+
+      deprecated(
+        "The value \""+s+"\" is currently parsed as a string, but it will be parsed as a color in",
+        "future versions of Sass. Use \"unquote('"+s+"')\" to continue parsing it as a string.",
+        true, pstate
+      );
+
+      return SASS_MEMORY_NEW(String_Quoted, pstate, lexed);
+    }
+
+    if (lex< sequence < exactly <'#'>, identifier > >())
+    { return SASS_MEMORY_NEW(String_Quoted, pstate, lexed); }
+
+    // also handle the 10em- foo special case
+    // alternatives < exactly < '.' >, .. > -- `1.5em-.75em` is split into a list, not a binary expression
+    if (lex< sequence< dimension, optional< sequence< exactly<'-'>, lookahead< alternatives < space > > > > > >())
+    { return lexed_dimension(lexed); }
+
+    if (lex< sequence< static_component, one_plus< strict_identifier > > >())
+    { return SASS_MEMORY_NEW(String_Constant, pstate, lexed); }
+
+    if (lex< number >())
+    { return lexed_number(lexed); }
+
+    if (lex< variable >())
+    { return SASS_MEMORY_NEW(Variable, pstate, Util::normalize_underscores(lexed)); }
+
+    // Special case handling for `%` proceeding an interpolant.
+    if (lex< sequence< exactly<'%'>, optional< percentage > > >())
+    { return SASS_MEMORY_NEW(String_Constant, pstate, lexed); }
+
+    css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
+
+    // unreachable statement
+    return 0;
+  }
+
+  // this parses interpolation inside other strings
+  // means the result should later be quoted again
+  String_Obj Parser::parse_interpolated_chunk(Token chunk, bool constant, bool css)
+  {
+    const char* i = chunk.begin;
+    // see if there any interpolants
+    const char* p = constant ? find_first_in_interval< exactly<hash_lbrace> >(i, chunk.end) :
+                    find_first_in_interval< exactly<hash_lbrace>, block_comment >(i, chunk.end);
+
+    if (!p) {
+      String_Quoted_Ptr str_quoted = SASS_MEMORY_NEW(String_Quoted, pstate, std::string(i, chunk.end), 0, false, false, true, css);
+      if (!constant && str_quoted->quote_mark()) str_quoted->quote_mark('*');
+      return str_quoted;
+    }
+
+    String_Schema_Obj schema = SASS_MEMORY_NEW(String_Schema, pstate, 0, css);
+    schema->is_interpolant(true);
+    while (i < chunk.end) {
+      p = constant ? find_first_in_interval< exactly<hash_lbrace> >(i, chunk.end) :
+          find_first_in_interval< exactly<hash_lbrace>, block_comment >(i, chunk.end);
+      if (p) {
+        if (i < p) {
+          // accumulate the preceding segment if it's nonempty
+          schema->append(SASS_MEMORY_NEW(String_Constant, pstate, std::string(i, p), css));
+        }
+        // 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
+          Expression_Obj interp_node = Parser::from_token(Token(p+2, j), ctx, traces, pstate, source).parse_list();
+          interp_node->is_interpolant(true);
+          schema->append(interp_node);
+          i = j;
+        }
+        else {
+          // throw an error if the interpolant is unterminated
+          error("unterminated interpolant inside string constant " + chunk.to_string());
+        }
+      }
+      else { // no interpolants left; add the last segment if nonempty
+        // check if we need quotes here (was not sure after merge)
+        if (i < chunk.end) schema->append(SASS_MEMORY_NEW(String_Constant, pstate, std::string(i, chunk.end), css));
+        break;
+      }
+      ++ i;
+    }
+
+    return schema.detach();
+  }
+
+  String_Schema_Obj Parser::parse_css_variable_value(bool top_level)
+  {
+    String_Schema_Obj schema = SASS_MEMORY_NEW(String_Schema, pstate);
+    String_Schema_Obj tok;
+    if (!(tok = parse_css_variable_value_token(top_level))) {
+      return NULL;
+    }
+
+    schema->concat(tok);
+    while ((tok = parse_css_variable_value_token(top_level))) {
+      schema->concat(tok);
+    }
+
+    return schema.detach();
+  }
+
+  String_Schema_Obj Parser::parse_css_variable_value_token(bool top_level)
+  {
+    String_Schema_Obj schema = SASS_MEMORY_NEW(String_Schema, pstate);
+    if (
+      (top_level && lex< css_variable_top_level_value >(false)) ||
+      (!top_level && lex< css_variable_value >(false))
+    ) {
+      Token str(lexed);
+      schema->append(SASS_MEMORY_NEW(String_Constant, pstate, str));
+    }
+    else if (Expression_Obj tok = lex_interpolation()) {
+      if (String_Schema_Ptr s = Cast<String_Schema>(tok)) {
+        schema->concat(s);
+      } else {
+        schema->append(tok);
+      }
+    }
+    else if (lex< quoted_string >()) {
+      Expression_Obj tok = parse_string();
+      if (String_Schema_Ptr s = Cast<String_Schema>(tok)) {
+        schema->concat(s);
+      } else {
+        schema->append(tok);
+      }
+    }
+    else {
+      if (peek< alternatives< exactly<'('>, exactly<'['>, exactly<'{'> > >()) {
+        if (lex< exactly<'('> >()) {
+          schema->append(SASS_MEMORY_NEW(String_Constant, pstate, std::string("(")));
+          if (String_Schema_Obj tok = parse_css_variable_value(false)) schema->concat(tok);
+          if (!lex< exactly<')'> >()) css_error("Invalid CSS", " after ", ": expected \")\", was ");
+          schema->append(SASS_MEMORY_NEW(String_Constant, pstate, std::string(")")));
+        }
+        else if (lex< exactly<'['> >()) {
+          schema->append(SASS_MEMORY_NEW(String_Constant, pstate, std::string("[")));
+          if (String_Schema_Obj tok = parse_css_variable_value(false)) schema->concat(tok);
+          if (!lex< exactly<']'> >()) css_error("Invalid CSS", " after ", ": expected \"]\", was ");
+          schema->append(SASS_MEMORY_NEW(String_Constant, pstate, std::string("]")));
+        }
+        else if (lex< exactly<'{'> >()) {
+          schema->append(SASS_MEMORY_NEW(String_Constant, pstate, std::string("{")));
+          if (String_Schema_Obj tok = parse_css_variable_value(false)) schema->concat(tok);
+          if (!lex< exactly<'}'> >()) css_error("Invalid CSS", " after ", ": expected \"}\", was ");
+          schema->append(SASS_MEMORY_NEW(String_Constant, pstate, std::string("}")));
+        }
+      }
+    }
+
+    return schema->length() > 0 ? schema.detach() : NULL;
+  }
+
+  String_Constant_Obj Parser::parse_static_value()
+  {
+    lex< static_value >();
+    Token str(lexed);
+    // static values always have trailing white-
+    // space and end delimiter (\s*[;]$) included
+    --pstate.offset.column;
+    --after_token.column;
+    --str.end;
+    --position;
+
+    String_Constant_Ptr str_node = SASS_MEMORY_NEW(String_Constant, pstate, str.time_wspace());
+    return str_node;
+  }
+
+  String_Obj Parser::parse_string()
+  {
+    return parse_interpolated_chunk(Token(lexed));
+  }
+
+  String_Obj Parser::parse_ie_property()
+  {
+    lex< ie_property >();
+    Token str(lexed);
+    const char* i = str.begin;
+    // see if there any interpolants
+    const char* p = find_first_in_interval< exactly<hash_lbrace>, block_comment >(str.begin, str.end);
+    if (!p) {
+      return SASS_MEMORY_NEW(String_Quoted, pstate, std::string(str.begin, str.end));
+    }
+
+    String_Schema_Ptr schema = SASS_MEMORY_NEW(String_Schema, pstate);
+    while (i < str.end) {
+      p = find_first_in_interval< exactly<hash_lbrace>, block_comment >(i, str.end);
+      if (p) {
+        if (i < p) {
+          schema->append(SASS_MEMORY_NEW(String_Constant, pstate, std::string(i, p))); // accumulate the preceding segment if it's nonempty
+        }
+        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
+          Expression_Obj interp_node = Parser::from_token(Token(p+2, j), ctx, traces, pstate, source).parse_list();
+          interp_node->is_interpolant(true);
+          schema->append(interp_node);
+          i = j;
+        }
+        else {
+          // throw an error if the interpolant is unterminated
+          error("unterminated interpolant inside IE function " + str.to_string());
+        }
+      }
+      else { // no interpolants left; add the last segment if nonempty
+        if (i < str.end) {
+          schema->append(SASS_MEMORY_NEW(String_Constant, pstate, std::string(i, str.end)));
+        }
+        break;
+      }
+    }
+    return schema;
+  }
+
+  String_Obj Parser::parse_ie_keyword_arg()
+  {
+    String_Schema_Ptr kwd_arg = SASS_MEMORY_NEW(String_Schema, pstate, 3);
+    if (lex< variable >()) {
+      kwd_arg->append(SASS_MEMORY_NEW(Variable, pstate, Util::normalize_underscores(lexed)));
+    } else {
+      lex< alternatives< identifier_schema, identifier > >();
+      kwd_arg->append(SASS_MEMORY_NEW(String_Constant, pstate, lexed));
+    }
+    lex< exactly<'='> >();
+    kwd_arg->append(SASS_MEMORY_NEW(String_Constant, pstate, lexed));
+    if (peek< variable >()) kwd_arg->append(parse_list());
+    else if (lex< number >()) {
+      std::string parsed(lexed);
+      Util::normalize_decimals(parsed);
+      kwd_arg->append(lexed_number(parsed));
+    }
+    else if (peek < ie_keyword_arg_value >()) { kwd_arg->append(parse_list()); }
+    return kwd_arg;
+  }
+
+  String_Schema_Obj Parser::parse_value_schema(const char* stop)
+  {
+    // initialize the string schema object to add tokens
+    String_Schema_Obj schema = SASS_MEMORY_NEW(String_Schema, pstate);
+
+    if (peek<exactly<'}'>>()) {
+      css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
+    }
+
+    const char* e;
+    const char* ee = end;
+    end = stop;
+    size_t num_items = 0;
+    bool need_space = false;
+    while (position < stop) {
+      // parse space between tokens
+      if (lex< spaces >() && num_items) {
+        need_space = true;
+      }
+      if (need_space) {
+        need_space = false;
+        // schema->append(SASS_MEMORY_NEW(String_Constant, pstate, " "));
+      }
+      if ((e = peek< re_functional >()) && e < stop) {
+        schema->append(parse_function_call());
+      }
+      // lex an interpolant /#{...}/
+      else if (lex< exactly < hash_lbrace > >()) {
+        // Try to lex static expression first
+        if (peek< exactly< rbrace > >()) {
+          css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
+        }
+        Expression_Obj ex;
+        if (lex< re_static_expression >()) {
+          ex = SASS_MEMORY_NEW(String_Constant, pstate, lexed);
+        } else {
+          ex = parse_list();
+        }
+        ex->is_interpolant(true);
+        schema->append(ex);
+        if (!lex < exactly < rbrace > >()) {
+          css_error("Invalid CSS", " after ", ": expected \"}\", was ");
+        }
+      }
+      // lex some string constants or other valid token
+      // Note: [-+] chars are left over from i.e. `#{3}+3`
+      else if (lex< alternatives < exactly<'%'>, exactly < '-' >, exactly < '+' > > >()) {
+        schema->append(SASS_MEMORY_NEW(String_Constant, pstate, lexed));
+      }
+      // lex a quoted string
+      else if (lex< quoted_string >()) {
+        // need_space = true;
+        // if (schema->length()) schema->append(SASS_MEMORY_NEW(String_Constant, pstate, " "));
+        // else need_space = true;
+        schema->append(parse_string());
+        if ((*position == '"' || *position == '\'') || peek < alternatives < alpha > >()) {
+          // need_space = true;
+        }
+        if (peek < exactly < '-' > >()) break;
+      }
+      else if (lex< sequence < identifier > >()) {
+        schema->append(SASS_MEMORY_NEW(String_Constant, pstate, lexed));
+        if ((*position == '"' || *position == '\'') || peek < alternatives < alpha > >()) {
+           // need_space = true;
+        }
+      }
+      // lex (normalized) variable
+      else if (lex< variable >()) {
+        std::string name(Util::normalize_underscores(lexed));
+        schema->append(SASS_MEMORY_NEW(Variable, pstate, name));
+      }
+      // lex percentage value
+      else if (lex< percentage >()) {
+        schema->append(lexed_percentage(lexed));
+      }
+      // lex dimension value
+      else if (lex< dimension >()) {
+        schema->append(lexed_dimension(lexed));
+      }
+      // lex number value
+      else if (lex< number >()) {
+        schema->append(lexed_number(lexed));
+      }
+      // lex hex color value
+      else if (lex< sequence < hex, negate < exactly < '-' > > > >()) {
+        schema->append(lexed_hex_color(lexed));
+      }
+      else if (lex< sequence < exactly <'#'>, identifier > >()) {
+        schema->append(SASS_MEMORY_NEW(String_Quoted, pstate, lexed));
+      }
+      // lex a value in parentheses
+      else if (peek< parenthese_scope >()) {
+        schema->append(parse_factor());
+      }
+      else {
+        break;
+      }
+      ++num_items;
+    }
+    if (position != stop) {
+      schema->append(SASS_MEMORY_NEW(String_Constant, pstate, std::string(position, stop)));
+      position = stop;
+    }
+    end = ee;
+    return schema;
+  }
+
+  // this parses interpolation outside other strings
+  // means the result must not be quoted again later
+  String_Obj Parser::parse_identifier_schema()
+  {
+    Token id(lexed);
+    const char* i = id.begin;
+    // see if there any interpolants
+    const char* p = find_first_in_interval< exactly<hash_lbrace>, block_comment >(id.begin, id.end);
+    if (!p) {
+      return SASS_MEMORY_NEW(String_Constant, pstate, std::string(id.begin, id.end));
+    }
+
+    String_Schema_Obj schema = SASS_MEMORY_NEW(String_Schema, pstate);
+    while (i < id.end) {
+      p = find_first_in_interval< exactly<hash_lbrace>, block_comment >(i, id.end);
+      if (p) {
+        if (i < p) {
+          // accumulate the preceding segment if it's nonempty
+          const char* o = position; position = i;
+          schema->append(parse_value_schema(p));
+          position = o;
+        }
+        // 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;
+          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
+          Expression_Obj interp_node = Parser::from_token(Token(p+2, j), ctx, traces, pstate, source).parse_list(DELAYED);
+          interp_node->is_interpolant(true);
+          schema->append(interp_node);
+          // schema->has_interpolants(true);
+          i = j;
+        }
+        else {
+          // throw an error if the interpolant is unterminated
+          error("unterminated interpolant inside interpolated identifier " + id.to_string());
+        }
+      }
+      else { // no interpolants left; add the last segment if nonempty
+        if (i < end) {
+          const char* o = position; position = i;
+          schema->append(parse_value_schema(id.end));
+          position = o;
+        }
+        break;
+      }
+    }
+    return schema ? schema.detach() : 0;
+  }
+
+  // calc functions should preserve arguments
+  Function_Call_Obj Parser::parse_calc_function()
+  {
+    lex< identifier >();
+    std::string name(lexed);
+    ParserState call_pos = pstate;
+    lex< exactly<'('> >();
+    ParserState arg_pos = pstate;
+    const char* arg_beg = position;
+    parse_list();
+    const char* arg_end = position;
+    lex< skip_over_scopes <
+          exactly < '(' >,
+          exactly < ')' >
+        > >();
+
+    Argument_Obj arg = SASS_MEMORY_NEW(Argument, arg_pos, parse_interpolated_chunk(Token(arg_beg, arg_end)));
+    Arguments_Obj args = SASS_MEMORY_NEW(Arguments, arg_pos);
+    args->append(arg);
+    return SASS_MEMORY_NEW(Function_Call, call_pos, name, args);
+  }
+
+  String_Obj Parser::parse_url_function_string()
+  {
+    std::string prefix("");
+    if (lex< uri_prefix >()) {
+      prefix = std::string(lexed);
+    }
+
+    lex < optional_spaces >();
+    String_Obj url_string = parse_url_function_argument();
+
+    std::string suffix("");
+    if (lex< real_uri_suffix >()) {
+      suffix = std::string(lexed);
+    }
+
+    std::string uri("");
+    if (url_string) {
+      uri = url_string->to_string({ NESTED, 5 });
+    }
+
+    if (String_Schema_Ptr schema = Cast<String_Schema>(url_string)) {
+      String_Schema_Obj res = SASS_MEMORY_NEW(String_Schema, pstate);
+      res->append(SASS_MEMORY_NEW(String_Constant, pstate, prefix));
+      res->append(schema);
+      res->append(SASS_MEMORY_NEW(String_Constant, pstate, suffix));
+      return res;
+    } else {
+      std::string res = prefix + uri + suffix;
+      return SASS_MEMORY_NEW(String_Constant, pstate, res);
+    }
+  }
+
+  String_Obj Parser::parse_url_function_argument()
+  {
+    const char* p = position;
+
+    std::string uri("");
+    if (lex< real_uri_value >(false)) {
+      uri = lexed.to_string();
+    }
+
+    if (peek< exactly< hash_lbrace > >()) {
+      const char* pp = position;
+      // TODO: error checking for unclosed interpolants
+      while (pp && peek< exactly< hash_lbrace > >(pp)) {
+        pp = sequence< interpolant, real_uri_value >(pp);
+      }
+      position = pp;
+      return parse_interpolated_chunk(Token(p, position));
+    }
+    else if (uri != "") {
+      std::string res = Util::rtrim(uri);
+      return SASS_MEMORY_NEW(String_Constant, pstate, res);
+    }
+
+    return 0;
+  }
+
+  Function_Call_Obj Parser::parse_function_call()
+  {
+    lex< identifier >();
+    std::string name(lexed);
+
+    if (Util::normalize_underscores(name) == "content-exists" && stack.back() != Scope::Mixin)
+    { error("Cannot call content-exists() except within a mixin."); }
+
+    ParserState call_pos = pstate;
+    Arguments_Obj args = parse_arguments();
+    return SASS_MEMORY_NEW(Function_Call, call_pos, name, args);
+  }
+
+  Function_Call_Schema_Obj Parser::parse_function_call_schema()
+  {
+    String_Obj name = parse_identifier_schema();
+    ParserState source_position_of_call = pstate;
+    Arguments_Obj args = parse_arguments();
+
+    return SASS_MEMORY_NEW(Function_Call_Schema, source_position_of_call, name, args);
+  }
+
+  Content_Obj Parser::parse_content_directive()
+  {
+    return SASS_MEMORY_NEW(Content, pstate);
+  }
+
+  If_Obj Parser::parse_if_directive(bool else_if)
+  {
+    stack.push_back(Scope::Control);
+    ParserState if_source_position = pstate;
+    bool root = block_stack.back()->is_root();
+    Expression_Obj predicate = parse_list();
+    Block_Obj block = parse_block(root);
+    Block_Obj alternative = NULL;
+
+    // only throw away comment if we parse a case
+    // we want all other comments to be parsed
+    if (lex_css< elseif_directive >()) {
+      alternative = SASS_MEMORY_NEW(Block, pstate);
+      alternative->append(parse_if_directive(true));
+    }
+    else if (lex_css< kwd_else_directive >()) {
+      alternative = parse_block(root);
+    }
+    stack.pop_back();
+    return SASS_MEMORY_NEW(If, if_source_position, predicate, block, alternative);
+  }
+
+  For_Obj Parser::parse_for_directive()
+  {
+    stack.push_back(Scope::Control);
+    ParserState for_source_position = pstate;
+    bool root = block_stack.back()->is_root();
+    lex_variable();
+    std::string var(Util::normalize_underscores(lexed));
+    if (!lex< kwd_from >()) error("expected 'from' keyword in @for directive");
+    Expression_Obj lower_bound = parse_expression();
+    bool inclusive = false;
+    if (lex< kwd_through >()) inclusive = true;
+    else if (lex< kwd_to >()) inclusive = false;
+    else                  error("expected 'through' or 'to' keyword in @for directive");
+    Expression_Obj upper_bound = parse_expression();
+    Block_Obj body = parse_block(root);
+    stack.pop_back();
+    return SASS_MEMORY_NEW(For, for_source_position, var, lower_bound, upper_bound, body, inclusive);
+  }
+
+  // helper to parse a var token
+  Token Parser::lex_variable()
+  {
+    // peek for dollar sign first
+    if (!peek< exactly <'$'> >()) {
+      css_error("Invalid CSS", " after ", ": expected \"$\", was ");
+    }
+    // we expect a simple identifier as the call name
+    if (!lex< sequence < exactly <'$'>, identifier > >()) {
+      lex< exactly <'$'> >(); // move pstate and position up
+      css_error("Invalid CSS", " after ", ": expected identifier, was ");
+    }
+    // return object
+    return token;
+  }
+  // helper to parse identifier
+  Token Parser::lex_identifier()
+  {
+    // we expect a simple identifier as the call name
+    if (!lex< identifier >()) { // ToDo: pstate wrong?
+      css_error("Invalid CSS", " after ", ": expected identifier, was ");
+    }
+    // return object
+    return token;
+  }
+
+  Each_Obj Parser::parse_each_directive()
+  {
+    stack.push_back(Scope::Control);
+    ParserState each_source_position = pstate;
+    bool root = block_stack.back()->is_root();
+    std::vector<std::string> vars;
+    lex_variable();
+    vars.push_back(Util::normalize_underscores(lexed));
+    while (lex< exactly<','> >()) {
+      if (!lex< variable >()) error("@each directive requires an iteration variable");
+      vars.push_back(Util::normalize_underscores(lexed));
+    }
+    if (!lex< kwd_in >()) error("expected 'in' keyword in @each directive");
+    Expression_Obj list = parse_list();
+    Block_Obj body = parse_block(root);
+    stack.pop_back();
+    return SASS_MEMORY_NEW(Each, each_source_position, vars, list, body);
+  }
+
+  // called after parsing `kwd_while_directive`
+  While_Obj Parser::parse_while_directive()
+  {
+    stack.push_back(Scope::Control);
+    bool root = block_stack.back()->is_root();
+    // create the initial while call object
+    While_Obj call = SASS_MEMORY_NEW(While, pstate, 0, 0);
+    // parse mandatory predicate
+    Expression_Obj predicate = parse_list();
+    List_Obj l = Cast<List>(predicate);
+    if (!predicate || (l && !l->length())) {
+      css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ", false);
+    }
+    call->predicate(predicate);
+    // parse mandatory block
+    call->block(parse_block(root));
+    // return ast node
+    stack.pop_back();
+    // return ast node
+    return call.detach();
+  }
+
+  // EO parse_while_directive
+  Media_Block_Obj Parser::parse_media_block()
+  {
+    stack.push_back(Scope::Media);
+    Media_Block_Obj media_block = SASS_MEMORY_NEW(Media_Block, pstate, 0, 0);
+
+    media_block->media_queries(parse_media_queries());
+
+    Media_Block_Obj prev_media_block = last_media_block;
+    last_media_block = media_block;
+    media_block->block(parse_css_block());
+    last_media_block = prev_media_block;
+    stack.pop_back();
+    return media_block.detach();
+  }
+
+  List_Obj Parser::parse_media_queries()
+  {
+    advanceToNextToken();
+    List_Obj queries = SASS_MEMORY_NEW(List, pstate, 0, SASS_COMMA);
+    if (!peek_css < exactly <'{'> >()) queries->append(parse_media_query());
+    while (lex_css < exactly <','> >()) queries->append(parse_media_query());
+    queries->update_pstate(pstate);
+    return queries.detach();
+  }
+
+  // Expression_Ptr Parser::parse_media_query()
+  Media_Query_Obj Parser::parse_media_query()
+  {
+    advanceToNextToken();
+    Media_Query_Obj media_query = SASS_MEMORY_NEW(Media_Query, pstate);
+    if (lex < kwd_not >()) { media_query->is_negated(true); lex < css_comments >(false); }
+    else if (lex < kwd_only >()) { media_query->is_restricted(true); lex < css_comments >(false); }
+
+    if (lex < identifier_schema >())  media_query->media_type(parse_identifier_schema());
+    else if (lex < identifier >())    media_query->media_type(parse_interpolated_chunk(lexed));
+    else                             media_query->append(parse_media_expression());
+
+    while (lex_css < kwd_and >()) media_query->append(parse_media_expression());
+    if (lex < identifier_schema >()) {
+      String_Schema_Ptr schema = SASS_MEMORY_NEW(String_Schema, pstate);
+      schema->append(media_query->media_type());
+      schema->append(SASS_MEMORY_NEW(String_Constant, pstate, " "));
+      schema->append(parse_identifier_schema());
+      media_query->media_type(schema);
+    }
+    while (lex_css < kwd_and >()) media_query->append(parse_media_expression());
+
+    media_query->update_pstate(pstate);
+
+    return media_query;
+  }
+
+  Media_Query_Expression_Obj Parser::parse_media_expression()
+  {
+    if (lex < identifier_schema >()) {
+      String_Obj ss = parse_identifier_schema();
+      return SASS_MEMORY_NEW(Media_Query_Expression, pstate, ss, 0, true);
+    }
+    if (!lex_css< exactly<'('> >()) {
+      error("media query expression must begin with '('");
+    }
+    Expression_Obj feature;
+    if (peek_css< exactly<')'> >()) {
+      error("media feature required in media query expression");
+    }
+    feature = parse_expression();
+    Expression_Obj expression = 0;
+    if (lex_css< exactly<':'> >()) {
+      expression = parse_list(DELAYED);
+    }
+    if (!lex_css< exactly<')'> >()) {
+      error("unclosed parenthesis in media query expression");
+    }
+    return SASS_MEMORY_NEW(Media_Query_Expression, feature->pstate(), feature, expression);
+  }
+
+  // lexed after `kwd_supports_directive`
+  // these are very similar to media blocks
+  Supports_Block_Obj Parser::parse_supports_directive()
+  {
+    Supports_Condition_Obj cond = parse_supports_condition();
+    if (!cond) {
+      css_error("Invalid CSS", " after ", ": expected @supports condition (e.g. (display: flexbox)), was ", false);
+    }
+    // create the ast node object for the support queries
+    Supports_Block_Obj query = SASS_MEMORY_NEW(Supports_Block, pstate, cond);
+    // additional block is mandatory
+    // parse inner block
+    query->block(parse_block());
+    // return ast node
+    return query;
+  }
+
+  // parse one query operation
+  // may encounter nested queries
+  Supports_Condition_Obj Parser::parse_supports_condition()
+  {
+    lex < css_whitespace >();
+    Supports_Condition_Obj cond;
+    if ((cond = parse_supports_negation())) return cond;
+    if ((cond = parse_supports_operator())) return cond;
+    if ((cond = parse_supports_interpolation())) return cond;
+    return cond;
+  }
+
+  Supports_Condition_Obj Parser::parse_supports_negation()
+  {
+    if (!lex < kwd_not >()) return 0;
+    Supports_Condition_Obj cond = parse_supports_condition_in_parens();
+    return SASS_MEMORY_NEW(Supports_Negation, pstate, cond);
+  }
+
+  Supports_Condition_Obj Parser::parse_supports_operator()
+  {
+    Supports_Condition_Obj cond = parse_supports_condition_in_parens();
+    if (cond.isNull()) return 0;
+
+    while (true) {
+      Supports_Operator::Operand op = Supports_Operator::OR;
+      if (lex < kwd_and >()) { op = Supports_Operator::AND; }
+      else if(!lex < kwd_or >()) { break; }
+
+      lex < css_whitespace >();
+      Supports_Condition_Obj right = parse_supports_condition_in_parens();
+
+      // Supports_Condition_Ptr cc = SASS_MEMORY_NEW(Supports_Condition, *static_cast<Supports_Condition_Ptr>(cond));
+      cond = SASS_MEMORY_NEW(Supports_Operator, pstate, cond, right, op);
+    }
+    return cond;
+  }
+
+  Supports_Condition_Obj Parser::parse_supports_interpolation()
+  {
+    if (!lex < interpolant >()) return 0;
+
+    String_Obj interp = parse_interpolated_chunk(lexed);
+    if (!interp) return 0;
+
+    return SASS_MEMORY_NEW(Supports_Interpolation, pstate, interp);
+  }
+
+  // TODO: This needs some major work. Although feature conditions
+  // look like declarations their semantics differ significantly
+  Supports_Condition_Obj Parser::parse_supports_declaration()
+  {
+    Supports_Condition_Ptr cond;
+    // parse something declaration like
+    Expression_Obj feature = parse_expression();
+    Expression_Obj expression = 0;
+    if (lex_css< exactly<':'> >()) {
+      expression = parse_list(DELAYED);
+    }
+    if (!feature || !expression) error("@supports condition expected declaration");
+    cond = SASS_MEMORY_NEW(Supports_Declaration,
+                     feature->pstate(),
+                     feature,
+                     expression);
+    // ToDo: maybe we need an additional error condition?
+    return cond;
+  }
+
+  Supports_Condition_Obj Parser::parse_supports_condition_in_parens()
+  {
+    Supports_Condition_Obj interp = parse_supports_interpolation();
+    if (interp != 0) return interp;
+
+    if (!lex < exactly <'('> >()) return 0;
+    lex < css_whitespace >();
+
+    Supports_Condition_Obj cond = parse_supports_condition();
+    if (cond != 0) {
+      if (!lex < exactly <')'> >()) error("unclosed parenthesis in @supports declaration");
+    } else {
+      cond = parse_supports_declaration();
+      if (!lex < exactly <')'> >()) error("unclosed parenthesis in @supports declaration");
+    }
+    lex < css_whitespace >();
+    return cond;
+  }
+
+  At_Root_Block_Obj Parser::parse_at_root_block()
+  {
+    stack.push_back(Scope::AtRoot);
+    ParserState at_source_position = pstate;
+    Block_Obj body = 0;
+    At_Root_Query_Obj expr;
+    Lookahead lookahead_result;
+    if (lex_css< exactly<'('> >()) {
+      expr = parse_at_root_query();
+    }
+    if (peek_css < exactly<'{'> >()) {
+      lex <optional_spaces>();
+      body = parse_block(true);
+    }
+    else if ((lookahead_result = lookahead_for_selector(position)).found) {
+      Ruleset_Obj r = parse_ruleset(lookahead_result);
+      body = SASS_MEMORY_NEW(Block, r->pstate(), 1, true);
+      body->append(r);
+    }
+    At_Root_Block_Obj at_root = SASS_MEMORY_NEW(At_Root_Block, at_source_position, body);
+    if (!expr.isNull()) at_root->expression(expr);
+    stack.pop_back();
+    return at_root;
+  }
+
+  At_Root_Query_Obj Parser::parse_at_root_query()
+  {
+    if (peek< exactly<')'> >()) error("at-root feature required in at-root expression");
+
+    if (!peek< alternatives< kwd_with_directive, kwd_without_directive > >()) {
+      css_error("Invalid CSS", " after ", ": expected \"with\" or \"without\", was ");
+    }
+
+    Expression_Obj feature = parse_list();
+    if (!lex_css< exactly<':'> >()) error("style declaration must contain a value");
+    Expression_Obj expression = parse_list();
+    List_Obj value = SASS_MEMORY_NEW(List, feature->pstate(), 1);
+
+    if (expression->concrete_type() == Expression::LIST) {
+        value = Cast<List>(expression);
+    }
+    else value->append(expression);
+
+    At_Root_Query_Obj cond = SASS_MEMORY_NEW(At_Root_Query,
+                                          value->pstate(),
+                                          feature,
+                                          value);
+    if (!lex_css< exactly<')'> >()) error("unclosed parenthesis in @at-root expression");
+    return cond;
+  }
+
+  Directive_Obj Parser::parse_special_directive()
+  {
+    std::string kwd(lexed);
+
+    if (lexed == "@else") error("Invalid CSS: @else must come after @if");
+
+    // this whole branch is never hit via spec tests
+
+    Directive_Ptr at_rule = SASS_MEMORY_NEW(Directive, pstate, kwd);
+    Lookahead lookahead = lookahead_for_include(position);
+    if (lookahead.found && !lookahead.has_interpolants) {
+      at_rule->selector(parse_selector_list(false));
+    }
+
+    lex < css_comments >(false);
+
+    if (lex < static_property >()) {
+      at_rule->value(parse_interpolated_chunk(Token(lexed)));
+    } else if (!(peek < alternatives < exactly<'{'>, exactly<'}'>, exactly<';'> > >())) {
+      at_rule->value(parse_list());
+    }
+
+    lex < css_comments >(false);
+
+    if (peek< exactly<'{'> >()) {
+      at_rule->block(parse_block());
+    }
+
+    return at_rule;
+  }
+
+  // this whole branch is never hit via spec tests
+  Directive_Obj Parser::parse_prefixed_directive()
+  {
+    std::string kwd(lexed);
+
+    if (lexed == "@else") error("Invalid CSS: @else must come after @if");
+
+    Directive_Obj at_rule = SASS_MEMORY_NEW(Directive, pstate, kwd);
+    Lookahead lookahead = lookahead_for_include(position);
+    if (lookahead.found && !lookahead.has_interpolants) {
+      at_rule->selector(parse_selector_list(false));
+    }
+
+    lex < css_comments >(false);
+
+    if (lex < static_property >()) {
+      at_rule->value(parse_interpolated_chunk(Token(lexed)));
+    } else if (!(peek < alternatives < exactly<'{'>, exactly<'}'>, exactly<';'> > >())) {
+      at_rule->value(parse_list());
+    }
+
+    lex < css_comments >(false);
+
+    if (peek< exactly<'{'> >()) {
+      at_rule->block(parse_block());
+    }
+
+    return at_rule;
+  }
+
+
+  Directive_Obj Parser::parse_directive()
+  {
+    Directive_Obj directive = SASS_MEMORY_NEW(Directive, pstate, lexed);
+    String_Schema_Obj val = parse_almost_any_value();
+    // strip left and right if they are of type string
+    directive->value(val);
+    if (peek< exactly<'{'> >()) {
+      directive->block(parse_block());
+    }
+    return directive;
+  }
+
+  Expression_Obj Parser::lex_interpolation()
+  {
+    if (lex < interpolant >(true) != NULL) {
+      return parse_interpolated_chunk(lexed, true);
+    }
+    return 0;
+  }
+
+  Expression_Obj Parser::lex_interp_uri()
+  {
+    // create a string schema by lexing optional interpolations
+    return lex_interp< re_string_uri_open, re_string_uri_close >();
+  }
+
+  Expression_Obj Parser::lex_interp_string()
+  {
+    Expression_Obj rv;
+    if ((rv = lex_interp< re_string_double_open, re_string_double_close >())) return rv;
+    if ((rv = lex_interp< re_string_single_open, re_string_single_close >())) return rv;
+    return rv;
+  }
+
+  Expression_Obj Parser::lex_almost_any_value_chars()
+  {
+    const char* match =
+    lex <
+      one_plus <
+        alternatives <
+          sequence <
+            exactly <'\\'>,
+            any_char
+          >,
+          sequence <
+            negate <
+              sequence <
+                exactly < url_kwd >,
+                exactly <'('>
+              >
+            >,
+            neg_class_char <
+              almost_any_value_class
+            >
+          >,
+          sequence <
+            exactly <'/'>,
+            negate <
+              alternatives <
+                exactly <'/'>,
+                exactly <'*'>
+              >
+            >
+          >,
+          sequence <
+            exactly <'\\'>,
+            exactly <'#'>,
+            negate <
+              exactly <'{'>
+            >
+          >,
+          sequence <
+            exactly <'!'>,
+            negate <
+              alpha
+            >
+          >
+        >
+      >
+    >(false);
+    if (match) {
+      return SASS_MEMORY_NEW(String_Constant, pstate, lexed);
+    }
+    return NULL;
+  }
+
+  Expression_Obj Parser::lex_almost_any_value_token()
+  {
+    Expression_Obj rv;
+    if (*position == 0) return 0;
+    if ((rv = lex_almost_any_value_chars())) return rv;
+    // if ((rv = lex_block_comment())) return rv;
+    // if ((rv = lex_single_line_comment())) return rv;
+    if ((rv = lex_interp_string())) return rv;
+    if ((rv = lex_interp_uri())) return rv;
+    if ((rv = lex_interpolation())) return rv;
+    return rv;
+  }
+
+  String_Schema_Obj Parser::parse_almost_any_value()
+  {
+
+    String_Schema_Obj schema = SASS_MEMORY_NEW(String_Schema, pstate);
+    if (*position == 0) return 0;
+    lex < spaces >(false);
+    Expression_Obj token = lex_almost_any_value_token();
+    if (!token) return 0;
+    schema->append(token);
+    if (*position == 0) {
+      schema->rtrim();
+      return schema.detach();
+    }
+
+    while ((token = lex_almost_any_value_token())) {
+      schema->append(token);
+    }
+
+    lex < css_whitespace >();
+
+    schema->rtrim();
+
+    return schema.detach();
+  }
+
+  Warning_Obj Parser::parse_warning()
+  {
+    if (stack.back() != Scope::Root &&
+        stack.back() != Scope::Function &&
+        stack.back() != Scope::Mixin &&
+        stack.back() != Scope::Control &&
+        stack.back() != Scope::Rules) {
+      error("Illegal nesting: Only properties may be nested beneath properties.");
+    }
+    return SASS_MEMORY_NEW(Warning, pstate, parse_list(DELAYED));
+  }
+
+  Error_Obj Parser::parse_error()
+  {
+    if (stack.back() != Scope::Root &&
+        stack.back() != Scope::Function &&
+        stack.back() != Scope::Mixin &&
+        stack.back() != Scope::Control &&
+        stack.back() != Scope::Rules) {
+      error("Illegal nesting: Only properties may be nested beneath properties.");
+    }
+    return SASS_MEMORY_NEW(Error, pstate, parse_list(DELAYED));
+  }
+
+  Debug_Obj Parser::parse_debug()
+  {
+    if (stack.back() != Scope::Root &&
+        stack.back() != Scope::Function &&
+        stack.back() != Scope::Mixin &&
+        stack.back() != Scope::Control &&
+        stack.back() != Scope::Rules) {
+      error("Illegal nesting: Only properties may be nested beneath properties.");
+    }
+    return SASS_MEMORY_NEW(Debug, pstate, parse_list(DELAYED));
+  }
+
+  Return_Obj Parser::parse_return_directive()
+  {
+    // check that we do not have an empty list (ToDo: check if we got all cases)
+    if (peek_css < alternatives < exactly < ';' >, exactly < '}' >, end_of_file > >())
+    { css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was "); }
+    return SASS_MEMORY_NEW(Return, pstate, parse_list());
+  }
+
+  Lookahead Parser::lookahead_for_selector(const char* start)
+  {
+    // init result struct
+    Lookahead rv = Lookahead();
+    // get start position
+    const char* p = start ? start : position;
+    // match in one big "regex"
+    rv.error = p;
+    if (const char* q =
+      peek <
+        re_selector_list
+      >(p)
+    ) {
+      bool could_be_property = peek< sequence< exactly<'-'>, exactly<'-'> > >(p) != 0;
+      while (p < q) {
+        // did we have interpolations?
+        if (*p == '#' && *(p+1) == '{') {
+          rv.has_interpolants = true;
+          p = q; break;
+        }
+        // A property that's ambiguous with a nested selector is interpreted as a
+        // custom property.
+        if (*p == ':') {
+          rv.is_custom_property = could_be_property || p+1 == q || peek< space >(p+1);
+        }
+        ++ p;
+      }
+      // store anyway  }
+
+
+      // ToDo: remove
+      rv.error = q;
+      rv.position = q;
+      // check expected opening bracket
+      // only after successfull matching
+      if (peek < exactly<'{'> >(q)) rv.found = q;
+      // else if (peek < end_of_file >(q)) rv.found = q;
+      else if (peek < exactly<'('> >(q)) rv.found = q;
+      // else if (peek < exactly<';'> >(q)) rv.found = q;
+      // else if (peek < exactly<'}'> >(q)) rv.found = q;
+      if (rv.found || *p == 0) rv.error = 0;
+    }
+
+    rv.parsable = ! rv.has_interpolants;
+
+    // return result
+    return rv;
+
+  }
+  // EO lookahead_for_selector
+
+  // used in parse_block_nodes and parse_special_directive
+  // ToDo: actual usage is still not really clear to me?
+  Lookahead Parser::lookahead_for_include(const char* start)
+  {
+    // we actually just lookahead for a selector
+    Lookahead rv = lookahead_for_selector(start);
+    // but the "found" rules are different
+    if (const char* p = rv.position) {
+      // check for additional abort condition
+      if (peek < exactly<';'> >(p)) rv.found = p;
+      else if (peek < exactly<'}'> >(p)) rv.found = p;
+    }
+    // return result
+    return rv;
+  }
+  // EO lookahead_for_include
+
+  // look ahead for a token with interpolation in it
+  // we mostly use the result if there is an interpolation
+  // everything that passes here gets parsed as one schema
+  // meaning it will not be parsed as a space separated list
+  Lookahead Parser::lookahead_for_value(const char* start)
+  {
+    // init result struct
+    Lookahead rv = Lookahead();
+    // get start position
+    const char* p = start ? start : position;
+    // match in one big "regex"
+    if (const char* q =
+      peek <
+        non_greedy <
+          alternatives <
+            // consume whitespace
+            block_comment, // spaces,
+            // main tokens
+            sequence <
+              interpolant,
+              optional <
+                quoted_string
+              >
+            >,
+            identifier,
+            variable,
+            // issue #442
+            sequence <
+              parenthese_scope,
+              interpolant,
+              optional <
+                quoted_string
+              >
+            >
+          >,
+          sequence <
+            // optional_spaces,
+            alternatives <
+              // end_of_file,
+              exactly<'{'>,
+              exactly<'}'>,
+              exactly<';'>
+            >
+          >
+        >
+      >(p)
+    ) {
+      if (p == q) return rv;
+      while (p < q) {
+        // did we have interpolations?
+        if (*p == '#' && *(p+1) == '{') {
+          rv.has_interpolants = true;
+          p = q; break;
+        }
+        ++ p;
+      }
+      // store anyway
+      // ToDo: remove
+      rv.position = q;
+      // check expected opening bracket
+      // only after successful matching
+      if (peek < exactly<'{'> >(q)) rv.found = q;
+      else if (peek < exactly<';'> >(q)) rv.found = q;
+      else if (peek < exactly<'}'> >(q)) rv.found = q;
+    }
+
+    // return result
+    return rv;
+  }
+  // EO lookahead_for_value
+
+  void Parser::read_bom()
+  {
+    size_t skip = 0;
+    std::string encoding;
+    bool utf_8 = false;
+    switch ((unsigned char) source[0]) {
+    case 0xEF:
+      skip = check_bom_chars(source, end, utf_8_bom, 3);
+      encoding = "UTF-8";
+      utf_8 = true;
+      break;
+    case 0xFE:
+      skip = check_bom_chars(source, end, utf_16_bom_be, 2);
+      encoding = "UTF-16 (big endian)";
+      break;
+    case 0xFF:
+      skip = check_bom_chars(source, end, utf_16_bom_le, 2);
+      skip += (skip ? check_bom_chars(source, end, utf_32_bom_le, 4) : 0);
+      encoding = (skip == 2 ? "UTF-16 (little endian)" : "UTF-32 (little endian)");
+      break;
+    case 0x00:
+      skip = check_bom_chars(source, end, utf_32_bom_be, 4);
+      encoding = "UTF-32 (big endian)";
+      break;
+    case 0x2B:
+      skip = check_bom_chars(source, end, utf_7_bom_1, 4)
+           | check_bom_chars(source, end, utf_7_bom_2, 4)
+           | check_bom_chars(source, end, utf_7_bom_3, 4)
+           | check_bom_chars(source, end, utf_7_bom_4, 4)
+           | check_bom_chars(source, end, utf_7_bom_5, 5);
+      encoding = "UTF-7";
+      break;
+    case 0xF7:
+      skip = check_bom_chars(source, end, utf_1_bom, 3);
+      encoding = "UTF-1";
+      break;
+    case 0xDD:
+      skip = check_bom_chars(source, end, utf_ebcdic_bom, 4);
+      encoding = "UTF-EBCDIC";
+      break;
+    case 0x0E:
+      skip = check_bom_chars(source, end, scsu_bom, 3);
+      encoding = "SCSU";
+      break;
+    case 0xFB:
+      skip = check_bom_chars(source, end, bocu_1_bom, 3);
+      encoding = "BOCU-1";
+      break;
+    case 0x84:
+      skip = check_bom_chars(source, end, gb_18030_bom, 4);
+      encoding = "GB-18030";
+      break;
+    default: break;
+    }
+    if (skip > 0 && !utf_8) error("only UTF-8 documents are currently supported; your document appears to be " + encoding);
+    position += skip;
+  }
+
+  size_t check_bom_chars(const char* src, const char *end, const unsigned char* bom, size_t len)
+  {
+    size_t skip = 0;
+    if (src + len > end) return 0;
+    for (size_t i = 0; i < len; ++i, ++skip) {
+      if ((unsigned char) src[i] != bom[i]) return 0;
+    }
+    return skip;
+  }
+
+
+  Expression_Obj Parser::fold_operands(Expression_Obj base, std::vector<Expression_Obj>& operands, Operand op)
+  {
+    for (size_t i = 0, S = operands.size(); i < S; ++i) {
+      base = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), op, base, operands[i]);
+    }
+    return base;
+  }
+
+  Expression_Obj Parser::fold_operands(Expression_Obj base, std::vector<Expression_Obj>& operands, std::vector<Operand>& ops, size_t i)
+  {
+    if (String_Schema_Ptr schema = Cast<String_Schema>(base)) {
+      // return schema;
+      if (schema->has_interpolants()) {
+        if (i + 1 < operands.size() && (
+             (ops[0].operand == Sass_OP::EQ)
+          || (ops[0].operand == Sass_OP::ADD)
+          || (ops[0].operand == Sass_OP::DIV)
+          || (ops[0].operand == Sass_OP::MUL)
+          || (ops[0].operand == Sass_OP::NEQ)
+          || (ops[0].operand == Sass_OP::LT)
+          || (ops[0].operand == Sass_OP::GT)
+          || (ops[0].operand == Sass_OP::LTE)
+          || (ops[0].operand == Sass_OP::GTE)
+        )) {
+          Expression_Obj rhs = fold_operands(operands[i], operands, ops, i + 1);
+          rhs = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), ops[0], schema, rhs);
+          return rhs;
+        }
+        // return schema;
+      }
+    }
+
+    for (size_t S = operands.size(); i < S; ++i) {
+      if (String_Schema_Ptr schema = Cast<String_Schema>(operands[i])) {
+        if (schema->has_interpolants()) {
+          if (i + 1 < S) {
+            // this whole branch is never hit via spec tests
+            Expression_Obj rhs = fold_operands(operands[i+1], operands, ops, i + 2);
+            rhs = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), ops[i], schema, rhs);
+            base = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), ops[i], base, rhs);
+            return base;
+          }
+          base = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), ops[i], base, operands[i]);
+          return base;
+        } else {
+          base = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), ops[i], base, operands[i]);
+        }
+      } else {
+        base = SASS_MEMORY_NEW(Binary_Expression, base->pstate(), ops[i], base, operands[i]);
+      }
+      Binary_Expression_Ptr b = Cast<Binary_Expression>(base.ptr());
+      if (b && ops[i].operand == Sass_OP::DIV && b->left()->is_delayed() && b->right()->is_delayed()) {
+        base->is_delayed(true);
+      }
+    }
+    // nested binary expression are never to be delayed
+    if (Binary_Expression_Ptr b = Cast<Binary_Expression>(base)) {
+      if (Cast<Binary_Expression>(b->left())) base->set_delayed(false);
+      if (Cast<Binary_Expression>(b->right())) base->set_delayed(false);
+    }
+    return base;
+  }
+
+  void Parser::error(std::string msg, Position pos)
+  {
+    Position p(pos.line ? pos : before_token);
+    ParserState pstate(path, source, p, Offset(0, 0));
+    traces.push_back(Backtrace(pstate));
+    throw Exception::InvalidSass(pstate, traces, msg);
+  }
+
+  void Parser::error(std::string msg)
+  {
+    error(msg, pstate);
+  }
+
+  // print a css parsing error with actual context information from parsed source
+  void Parser::css_error(const std::string& msg, const std::string& prefix, const std::string& middle, const bool trim)
+  {
+    int max_len = 18;
+    const char* end = this->end;
+    while (*end != 0) ++ end;
+    const char* pos = peek < optional_spaces >();
+    if (!pos) pos = position;
+
+    const char* last_pos(pos);
+    if (last_pos > source) {
+      utf8::prior(last_pos, source);
+    }
+    // backup position to last significant char
+    while (trim && last_pos > source && last_pos < end) {
+      if (!Prelexer::is_space(*last_pos)) break;
+      utf8::prior(last_pos, source);
+    }
+
+    bool ellipsis_left = false;
+    const char* pos_left(last_pos);
+    const char* end_left(last_pos);
+
+    if (*pos_left) utf8::next(pos_left, end);
+    if (*end_left) utf8::next(end_left, end);
+    while (pos_left > source) {
+      if (utf8::distance(pos_left, end_left) >= max_len) {
+        utf8::prior(pos_left, source);
+        ellipsis_left = *(pos_left) != '\n' &&
+                        *(pos_left) != '\r';
+        utf8::next(pos_left, end);
+        break;
+      }
+
+      const char* prev = pos_left;
+      utf8::prior(prev, source);
+      if (*prev == '\r') break;
+      if (*prev == '\n') break;
+      pos_left = prev;
+    }
+    if (pos_left < source) {
+      pos_left = source;
+    }
+
+    bool ellipsis_right = false;
+    const char* end_right(pos);
+    const char* pos_right(pos);
+    while (end_right < end) {
+      if (utf8::distance(pos_right, end_right) > max_len) {
+        ellipsis_left = *(pos_right) != '\n' &&
+                        *(pos_right) != '\r';
+        break;
+      }
+      if (*end_right == '\r') break;
+      if (*end_right == '\n') break;
+      utf8::next(end_right, end);
+    }
+    // if (*end_right == 0) end_right ++;
+
+    std::string left(pos_left, end_left);
+    std::string right(pos_right, end_right);
+    size_t left_subpos = left.size() > 15 ? left.size() - 15 : 0;
+    size_t right_subpos = right.size() > 15 ? right.size() - 15 : 0;
+    if (left_subpos && ellipsis_left) left = ellipsis + left.substr(left_subpos);
+    if (right_subpos && ellipsis_right) right = right.substr(right_subpos) + ellipsis;
+    // Hotfix when source is null, probably due to interpolation parsing!?
+    if (source == NULL || *source == 0) source = pstate.src;
+    // now pass new message to the more generic error function
+    error(msg + prefix + quote(left) + middle + quote(right));
   }
 
 }
diff --git a/libsass/src/parser.hpp b/libsass/src/parser.hpp
--- a/libsass/src/parser.hpp
+++ b/libsass/src/parser.hpp
@@ -10,12 +10,22 @@
 #include "position.hpp"
 #include "prelexer.hpp"
 
+#ifndef MAX_NESTING
+// Note that this limit is not an exact science
+// it depends on various factors, which some are
+// not under our control (compile time or even OS
+// dependent settings on the available stack size)
+// It should fix most common segfault cases though.
+#define MAX_NESTING 512
+#endif
+
 struct Lookahead {
   const char* found;
   const char* error;
   const char* position;
   bool parsable;
   bool has_interpolants;
+  bool is_custom_property;
 };
 
 namespace Sass {
@@ -23,7 +33,7 @@
   class Parser : public ParserState {
   public:
 
-    enum Scope { Root, Mixin, Function, Media, Control, Properties, Rules };
+    enum Scope { Root, Mixin, Function, Media, Control, Properties, Rules, AtRoot };
 
     Context& ctx;
     std::vector<Block_Obj> block_stack;
@@ -35,23 +45,26 @@
     Position before_token;
     Position after_token;
     ParserState pstate;
-    int indentation;
-
+    Backtraces traces;
+    size_t indentation;
+    size_t nestings;
 
     Token lexed;
-    bool in_at_root;
 
-    Parser(Context& ctx, const ParserState& pstate)
+    Parser(Context& ctx, const ParserState& pstate, Backtraces traces)
     : ParserState(pstate), ctx(ctx), block_stack(), stack(0), last_media_block(),
-      source(0), position(0), end(0), before_token(pstate), after_token(pstate), pstate(pstate), indentation(0)
-    { in_at_root = false; stack.push_back(Scope::Root); }
+      source(0), position(0), end(0), before_token(pstate), after_token(pstate),
+      pstate(pstate), traces(traces), indentation(0), nestings(0)
+    { 
+      stack.push_back(Scope::Root);
+    }
 
     // static Parser from_string(const std::string& src, Context& ctx, ParserState pstate = ParserState("[STRING]"));
-    static Parser from_c_str(const char* src, Context& ctx, ParserState pstate = ParserState("[CSTRING]"), const char* source = 0);
-    static Parser from_c_str(const char* beg, const char* end, Context& ctx, ParserState pstate = ParserState("[CSTRING]"), const char* source = 0);
-    static Parser from_token(Token t, Context& ctx, ParserState pstate = ParserState("[TOKEN]"), const char* source = 0);
+    static Parser from_c_str(const char* src, Context& ctx, Backtraces, ParserState pstate = ParserState("[CSTRING]"), const char* source = 0);
+    static Parser from_c_str(const char* beg, const char* end, Context& ctx, Backtraces, ParserState pstate = ParserState("[CSTRING]"), const char* source = 0);
+    static Parser from_token(Token t, Context& ctx, Backtraces, ParserState pstate = ParserState("[TOKEN]"), const char* source = 0);
     // special static parsers to convert strings into certain selectors
-    static Selector_List_Obj parse_selector(const char* src, Context& ctx, ParserState pstate = ParserState("[SELECTOR]"), const char* source = 0);
+    static Selector_List_Obj parse_selector(const char* src, Context& ctx, Backtraces, ParserState pstate = ParserState("[SELECTOR]"), const char* source = 0);
 
 #ifdef __clang__
 
@@ -100,7 +113,7 @@
 
     }
 
-    // peek will only skip over space, tabs and line comment
+    // match will not skip over space, tabs and line comment
     // return the position where the lexer match will occur
     template <Prelexer::prelexer mx>
     const char* match(const char* start = 0)
@@ -223,12 +236,14 @@
 
 #endif
 
+    void error(std::string msg);
     void error(std::string msg, Position pos);
     // generate message with given and expected sample
     // text before and in the middle are configurable
     void css_error(const std::string& msg,
                    const std::string& prefix = " after ",
-                   const std::string& middle = ", was: ");
+                   const std::string& middle = ", was: ",
+                   const bool trim = true);
     void read_bom();
 
     Block_Obj parse();
@@ -240,10 +255,10 @@
     Arguments_Obj parse_arguments();
     Argument_Obj parse_argument();
     Assignment_Obj parse_assignment();
-    Ruleset_Obj parse_ruleset(Lookahead lookahead, bool is_root = false);
-    Selector_Schema_Obj parse_selector_schema(const char* end_of_selector);
-    Selector_List_Obj parse_selector_list(bool at_root = false);
-    Complex_Selector_Obj parse_complex_selector(bool in_root = true);
+    Ruleset_Obj parse_ruleset(Lookahead lookahead);
+    Selector_List_Obj parse_selector_list(bool chroot);
+    Complex_Selector_Obj parse_complex_selector(bool chroot);
+    Selector_Schema_Obj parse_selector_schema(const char* end_of_selector, bool chroot);
     Compound_Selector_Obj parse_compound_selector();
     Simple_Selector_Obj parse_simple_selector();
     Wrapped_Selector_Obj parse_negated_selector();
@@ -257,6 +272,7 @@
     bool parse_number_prefix();
     Declaration_Obj parse_declaration();
     Expression_Obj parse_map();
+    Expression_Obj parse_bracket_list();
     Expression_Obj parse_list(bool delayed = false);
     Expression_Obj parse_comma_list(bool delayed = false);
     Expression_Obj parse_space_list();
@@ -272,9 +288,11 @@
     Function_Call_Schema_Obj parse_function_call_schema();
     String_Obj parse_url_function_string();
     String_Obj parse_url_function_argument();
-    String_Obj parse_interpolated_chunk(Token, bool constant = false);
+    String_Obj parse_interpolated_chunk(Token, bool constant = false, bool css = true);
     String_Obj parse_string();
     String_Constant_Obj parse_static_value();
+    String_Schema_Obj parse_css_variable_value(bool top_level = true);
+    String_Schema_Obj parse_css_variable_value_token(bool top_level = true);
     String_Obj parse_ie_property();
     String_Obj parse_ie_keyword_arg();
     String_Schema_Obj parse_value_schema(const char* stop);
@@ -340,15 +358,15 @@
         schema->append(SASS_MEMORY_NEW(String_Constant, pstate, lexed));
         if (position[0] == '#' && position[1] == '{') {
           Expression_Obj itpl = lex_interpolation();
-          if (&itpl) schema->append(&itpl);
+          if (!itpl.isNull()) schema->append(itpl);
           while (lex < close >(false)) {
             // std::cerr << "LEX [[" << std::string(lexed) << "]]\n";
             schema->append(SASS_MEMORY_NEW(String_Constant, pstate, lexed));
             if (position[0] == '#' && position[1] == '{') {
               Expression_Obj itpl = lex_interpolation();
-              if (&itpl) schema->append(&itpl);
+              if (!itpl.isNull()) schema->append(itpl);
             } else {
-              return &schema;
+              return schema;
             }
           }
         } else {
@@ -357,6 +375,21 @@
       }
       return 0;
     }
+
+  public:
+    static Number_Ptr lexed_number(const ParserState& pstate, const std::string& parsed);
+    static Number_Ptr lexed_dimension(const ParserState& pstate, const std::string& parsed);
+    static Number_Ptr lexed_percentage(const ParserState& pstate, const std::string& parsed);
+    static Expression_Ptr lexed_hex_color(const ParserState& pstate, const std::string& parsed);
+  private:
+    Number_Ptr lexed_number(const std::string& parsed) { return lexed_number(pstate, parsed); };
+    Number_Ptr lexed_dimension(const std::string& parsed) { return lexed_dimension(pstate, parsed); };
+    Number_Ptr lexed_percentage(const std::string& parsed) { return lexed_percentage(pstate, parsed); };
+    Expression_Ptr lexed_hex_color(const std::string& parsed) { return lexed_hex_color(pstate, parsed); };
+
+    static const char* re_attr_sensitive_close(const char* src);
+    static const char* re_attr_insensitive_close(const char* src);
+
   };
 
   size_t check_bom_chars(const char* src, const char *end, const unsigned char* bom, size_t len);
diff --git a/libsass/src/plugins.cpp b/libsass/src/plugins.cpp
--- a/libsass/src/plugins.cpp
+++ b/libsass/src/plugins.cpp
@@ -1,3 +1,8 @@
+#include "sass.hpp"
+#include <iostream>
+#include "output.hpp"
+#include "plugins.hpp"
+
 #ifdef _WIN32
 #include <windows.h>
 #else
@@ -7,15 +12,21 @@
 #include <dlfcn.h>
 #endif
 
-#include "sass.hpp"
-#include <iostream>
-#include "output.hpp"
-#include "plugins.hpp"
-
 namespace Sass {
 
   Plugins::Plugins(void) { }
-  Plugins::~Plugins(void) { }
+  Plugins::~Plugins(void)
+  {
+    for (auto function : functions) {
+      sass_delete_function(function);
+    }
+    for (auto importer : importers) {
+      sass_delete_importer(importer);
+    }
+    for (auto header : headers) {
+      sass_delete_importer(header);
+    }
+  }
 
   // check if plugin is compatible with this version
   // plugins may be linked static against libsass
@@ -57,20 +68,23 @@
         // try to get import address for "libsass_load_functions"
         if (LOAD_LIB_FN(__plugin_load_fns__, plugin_load_functions, "libsass_load_functions"))
         {
-          Sass_Function_List fns = plugin_load_functions();
+          Sass_Function_List fns = plugin_load_functions(), _p = fns;
           while (fns && *fns) { functions.push_back(*fns); ++ fns; }
+          sass_free_memory(_p); // only delete the container, items not yet
         }
         // try to get import address for "libsass_load_importers"
         if (LOAD_LIB_FN(__plugin_load_imps__, plugin_load_importers, "libsass_load_importers"))
         {
-          Sass_Importer_List imps = plugin_load_importers();
+          Sass_Importer_List imps = plugin_load_importers(), _p = imps;
           while (imps && *imps) { importers.push_back(*imps); ++ imps; }
+          sass_free_memory(_p); // only delete the container, items not yet
         }
         // try to get import address for "libsass_load_headers"
         if (LOAD_LIB_FN(__plugin_load_imps__, plugin_load_headers, "libsass_load_headers"))
         {
-          Sass_Importer_List imps = plugin_load_headers();
+          Sass_Importer_List imps = plugin_load_headers(), _p = imps;
           while (imps && *imps) { headers.push_back(*imps); ++ imps; }
+          sass_free_memory(_p); // only delete the container, items not yet
         }
         // success
         return true;
@@ -153,7 +167,11 @@
       struct dirent *dirp;
       if((dp  = opendir(path.c_str())) == NULL) return -1;
       while ((dirp = readdir(dp)) != NULL) {
-        if (!ends_with(dirp->d_name, ".so")) continue;
+        #if __APPLE__
+          if (!ends_with(dirp->d_name, ".dylib")) continue;
+        #else
+          if (!ends_with(dirp->d_name, ".so")) continue;
+        #endif
         if (load_plugin(path + dirp->d_name)) ++ loaded;
       }
       closedir(dp);
diff --git a/libsass/src/position.cpp b/libsass/src/position.cpp
--- a/libsass/src/position.cpp
+++ b/libsass/src/position.cpp
@@ -4,6 +4,11 @@
 namespace Sass {
 
 
+  Offset::Offset(const char chr)
+  : line(chr == '\n' ? 1 : 0),
+    column(chr == '\n' ? 0 : 1)
+  {}
+
   Offset::Offset(const char* string)
   : line(0), column(0)
   {
@@ -32,7 +37,6 @@
 
   // increase offset by given string (mostly called by lexer)
   // increase line counter and count columns on the last line
-  // ToDo: make the col count utf8 aware
   Offset Offset::add(const char* begin, const char* end)
   {
     if (end == 0) return *this;
@@ -42,9 +46,23 @@
         // start new line
         column = 0;
       } else {
-        ++ column;
+        // do not count any utf8 continuation bytes
+        // https://stackoverflow.com/a/9356203/1550314
+        // https://en.wikipedia.org/wiki/UTF-8#Description
+        unsigned char chr = *begin;
+        // skip over 10xxxxxx
+        // is 1st bit not set
+        if ((chr & 128) == 0) {
+          // regular ascii char
+          column += 1;
+        }
+        // is 2nd bit not set
+        else if ((chr & 64) == 0) {
+          // first utf8 byte
+          column += 1;
+        }
       }
-      ++begin;
+      ++ begin;
     }
     return *this;
   }
diff --git a/libsass/src/position.hpp b/libsass/src/position.hpp
--- a/libsass/src/position.hpp
+++ b/libsass/src/position.hpp
@@ -11,6 +11,7 @@
   class Offset {
 
     public: // c-tor
+      Offset(const char chr);
       Offset(const char* string);
       Offset(const std::string& text);
       Offset(const size_t line, const size_t column);
@@ -85,7 +86,7 @@
 
     size_t length()    const { return end - begin; }
     std::string ws_before() const { return std::string(prefix, begin); }
-    std::string to_string() const { return std::string(begin, end); }
+    const std::string to_string() const { return std::string(begin, end); }
     std::string time_wspace() const {
       std::string str(to_string());
       std::string whitespaces(" \t\f\v\n\r");
diff --git a/libsass/src/prelexer.cpp b/libsass/src/prelexer.cpp
--- a/libsass/src/prelexer.cpp
+++ b/libsass/src/prelexer.cpp
@@ -1,6 +1,5 @@
 #include "sass.hpp"
 #include <cctype>
-#include <cstddef>
 #include <iostream>
 #include <iomanip>
 #include "util.hpp"
@@ -438,6 +437,10 @@
         optional <
           sequence <
           exactly <'/'>,
+          negate < sequence <
+            exactly < calc_fn_kwd >,
+            exactly < '(' >
+          > >,
           multiple_units
         > >
       >(src);
@@ -577,7 +580,7 @@
     const char* value_combinations(const char* src) {
       // `2px-2px` is invalid combo
       bool was_number = false;
-      const char* pos = src;
+      const char* pos;
       while (src) {
         if ((pos = alternatives < quoted_string, identifier, percentage, hex >(src))) {
           was_number = false;
@@ -643,10 +646,7 @@
             >,
             sequence <
               negate <
-                sequence <
-                  exactly < url_kwd >,
-                  exactly <'('>
-                >
+                uri_prefix
               >,
               neg_class_char <
                 almost_any_value_class
@@ -998,7 +998,17 @@
                           digits>(src);
     }
     const char* number(const char* src) {
-      return sequence< optional<sign>, unsigned_number>(src);
+      return sequence<
+          optional<sign>,
+          unsigned_number,
+          optional<
+            sequence<
+              exactly<'e'>,
+              optional<sign>,
+              unsigned_number
+            >
+          >
+        >(src);
     }
     const char* coefficient(const char* src) {
       return alternatives< sequence< optional<sign>, digits >,
@@ -1037,7 +1047,7 @@
     const char* hexa(const char* src) {
       const char* p = sequence< exactly<'#'>, one_plus<xdigit> >(src);
       ptrdiff_t len = p - src;
-      return (len != 4 && len != 7 && len != 9) ? 0 : p;
+      return (len != 5 && len != 9) ? 0 : p;
     }
     const char* hex0(const char* src) {
       const char* p = sequence< exactly<'0'>, exactly<'x'>, one_plus<xdigit> >(src);
@@ -1047,7 +1057,7 @@
 
     /* no longer used - remove?
     const char* rgb_prefix(const char* src) {
-      return word<rgb_kwd>(src);
+      return word<rgb_fn_kwd>(src);
     }*/
     // Match CSS uri specifiers.
 
@@ -1161,7 +1171,7 @@
     }
     // Match the CSS negation pseudo-class.
     const char* pseudo_not(const char* src) {
-      return word< pseudo_not_kwd >(src);
+      return word< pseudo_not_fn_kwd >(src);
     }
     // Match CSS 'odd' and 'even' keywords for functional pseudo-classes.
     const char* even(const char* src) {
@@ -1269,7 +1279,7 @@
             optional_css_whitespace,
             exactly<'='>,
             optional_css_whitespace,
-            alternatives< variable, identifier_schema, identifier, quoted_string, number, hexa >,
+            alternatives< variable, identifier_schema, identifier, quoted_string, number, hex, hexa >,
             zero_plus< sequence<
               optional_css_whitespace,
               exactly<','>,
@@ -1279,7 +1289,7 @@
                 optional_css_whitespace,
                 exactly<'='>,
                 optional_css_whitespace,
-                alternatives< variable, identifier_schema, identifier, quoted_string, number, hexa >
+                alternatives< variable, identifier_schema, identifier, quoted_string, number, hex, hexa >
               >
             > >
           > >,
@@ -1314,6 +1324,7 @@
           identifier,
           quoted_string,
           number,
+          hex,
           hexa,
           sequence <
             exactly < '(' >,
@@ -1420,7 +1431,29 @@
       >(src);
     }
 
+    const char* list_terminator(const char* src) {
+      return alternatives <
+        exactly<';'>,
+        exactly<'}'>,
+        exactly<'{'>,
+        exactly<')'>,
+        exactly<']'>,
+        exactly<':'>,
+        end_of_file,
+        exactly<ellipsis>,
+        default_flag,
+        global_flag
+      >(src);
+    };
 
+    const char* space_list_terminator(const char* src) {
+      return alternatives <
+        exactly<','>,
+        list_terminator
+      >(src);
+    };
+
+
     // const char* real_uri_prefix(const char* src) {
     //   return alternatives<
     //     exactly< url_kwd >,
@@ -1428,6 +1461,16 @@
     //   >(src);
     // }
 
+    const char* real_uri(const char* src) {
+      return sequence<
+        exactly< url_kwd >,
+        exactly< '(' >,
+        W,
+        real_uri_value,
+        exactly< ')' >
+      >(src);
+    }
+
     const char* real_uri_suffix(const char* src) {
       return sequence< W, exactly< ')' > >(src);
     }
@@ -1478,6 +1521,7 @@
                            static_string,
                            percentage,
                            hex,
+                           hexa,
                            exactly<'|'>,
                            // exactly<'+'>,
                            sequence < number, unit_identifier >,
@@ -1545,6 +1589,40 @@
                       >(src);
     }
 
+    extern const char css_variable_url_negates[] = "()[]{}\"'#/";
+    const char* css_variable_value(const char* src) {
+      return sequence<
+        alternatives<
+          sequence<
+            negate< exactly< url_fn_kwd > >,
+            one_plus< neg_class_char< css_variable_url_negates > >
+          >,
+          sequence< exactly<'#'>, negate< exactly<'{'> > >,
+          sequence< exactly<'/'>, negate< exactly<'*'> > >,
+          static_string,
+          real_uri,
+          block_comment
+        >
+      >(src);
+    }
+
+    extern const char css_variable_url_top_level_negates[] = "()[]{}\"'#/;!";
+    const char* css_variable_top_level_value(const char* src) {
+      return sequence<
+        alternatives<
+          sequence<
+            negate< exactly< url_fn_kwd > >,
+            one_plus< neg_class_char< css_variable_url_top_level_negates > >
+          >,
+          sequence< exactly<'#'>, negate< exactly<'{'> > >,
+          sequence< exactly<'/'>, negate< exactly<'*'> > >,
+          static_string,
+          real_uri,
+          block_comment
+        >
+      >(src);
+    }
+
     const char* parenthese_scope(const char* src) {
       return sequence <
         exactly < '(' >,
@@ -1578,7 +1656,7 @@
             class_char < selector_lookahead_ops >,
             // match selector combinators /[>+~]/
             class_char < selector_combinator_ops >,
-            // match attribute compare operators
+            // match pseudo selectors
             sequence <
               exactly <'('>,
               optional_spaces,
@@ -1586,6 +1664,7 @@
               optional_spaces,
               exactly <')'>
             >,
+            // match attribute compare operators
             alternatives <
               exact_match, class_match, dash_match,
               prefix_match, suffix_match, substring_match
@@ -1604,12 +1683,21 @@
                 // class match
                 exactly <'.'>,
                 // single or double colon
-                optional < pseudo_prefix >
+                sequence <
+                  optional < pseudo_prefix >,
+                  // fix libsass issue 2376
+                  negate < uri_prefix >
+                >
               >,
               // accept hypens in token
               one_plus < sequence <
                 // can start with hyphens
-                zero_plus < exactly<'-'> >,
+                zero_plus <
+                  sequence <
+                    exactly <'-'>,
+                    optional_spaces
+                  >
+                >,
                 // now the main token
                 alternatives <
                   kwd_optional,
@@ -1636,10 +1724,7 @@
       return sequence< optional<namespace_schema>, identifier>(src);
     }
     const char* re_type_selector(const char* src) {
-      return alternatives< type_selector, universal, quoted_string, dimension, percentage, number, identifier_alnums >(src);
-    }
-    const char* re_type_selector2(const char* src) {
-      return alternatives< type_selector, universal, quoted_string, dimension, percentage, number, identifier_alnums >(src);
+      return alternatives< type_selector, universal, dimension, percentage, number, identifier_alnums >(src);
     }
     const char* re_static_expression(const char* src) {
       return sequence< number, optional_spaces, exactly<'/'>, optional_spaces, number >(src);
diff --git a/libsass/src/prelexer.hpp b/libsass/src/prelexer.hpp
--- a/libsass/src/prelexer.hpp
+++ b/libsass/src/prelexer.hpp
@@ -46,7 +46,7 @@
       src = exactly<beg>(src);
       if (!src) return 0;
       const char* stop;
-      while (1) {
+      while (true) {
         if (!*src) return 0;
         stop = exactly<end>(src);
         if (stop && (!esc || *(src - 1) != '\\')) return stop;
@@ -139,7 +139,7 @@
       src = exactly<beg>(src);
       if (!src) return 0;
       const char* stop;
-      while (1) {
+      while (true) {
         if (!*src) return 0;
         stop = exactly<end>(src);
         if (stop && (!esc || *(src - 1) != '\\')) return stop;
@@ -264,7 +264,6 @@
     const char* kwd_while_directive(const char* src);
 
     const char* re_nothing(const char* src);
-    const char* re_type_selector2(const char* src);
 
     const char* re_special_fun(const char* src);
 
@@ -355,6 +354,10 @@
     const char* ie_keyword_arg_value(const char* src);
     const char* ie_keyword_arg_property(const char* src);
 
+    // characters that terminate parsing of a list
+    const char* list_terminator(const char* src);
+    const char* space_list_terminator(const char* src);
+
     // match url()
     const char* H(const char* src);
     const char* W(const char* src);
@@ -362,6 +365,7 @@
     const char* UUNICODE(const char* src);
     const char* NONASCII(const char* src);
     const char* ESCAPE(const char* src);
+    const char* real_uri(const char* src);
     const char* real_uri_suffix(const char* src);
     // const char* real_uri_prefix(const char* src);
     const char* real_uri_value(const char* src);
@@ -375,6 +379,9 @@
     const char* static_component(const char* src);
     const char* static_property(const char* src);
     const char* static_value(const char* src);
+
+    const char* css_variable_value(const char* src);
+    const char* css_variable_top_level_value(const char* src);
 
     // Utility functions for finding and counting characters in a string.
     template<char c>
diff --git a/libsass/src/remove_placeholders.cpp b/libsass/src/remove_placeholders.cpp
--- a/libsass/src/remove_placeholders.cpp
+++ b/libsass/src/remove_placeholders.cpp
@@ -6,13 +6,12 @@
 
 namespace Sass {
 
-    Remove_Placeholders::Remove_Placeholders(Context& ctx)
-    : ctx(ctx)
+    Remove_Placeholders::Remove_Placeholders()
     { }
 
     void Remove_Placeholders::operator()(Block_Ptr b) {
         for (size_t i = 0, L = b->length(); i < L; ++i) {
-            Statement_Ptr st = &b->at(i);
+            Statement_Ptr st = b->at(i);
             st->perform(this);
         }
     }
@@ -34,19 +33,19 @@
 
     void Remove_Placeholders::operator()(Ruleset_Ptr r) {
         // Create a new selector group without placeholders
-        Selector_List_Obj sl = SASS_MEMORY_CAST(Selector_List, r->selector());
+        Selector_List_Obj sl = Cast<Selector_List>(r->selector());
 
         if (sl) {
           // Set the new placeholder selector list
-          r->selector(remove_placeholders(&sl));
+          r->selector(remove_placeholders(sl));
           // Remove placeholders in wrapped selectors
           for (Complex_Selector_Obj cs : sl->elements()) {
             while (cs) {
               if (cs->head()) {
                 for (Simple_Selector_Obj& ss : cs->head()->elements()) {
-                  if (Wrapped_Selector_Ptr ws = SASS_MEMORY_CAST(Wrapped_Selector, ss)) {
-                    if (Selector_List_Ptr sl = SASS_MEMORY_CAST(Selector_List, ws->selector())) {
-                      Selector_List_Ptr clean = remove_placeholders(sl);
+                  if (Wrapped_Selector_Ptr ws = Cast<Wrapped_Selector>(ss)) {
+                    if (Selector_List_Ptr wsl = Cast<Selector_List>(ws->selector())) {
+                      Selector_List_Ptr clean = remove_placeholders(wsl);
                       // also clean superflous parent selectors
                       // probably not really the correct place
                       clean->remove_parent_selectors();
@@ -72,10 +71,10 @@
     }
 
     void Remove_Placeholders::operator()(Media_Block_Ptr m) {
-        operator()(&m->block());
+        operator()(m->block());
     }
     void Remove_Placeholders::operator()(Supports_Block_Ptr m) {
-        operator()(&m->block());
+        operator()(m->block());
     }
 
     void Remove_Placeholders::operator()(Directive_Ptr a) {
diff --git a/libsass/src/remove_placeholders.hpp b/libsass/src/remove_placeholders.hpp
--- a/libsass/src/remove_placeholders.hpp
+++ b/libsass/src/remove_placeholders.hpp
@@ -9,19 +9,15 @@
 namespace Sass {
 
 
-    class Context;
-
     class Remove_Placeholders : public Operation_CRTP<void, Remove_Placeholders> {
 
-        Context&          ctx;
-
         void fallback_impl(AST_Node_Ptr n) {}
 
     public:
       Selector_List_Ptr remove_placeholders(Selector_List_Ptr);
 
     public:
-        Remove_Placeholders(Context&);
+        Remove_Placeholders();
         ~Remove_Placeholders() { }
 
         void operator()(Block_Ptr);
diff --git a/libsass/src/sass.cpp b/libsass/src/sass.cpp
--- a/libsass/src/sass.cpp
+++ b/libsass/src/sass.cpp
@@ -7,7 +7,24 @@
 #include "sass.h"
 #include "file.hpp"
 #include "util.hpp"
+#include "sass_context.hpp"
+#include "sass_functions.hpp"
 
+namespace Sass {
+
+  // helper to convert string list to vector
+  std::vector<std::string> list2vec(struct string_list* cur)
+  {
+    std::vector<std::string> list;
+    while (cur) {
+      list.push_back(cur->string);
+      cur = cur->next;
+    }
+    return list;
+  }
+
+}
+
 extern "C" {
   using namespace Sass;
 
@@ -49,11 +66,50 @@
     return sass_copy_c_string(unquoted.c_str());
   }
 
+  char* ADDCALL sass_compiler_find_include (const char* file, struct Sass_Compiler* compiler)
+  {
+    // get the last import entry to get current base directory
+    Sass_Import_Entry import = sass_compiler_get_last_import(compiler);
+    const std::vector<std::string>& incs = compiler->cpp_ctx->include_paths;
+    // create the vector with paths to lookup
+    std::vector<std::string> paths(1 + incs.size());
+    paths.push_back(File::dir_name(import->abs_path));
+    paths.insert( paths.end(), incs.begin(), incs.end() );
+    // now resolve the file path relative to lookup paths
+    std::string resolved(File::find_include(file, paths));
+    return sass_copy_c_string(resolved.c_str());
+  }
+
+  char* ADDCALL sass_compiler_find_file (const char* file, struct Sass_Compiler* compiler)
+  {
+    // get the last import entry to get current base directory
+    Sass_Import_Entry import = sass_compiler_get_last_import(compiler);
+    const std::vector<std::string>& incs = compiler->cpp_ctx->include_paths;
+    // create the vector with paths to lookup
+    std::vector<std::string> paths(1 + incs.size());
+    paths.push_back(File::dir_name(import->abs_path));
+    paths.insert( paths.end(), incs.begin(), incs.end() );
+    // now resolve the file path relative to lookup paths
+    std::string resolved(File::find_file(file, paths));
+    return sass_copy_c_string(resolved.c_str());
+  }
+
   // Make sure to free the returned value!
   // Incs array has to be null terminated!
-  char* ADDCALL sass_resolve_file (const char* file, const char* paths[])
+  // this has the original resolve logic for sass include
+  char* ADDCALL sass_find_include (const char* file, struct Sass_Options* opt)
   {
-    std::string resolved(File::find_file(file, paths));
+    std::vector<std::string> vec(list2vec(opt->include_paths));
+    std::string resolved(File::find_include(file, vec));
+    return sass_copy_c_string(resolved.c_str());
+  }
+
+  // Make sure to free the returned value!
+  // Incs array has to be null terminated!
+  char* ADDCALL sass_find_file (const char* file, struct Sass_Options* opt)
+  {
+    std::vector<std::string> vec(list2vec(opt->include_paths));
+    std::string resolved(File::find_file(file, vec));
     return sass_copy_c_string(resolved.c_str());
   }
 
diff --git a/libsass/src/sass.hpp b/libsass/src/sass.hpp
--- a/libsass/src/sass.hpp
+++ b/libsass/src/sass.hpp
@@ -90,10 +90,13 @@
   // Precision for fractional numbers
   int precision;
 
+  // Do not compress colors in selectors
+  bool in_selector;
+
   // initialization list (constructor with defaults)
   Sass_Inspect_Options(Sass_Output_Style style = Sass::NESTED,
-                       int precision = 5)
-  : output_style(style), precision(precision)
+                       int precision = 5, bool in_selector = false)
+  : output_style(style), precision(precision), in_selector(in_selector)
   { }
 
 };
diff --git a/libsass/src/sass_context.cpp b/libsass/src/sass_context.cpp
--- a/libsass/src/sass_context.cpp
+++ b/libsass/src/sass_context.cpp
@@ -35,7 +35,6 @@
     catch (Exception::Base& e) {
       std::stringstream msg_stream;
       std::string cwd(Sass::File::get_cwd());
-
       std::string msg_prefix(e.errtype());
       bool got_newline = false;
       msg_stream << msg_prefix << ": ";
@@ -55,41 +54,49 @@
         ++msg;
       }
       if (!got_newline) msg_stream << "\n";
-      if (e.import_stack) {
-        for (size_t i = 1; i < e.import_stack->size() - 1; ++i) {
-          std::string path((*e.import_stack)[i]->imp_path);
-          std::string rel_path(Sass::File::abs2rel(path, cwd, cwd));
-          msg_stream << std::string(msg_prefix.size() + 2, ' ');
-          msg_stream << (i == 1 ? " on line " : " from line ");
-          msg_stream << e.pstate.line + 1 << " of " << rel_path << "\n";
-        }
-      }
-      else {
+
+      if (e.traces.empty()) {
+        // we normally should have some traces, still here as a fallback
         std::string rel_path(Sass::File::abs2rel(e.pstate.path, cwd, cwd));
         msg_stream << std::string(msg_prefix.size() + 2, ' ');
         msg_stream << " on line " << e.pstate.line + 1 << " of " << rel_path << "\n";
       }
+      else {
+        std::string rel_path(Sass::File::abs2rel(e.pstate.path, cwd, cwd));
+        msg_stream << traces_to_string(e.traces, "        ");
+      }
 
       // now create the code trace (ToDo: maybe have util functions?)
       if (e.pstate.line != std::string::npos && e.pstate.column != std::string::npos) {
-        size_t line = e.pstate.line;
+        size_t lines = e.pstate.line;
         const char* line_beg = e.pstate.src;
-        while (line_beg && *line_beg && line) {
-          if (*line_beg == '\n') --line;
-          ++line_beg;
+        // scan through src until target line
+        // move line_beg pointer to line start
+        while (line_beg && *line_beg && lines != 0) {
+          if (*line_beg == '\n') --lines;
+          utf8::unchecked::next(line_beg); 
         }
         const char* line_end = line_beg;
+        // move line_end before next newline character
         while (line_end && *line_end && *line_end != '\n') {
           if (*line_end == '\n') break;
           if (*line_end == '\r') break;
-          line_end++;
+          utf8::unchecked::next(line_end); 
         }
-        size_t max_left = 42; size_t max_right = 78;
-        size_t move_in = e.pstate.column > max_left ? e.pstate.column - max_left : 0;
-        size_t shorten = (line_end - line_beg) - move_in > max_right ?
-          (line_end - line_beg) - move_in - max_right : 0;
-        msg_stream << ">> " << std::string(line_beg + move_in, line_end - shorten) << "\n";
-        msg_stream << "   " << std::string(e.pstate.column - move_in, '-') << "^\n";
+        if (line_end && *line_end != 0) ++ line_end;
+        size_t line_len = line_end - line_beg;
+        size_t move_in = 0; size_t shorten = 0;
+        size_t left_chars = 42; size_t max_chars = 76;
+        // reported excerpt should not exceed `max_chars` chars
+        if (e.pstate.column > line_len) left_chars = e.pstate.column;
+        if (e.pstate.column > left_chars) move_in = e.pstate.column - left_chars;
+        if (line_len > max_chars + move_in) shorten = line_len - move_in - max_chars;
+        utf8::advance(line_beg, move_in, line_end);
+        utf8::retreat(line_end, shorten, line_beg);
+        std::string sanitized; std::string marker(e.pstate.column - move_in, '-');
+        utf8::replace_invalid(line_beg, line_end, std::back_inserter(sanitized));
+        msg_stream << ">> " << sanitized << "\n";
+        msg_stream << "   " << marker << "^\n";
       }
 
       JsonNode* json_err = json_mkobject();
@@ -199,7 +206,6 @@
   static int handle_errors(Sass_Context* c_ctx) {
     try { return handle_error(c_ctx); }
     catch (...) { return handle_error(c_ctx); }
-    return c_ctx->error_status;
   }
 
   static Block_Obj sass_parse_block(Sass_Compiler* compiler) throw()
@@ -272,10 +278,14 @@
   #define IMPLEMENT_SASS_OPTION_ACCESSOR(type, option) \
     type ADDCALL sass_option_get_##option (struct Sass_Options* options) { return options->option; } \
     void ADDCALL sass_option_set_##option (struct Sass_Options* options, type option) { options->option = option; }
-  #define IMPLEMENT_SASS_OPTION_STRING_ACCESSOR(type, option, def) \
-    type ADDCALL sass_option_get_##option (struct Sass_Options* options) { return safe_str(options->option, def); } \
+  #define IMPLEMENT_SASS_OPTION_STRING_GETTER(type, option, def) \
+    type ADDCALL sass_option_get_##option (struct Sass_Options* options) { return safe_str(options->option, def); }
+  #define IMPLEMENT_SASS_OPTION_STRING_SETTER(type, option, def) \
     void ADDCALL sass_option_set_##option (struct Sass_Options* options, type option) \
     { free(options->option); options->option = option || def ? sass_copy_c_string(option ? option : def) : 0; }
+  #define IMPLEMENT_SASS_OPTION_STRING_ACCESSOR(type, option, def) \
+    IMPLEMENT_SASS_OPTION_STRING_GETTER(type, option, def) \
+    IMPLEMENT_SASS_OPTION_STRING_SETTER(type, option, def)
 
   #define IMPLEMENT_SASS_CONTEXT_GETTER(type, option) \
     type ADDCALL sass_context_get_##option (struct Sass_Context* ctx) { return ctx->option; }
@@ -327,7 +337,9 @@
       c_ctx->error_column = std::string::npos;
 
       // allocate a new compiler instance
-      Sass_Compiler* compiler = (struct Sass_Compiler*) calloc(1, sizeof(struct Sass_Compiler));
+      void* ctxmem = calloc(1, sizeof(struct Sass_Compiler));
+      if (ctxmem == 0) { std::cerr << "Error allocating memory for context" << std::endl; return 0; }
+      Sass_Compiler* compiler = (struct Sass_Compiler*) ctxmem;
       compiler->state = SASS_COMPILER_CREATED;
 
       // store in sass compiler
@@ -468,7 +480,7 @@
     if (compiler->c_ctx->error_status)
       return compiler->c_ctx->error_status;
     // parse the context we have set up (file or data)
-    compiler->root = &sass_parse_block(compiler);
+    compiler->root = sass_parse_block(compiler);
     // success
     return 0;
   }
@@ -518,30 +530,10 @@
   static void sass_clear_options (struct Sass_Options* options)
   {
     if (options == 0) return;
-    // Deallocate custom functions
-    if (options->c_functions) {
-      Sass_Function_List this_func_data = options->c_functions;
-      while (this_func_data && *this_func_data) {
-        free(*this_func_data);
-        ++this_func_data;
-      }
-    }
-    // Deallocate custom headers
-    if (options->c_headers) {
-      Sass_Importer_List this_head_data = options->c_headers;
-      while (this_head_data && *this_head_data) {
-        free(*this_head_data);
-        ++this_head_data;
-      }
-    }
-    // Deallocate custom importers
-    if (options->c_importers) {
-      Sass_Importer_List this_imp_data = options->c_importers;
-      while (this_imp_data && *this_imp_data) {
-        free(*this_imp_data);
-        ++this_imp_data;
-      }
-    }
+    // Deallocate custom functions, headers and importes
+    sass_delete_function_list(options->c_functions);
+    sass_delete_importer_list(options->c_importers);
+    sass_delete_importer_list(options->c_headers);
     // Deallocate inc paths
     if (options->plugin_paths) {
       struct string_list* cur;
@@ -573,11 +565,6 @@
     free(options->include_path);
     free(options->source_map_file);
     free(options->source_map_root);
-    // Free custom functions
-    free(options->c_functions);
-    // Free custom importers
-    free(options->c_importers);
-    free(options->c_headers);
     // Reset our pointers
     options->input_path = 0;
     options->output_path = 0;
@@ -674,6 +661,10 @@
   size_t ADDCALL sass_compiler_get_import_stack_size(struct Sass_Compiler* compiler) { return compiler->cpp_ctx->import_stack.size(); }
   Sass_Import_Entry ADDCALL sass_compiler_get_last_import(struct Sass_Compiler* compiler) { return compiler->cpp_ctx->import_stack.back(); }
   Sass_Import_Entry ADDCALL sass_compiler_get_import_entry(struct Sass_Compiler* compiler, size_t idx) { return compiler->cpp_ctx->import_stack[idx]; }
+  // Getters for Sass_Compiler options (query function stack)
+  size_t ADDCALL sass_compiler_get_callee_stack_size(struct Sass_Compiler* compiler) { return compiler->cpp_ctx->callee_stack.size(); }
+  Sass_Callee_Entry ADDCALL sass_compiler_get_last_callee(struct Sass_Compiler* compiler) { return &compiler->cpp_ctx->callee_stack.back(); }
+  Sass_Callee_Entry ADDCALL sass_compiler_get_callee_entry(struct Sass_Compiler* compiler, size_t idx) { return &compiler->cpp_ctx->callee_stack[idx]; }
 
   // Calculate the size of the stored null terminated array
   size_t ADDCALL sass_context_get_included_files_size (struct Sass_Context* ctx)
@@ -693,10 +684,10 @@
   IMPLEMENT_SASS_OPTION_ACCESSOR(Sass_Importer_List, c_headers);
   IMPLEMENT_SASS_OPTION_ACCESSOR(const char*, indent);
   IMPLEMENT_SASS_OPTION_ACCESSOR(const char*, linefeed);
+  IMPLEMENT_SASS_OPTION_STRING_SETTER(const char*, plugin_path, 0);
+  IMPLEMENT_SASS_OPTION_STRING_SETTER(const char*, include_path, 0);
   IMPLEMENT_SASS_OPTION_STRING_ACCESSOR(const char*, input_path, 0);
   IMPLEMENT_SASS_OPTION_STRING_ACCESSOR(const char*, output_path, 0);
-  IMPLEMENT_SASS_OPTION_STRING_ACCESSOR(const char*, plugin_path, 0);
-  IMPLEMENT_SASS_OPTION_STRING_ACCESSOR(const char*, include_path, 0);
   IMPLEMENT_SASS_OPTION_STRING_ACCESSOR(const char*, source_map_file, 0);
   IMPLEMENT_SASS_OPTION_STRING_ACCESSOR(const char*, source_map_root, 0);
 
@@ -738,6 +729,23 @@
       last->next = include_path;
     }
 
+  }
+
+  // Push function for include paths (no manipulation support for now)
+  size_t ADDCALL sass_option_get_include_path_size(struct Sass_Options* options)
+  {
+    size_t len = 0;
+    struct string_list* cur = options->include_paths;
+    while (cur) { len ++; cur = cur->next; }
+    return len;
+  }
+
+  // Push function for include paths (no manipulation support for now)
+  const char* ADDCALL sass_option_get_include_path(struct Sass_Options* options, size_t i)
+  {
+    struct string_list* cur = options->include_paths;
+    while (i) { i--; cur = cur->next; }
+    return cur->string;
   }
 
   // Push function for plugin paths (no manipulation support for now)
diff --git a/libsass/src/sass_context.hpp b/libsass/src/sass_context.hpp
--- a/libsass/src/sass_context.hpp
+++ b/libsass/src/sass_context.hpp
@@ -1,9 +1,8 @@
 #ifndef SASS_SASS_CONTEXT_H
 #define SASS_SASS_CONTEXT_H
 
-#include "sass.h"
-#include "sass.hpp"
-#include "context.hpp"
+#include "sass/base.h"
+#include "sass/context.h"
 #include "ast_fwd_decl.hpp"
 
 // sass config options structure
@@ -33,7 +32,7 @@
   char* input_path;
 
   // The output path is used for source map
-  // generation. Libsass will not write to
+  // generation. LibSass will not write to
   // this file, it is just used to create
   // information in source-maps etc.
   char* output_path;
diff --git a/libsass/src/sass_functions.cpp b/libsass/src/sass_functions.cpp
--- a/libsass/src/sass_functions.cpp
+++ b/libsass/src/sass_functions.cpp
@@ -2,6 +2,7 @@
 #include <cstring>
 #include "util.hpp"
 #include "context.hpp"
+#include "values.hpp"
 #include "sass/functions.h"
 #include "sass_functions.hpp"
 
@@ -17,12 +18,30 @@
   {
     Sass_Function_Entry cb = (Sass_Function_Entry) calloc(1, sizeof(Sass_Function));
     if (cb == 0) return 0;
-    cb->signature = signature;
+    cb->signature = sass_copy_c_string(signature);
     cb->function = function;
     cb->cookie = cookie;
     return cb;
   }
 
+  void ADDCALL sass_delete_function(Sass_Function_Entry entry)
+  {
+    free(entry->signature);
+    free(entry);
+  }
+
+  // Deallocator for the allocated memory
+  void ADDCALL sass_delete_function_list(Sass_Function_List list)
+  {
+    Sass_Function_List it = list;
+    if (list == 0) return;
+    while(*list) {
+      sass_delete_function(*list);
+      ++list;
+    }
+    free(it);
+  }
+
   // Setters and getters for callbacks on function lists
   Sass_Function_Entry ADDCALL sass_function_get_list_entry(Sass_Function_List list, size_t pos) { return list[pos]; }
   void sass_function_set_list_entry(Sass_Function_List list, size_t pos, Sass_Function_Entry cb) { list[pos] = cb; }
@@ -57,6 +76,18 @@
     return (Sass_Importer_List) calloc(length + 1, sizeof(Sass_Importer_Entry));
   }
 
+  // Deallocator for the allocated memory
+  void ADDCALL sass_delete_importer_list(Sass_Importer_List list)
+  {
+    Sass_Importer_List it = list;
+    if (list == 0) return;
+    while(*list) {
+      sass_delete_importer(*list);
+      ++list;
+    }
+    free(it);
+  }
+
   Sass_Importer_Entry ADDCALL sass_importer_get_list_entry(Sass_Importer_List list, size_t idx) { return list[idx]; }
   void ADDCALL sass_importer_set_list_entry(Sass_Importer_List list, size_t idx, Sass_Importer_Entry cb) { list[idx] = cb; }
 
@@ -124,6 +155,37 @@
     free(import->srcmap);
     free(import->error);
     free(import);
+  }
+
+  // Getter for callee entry
+  const char* ADDCALL sass_callee_get_name(Sass_Callee_Entry entry) { return entry->name; }
+  const char* ADDCALL sass_callee_get_path(Sass_Callee_Entry entry) { return entry->path; }
+  size_t ADDCALL sass_callee_get_line(Sass_Callee_Entry entry) { return entry->line; }
+  size_t ADDCALL sass_callee_get_column(Sass_Callee_Entry entry) { return entry->column; }
+  enum Sass_Callee_Type ADDCALL sass_callee_get_type(Sass_Callee_Entry entry) { return entry->type; }
+  Sass_Env_Frame ADDCALL sass_callee_get_env (Sass_Callee_Entry entry) { return &entry->env; }
+
+  // Getters and Setters for environments (lexical, local and global)
+  union Sass_Value* ADDCALL sass_env_get_lexical (Sass_Env_Frame env, const char* name) {
+    Expression_Ptr ex = Cast<Expression>((*env->frame)[name]);
+    return ex != NULL ? ast_node_to_sass_value(ex) : NULL;
+  }
+  void ADDCALL sass_env_set_lexical (Sass_Env_Frame env, const char* name, union Sass_Value* val) {
+    (*env->frame)[name] = sass_value_to_ast_node(val);
+  }
+  union Sass_Value* ADDCALL sass_env_get_local (Sass_Env_Frame env, const char* name) {
+    Expression_Ptr ex = Cast<Expression>(env->frame->get_local(name));
+    return ex != NULL ? ast_node_to_sass_value(ex) : NULL;
+  }
+  void ADDCALL sass_env_set_local (Sass_Env_Frame env, const char* name, union Sass_Value* val) {
+    env->frame->set_local(name, sass_value_to_ast_node(val));
+  }
+  union Sass_Value* ADDCALL sass_env_get_global (Sass_Env_Frame env, const char* name) {
+    Expression_Ptr ex = Cast<Expression>(env->frame->get_global(name));
+    return ex != NULL ? ast_node_to_sass_value(ex) : NULL;
+  }
+  void ADDCALL sass_env_set_global (Sass_Env_Frame env, const char* name, union Sass_Value* val) {
+    env->frame->set_global(name, sass_value_to_ast_node(val));
   }
 
   // Getter for import entry
diff --git a/libsass/src/sass_functions.hpp b/libsass/src/sass_functions.hpp
--- a/libsass/src/sass_functions.hpp
+++ b/libsass/src/sass_functions.hpp
@@ -2,10 +2,12 @@
 #define SASS_SASS_FUNCTIONS_H
 
 #include "sass.h"
+#include "environment.hpp"
+#include "functions.hpp"
 
 // Struct to hold custom function callback
 struct Sass_Function {
-  const char*      signature;
+  char*            signature;
   Sass_Function_Fn function;
   void*            cookie;
 };
@@ -20,6 +22,22 @@
   char* error;
   size_t line;
   size_t column;
+};
+
+// External environments
+struct Sass_Env {
+  // links to parent frames
+  Sass::Env* frame;
+};
+
+// External call entry
+struct Sass_Callee {
+  const char* name;
+  const char* path;
+  size_t line;
+  size_t column;
+  enum Sass_Callee_Type type;
+  struct Sass_Env env;
 };
 
 // Struct to hold importer callback
diff --git a/libsass/src/sass_util.cpp b/libsass/src/sass_util.cpp
--- a/libsass/src/sass_util.cpp
+++ b/libsass/src/sass_util.cpp
@@ -37,7 +37,7 @@
       end
     end
   */
-  Node paths(const Node& arrs, Context& ctx) {
+  Node paths(const Node& arrs) {
 
     Node loopStart = Node::createCollection();
     loopStart.collection()->push_back(Node::createCollection());
@@ -108,7 +108,7 @@
     return flattened
   end
   */
-  Node flatten(Node& arr, Context& ctx, int n) {
+  Node flatten(Node& arr, int n) {
     if (n != -1 && n == 0) {
       return arr;
     }
@@ -124,7 +124,7 @@
       if (e.isCollection()) {
 
       	// e.collection().got_line_feed = e.got_line_feed;
-      	Node recurseFlattened = flatten(e, ctx, n - 1);
+      	Node recurseFlattened = flatten(e, n - 1);
 
       	if(e.got_line_feed) {
       		 flattened.got_line_feed = e.got_line_feed;
diff --git a/libsass/src/sass_util.hpp b/libsass/src/sass_util.hpp
--- a/libsass/src/sass_util.hpp
+++ b/libsass/src/sass_util.hpp
@@ -28,7 +28,7 @@
     #     #  [1, 4, 5],
     #     #  [2, 4, 5]]
   */
-  Node paths(const Node& arrs, Context& ctx);
+  Node paths(const Node& arrs);
 
 
   /*
@@ -40,7 +40,7 @@
     bool operator()(const Node& one, const Node& two, Node& out) const {
       // TODO: Is this the correct C++ interpretation?
       // block ||= proc {|a, b| a == b && a}
-      if (nodesEqual(one, two, true)) {
+      if (one == two) {
         out = one;
         return true;
       }
@@ -139,7 +139,7 @@
   http://en.wikipedia.org/wiki/Longest_common_subsequence_problem
   */
   template<typename ComparatorType>
-  Node lcs(Node& x, Node& y, const ComparatorType& comparator, Context& ctx) {
+  Node lcs(Node& x, Node& y, const ComparatorType& comparator) {
     DEBUG_PRINTLN(LCS, "LCS: X=" << x << " Y=" << y)
 
     Node newX = Node::createCollection();
@@ -169,7 +169,7 @@
   # @param n [int] The number of levels to flatten
   # @return [NodeCollection] The flattened array
   */
-  Node flatten(Node& arr, Context& ctx, int n = -1);
+  Node flatten(Node& arr, int n = -1);
 
 
   /*
diff --git a/libsass/src/sass_values.cpp b/libsass/src/sass_values.cpp
--- a/libsass/src/sass_values.cpp
+++ b/libsass/src/sass_values.cpp
@@ -4,6 +4,7 @@
 #include "util.hpp"
 #include "eval.hpp"
 #include "values.hpp"
+#include "operators.hpp"
 #include "sass/values.h"
 #include "sass_values.hpp"
 
@@ -54,6 +55,8 @@
   size_t ADDCALL sass_list_get_length(const union Sass_Value* v) { return v->list.length; }
   enum Sass_Separator ADDCALL sass_list_get_separator(const union Sass_Value* v) { return v->list.separator; }
   void ADDCALL sass_list_set_separator(union Sass_Value* v, enum Sass_Separator separator) { v->list.separator = separator; }
+  bool ADDCALL sass_list_get_is_bracketed(const union Sass_Value* v) { return v->list.is_bracketed; }
+  void ADDCALL sass_list_set_is_bracketed(union Sass_Value* v, bool is_bracketed) { v->list.is_bracketed = is_bracketed; }
   // Getters and setters for Sass_List values
   union Sass_Value* ADDCALL sass_list_get_value(const union Sass_Value* v, size_t i) { return v->list.values[i]; }
   void ADDCALL sass_list_set_value(union Sass_Value* v, size_t i, union Sass_Value* value) { v->list.values[i] = value; }
@@ -130,13 +133,14 @@
     return v;
   }
 
-  union Sass_Value* ADDCALL sass_make_list(size_t len, enum Sass_Separator sep)
+  union Sass_Value* ADDCALL sass_make_list(size_t len, enum Sass_Separator sep, bool is_bracketed)
   {
     union Sass_Value* v = (Sass_Value*) calloc(1, sizeof(Sass_Value));
     if (v == 0) return 0;
     v->list.tag = SASS_LIST;
     v->list.length = len;
     v->list.separator = sep;
+    v->list.is_bracketed = is_bracketed;
     v->list.values = (union Sass_Value**) calloc(len, sizeof(union Sass_Value*));
     if (v->list.values == 0) { free(v); return 0; }
     return v;
@@ -218,6 +222,7 @@
         case SASS_WARNING: {
                 free(val->error.message);
         }   break;
+        default: break;
     }
 
     free(val);
@@ -233,26 +238,26 @@
     switch(val->unknown.tag) {
         case SASS_NULL: {
                 return sass_make_null();
-        }   break;
+        }
         case SASS_BOOLEAN: {
                 return sass_make_boolean(val->boolean.value);
-        }   break;
+        }
         case SASS_NUMBER: {
                 return sass_make_number(val->number.value, val->number.unit);
-        }   break;
+        }
         case SASS_COLOR: {
                 return sass_make_color(val->color.r, val->color.g, val->color.b, val->color.a);
-        }   break;
+        }
         case SASS_STRING: {
                 return sass_string_is_quoted(val) ? sass_make_qstring(val->string.value) : sass_make_string(val->string.value);
-        }   break;
+        }
         case SASS_LIST: {
-                union Sass_Value* list = sass_make_list(val->list.length, val->list.separator);
+                union Sass_Value* list = sass_make_list(val->list.length, val->list.separator, val->list.is_bracketed);
                 for (i = 0; i < list->list.length; i++) {
                     list->list.values[i] = sass_clone_value(val->list.values[i]);
                 }
                 return list;
-        }   break;
+        }
         case SASS_MAP: {
                 union Sass_Value* map = sass_make_map(val->map.length);
                 for (i = 0; i < val->map.length; i++) {
@@ -260,13 +265,14 @@
                     map->map.pairs[i].value = sass_clone_value(val->map.pairs[i].value);
                 }
                 return map;
-        }   break;
+        }
         case SASS_ERROR: {
                 return sass_make_error(val->error.message);
-        }   break;
+        }
         case SASS_WARNING: {
                 return sass_make_warning(val->warning.message);
-        }   break;
+        }
+        default: break;
     }
 
     return 0;
@@ -284,7 +290,7 @@
   union Sass_Value* ADDCALL sass_value_op (enum Sass_OP op, const union Sass_Value* a, const union Sass_Value* b)
   {
 
-    Sass::Value_Ptr rv = 0;
+    Sass::Value_Ptr rv;
 
     try {
 
@@ -294,41 +300,41 @@
 
       // see if it's a relational expression
       switch(op) {
-        case Sass_OP::EQ:  return sass_make_boolean(Eval::eq(&lhs, &rhs));
-        case Sass_OP::NEQ: return sass_make_boolean(!Eval::eq(&lhs, &rhs));
-        case Sass_OP::GT:  return sass_make_boolean(!Eval::lt(&lhs, &rhs, "gt") && !Eval::eq(&lhs, &rhs));
-        case Sass_OP::GTE: return sass_make_boolean(!Eval::lt(&lhs, &rhs, "gte"));
-        case Sass_OP::LT:  return sass_make_boolean(Eval::lt(&lhs, &rhs, "lt"));
-        case Sass_OP::LTE: return sass_make_boolean(Eval::lt(&lhs, &rhs, "lte") || Eval::eq(&lhs, &rhs));
-        case Sass_OP::AND: return ast_node_to_sass_value(lhs->is_false() ? &lhs : &rhs);
-        case Sass_OP::OR:  return ast_node_to_sass_value(lhs->is_false() ? &rhs : &lhs);
-        default:           break;
+        case Sass_OP::EQ:  return sass_make_boolean(Operators::eq(lhs, rhs));
+        case Sass_OP::NEQ: return sass_make_boolean(Operators::neq(lhs, rhs));
+        case Sass_OP::GT:  return sass_make_boolean(Operators::gt(lhs, rhs));
+        case Sass_OP::GTE: return sass_make_boolean(Operators::gte(lhs, rhs));
+        case Sass_OP::LT:  return sass_make_boolean(Operators::lt(lhs, rhs));
+        case Sass_OP::LTE: return sass_make_boolean(Operators::lte(lhs, rhs));
+        case Sass_OP::AND: return ast_node_to_sass_value(lhs->is_false() ? lhs : rhs);
+        case Sass_OP::OR:  return ast_node_to_sass_value(lhs->is_false() ? rhs : lhs);
+        default: break;
       }
 
       if (sass_value_is_number(a) && sass_value_is_number(b)) {
-        Number_Ptr_Const l_n = SASS_MEMORY_CAST(Number, lhs);
-        Number_Ptr_Const r_n = SASS_MEMORY_CAST(Number, rhs);
-        rv = Eval::op_numbers(op, *l_n, *r_n, options);
+        Number_Ptr_Const l_n = Cast<Number>(lhs);
+        Number_Ptr_Const r_n = Cast<Number>(rhs);
+        rv = Operators::op_numbers(op, *l_n, *r_n, options, l_n->pstate());
       }
       else if (sass_value_is_number(a) && sass_value_is_color(a)) {
-        Number_Ptr_Const l_n = SASS_MEMORY_CAST(Number, lhs);
-        Color_Ptr_Const r_c = SASS_MEMORY_CAST(Color, rhs);
-        rv = Eval::op_number_color(op, *l_n, *r_c, options);
+        Number_Ptr_Const l_n = Cast<Number>(lhs);
+        Color_Ptr_Const r_c = Cast<Color>(rhs);
+        rv = Operators::op_number_color(op, *l_n, *r_c, options, l_n->pstate());
       }
       else if (sass_value_is_color(a) && sass_value_is_number(b)) {
-        Color_Ptr_Const l_c = SASS_MEMORY_CAST(Color, lhs);
-        Number_Ptr_Const r_n = SASS_MEMORY_CAST(Number, rhs);
-        rv = Eval::op_color_number(op, *l_c, *r_n, options);
+        Color_Ptr_Const l_c = Cast<Color>(lhs);
+        Number_Ptr_Const r_n = Cast<Number>(rhs);
+        rv = Operators::op_color_number(op, *l_c, *r_n, options, l_c->pstate());
       }
       else if (sass_value_is_color(a) && sass_value_is_color(b)) {
-        Color_Ptr_Const l_c = SASS_MEMORY_CAST(Color, lhs);
-        Color_Ptr_Const r_c = SASS_MEMORY_CAST(Color, rhs);
-        rv = Eval::op_colors(op, *l_c, *r_c, options);
+        Color_Ptr_Const l_c = Cast<Color>(lhs);
+        Color_Ptr_Const r_c = Cast<Color>(rhs);
+        rv = Operators::op_colors(op, *l_c, *r_c, options, l_c->pstate());
       }
       else /* convert other stuff to string and apply operation */ {
-        Value_Ptr l_v = SASS_MEMORY_CAST(Value, lhs);
-        Value_Ptr r_v = SASS_MEMORY_CAST(Value, rhs);
-        rv = Eval::op_strings(op, *l_v, *r_v, options);
+        Value_Ptr l_v = Cast<Value>(lhs);
+        Value_Ptr r_v = Cast<Value>(rhs);
+        rv = Operators::op_strings(op, *l_v, *r_v, options, l_v->pstate());
       }
 
       // ToDo: maybe we should should return null value?
@@ -346,9 +352,6 @@
     catch (std::string& e) { return sass_make_error(e.c_str()); }
     catch (const char* e) { return sass_make_error(e); }
     catch (...) { return sass_make_error("unknown"); }
-
-    return 0;
-
   }
 
 }
diff --git a/libsass/src/sass_values.hpp b/libsass/src/sass_values.hpp
--- a/libsass/src/sass_values.hpp
+++ b/libsass/src/sass_values.hpp
@@ -35,6 +35,7 @@
 struct Sass_List {
   enum Sass_Tag       tag;
   enum Sass_Separator separator;
+  bool                is_bracketed;
   size_t              length;
   // null terminated "array"
   union Sass_Value**  values;
diff --git a/libsass/src/source_map.cpp b/libsass/src/source_map.cpp
--- a/libsass/src/source_map.cpp
+++ b/libsass/src/source_map.cpp
@@ -2,7 +2,6 @@
 #include <string>
 #include <sstream>
 #include <iostream>
-#include <cstddef>
 #include <iomanip>
 
 #include "ast.hpp"
@@ -25,9 +24,9 @@
 
     json_append_member(json_srcmap, "version", json_mknumber(3));
 
-    const char *include = file.c_str();
-    JsonNode *json_include = json_mkstring(include);
-    json_append_member(json_srcmap, "file", json_include);
+    const char *file_name = file.c_str();
+    JsonNode *json_file_name = json_mkstring(file_name);
+    json_append_member(json_srcmap, "file", json_file_name);
 
     // pass-through sourceRoot option
     if (!ctx.source_map_root.empty()) {
@@ -35,35 +34,34 @@
       json_append_member(json_srcmap, "sourceRoot", root);
     }
 
-    JsonNode *json_includes = json_mkarray();
+    JsonNode *json_sources = json_mkarray();
     for (size_t i = 0; i < source_index.size(); ++i) {
-      std::string include(links[source_index[i]]);
+      std::string source(links[source_index[i]]);
       if (ctx.c_options.source_map_file_urls) {
-        include = File::rel2abs(include);
+        source = File::rel2abs(source);
         // check for windows abs path
-        if (include[0] == '/') {
+        if (source[0] == '/') {
           // ends up with three slashes
-          include = "file://" + include;
+          source = "file://" + source;
         } else {
           // needs an additional slash
-          include = "file:///" + include;
+          source = "file:///" + source;
         }
       }
-      const char* inc = include.c_str();
-      JsonNode *json_include = json_mkstring(inc);
-      json_append_element(json_includes, json_include);
+      const char* source_name = source.c_str();
+      JsonNode *json_source_name = json_mkstring(source_name);
+      json_append_element(json_sources, json_source_name);
     }
-    json_append_member(json_srcmap, "sources", json_includes);
+    json_append_member(json_srcmap, "sources", json_sources);
 
-    if (include_sources) {
+    if (include_sources && source_index.size()) {
       JsonNode *json_contents = json_mkarray();
       for (size_t i = 0; i < source_index.size(); ++i) {
         const Resource& resource(sources[source_index[i]]);
         JsonNode *json_content = json_mkstring(resource.contents);
         json_append_element(json_contents, json_content);
       }
-      if (json_contents->children.head)
-        json_append_member(json_srcmap, "sourcesContent", json_contents);
+      json_append_member(json_srcmap, "sourcesContent", json_contents);
     }
 
     JsonNode *json_names = json_mkarray();
@@ -138,7 +136,7 @@
         }
       }
     }
-    // will adjust the offset
+    // adjust the buffer offset
     prepend(Offset(out.buffer));
     // now add the new mappings
     VECTOR_UNSHIFT(mappings, out.smap.mappings);
diff --git a/libsass/src/subset_map.cpp b/libsass/src/subset_map.cpp
--- a/libsass/src/subset_map.cpp
+++ b/libsass/src/subset_map.cpp
@@ -4,22 +4,20 @@
 
 namespace Sass {
 
-  void Subset_Map::put(const Compound_Selector_Obj& sel, const Subset_Map_Val& value)
+  void Subset_Map::put(const Compound_Selector_Obj& sel, const SubSetMapPair& value)
   {
     if (sel->empty()) throw std::runtime_error("internal error: subset map keys may not be empty");
     size_t index = values_.size();
     values_.push_back(value);
     for (size_t i = 0, S = sel->length(); i < S; ++i)
     {
-      hash_[(*sel)[i]].push_back(std::make_pair(&sel, index));
+      hash_[(*sel)[i]].push_back(std::make_pair(sel, index));
     }
   }
 
-  std::vector<Subset_Map_Val> Subset_Map::get_kv(const Compound_Selector_Obj& sel)
+  std::vector<SubSetMapPair> Subset_Map::get_kv(const Compound_Selector_Obj& sel)
   {
-    // std::vector<Subset_Map_Key> s = sel->to_str_vec();
-    // std::set<std::string> dict(s.begin(), s.end());
-    std::unordered_set<Simple_Selector_Obj, HashSimpleSelector, CompareSimpleSelector> dict(sel->begin(), sel->end());
+    SimpleSelectorDict dict(sel->begin(), sel->end()); // XXX Set
     std::vector<size_t> indices;
     for (size_t i = 0, S = sel->length(); i < S; ++i) {
       if (!hash_.count((*sel)[i])) {
@@ -42,14 +40,14 @@
     std::vector<size_t>::iterator indices_end = unique(indices.begin(), indices.end());
     indices.resize(distance(indices.begin(), indices_end));
 
-    std::vector<Subset_Map_Val> results;
+    std::vector<SubSetMapPair> results;
     for (size_t i = 0, S = indices.size(); i < S; ++i) {
       results.push_back(values_[indices[i]]);
     }
     return results;
   }
 
-  std::vector<Subset_Map_Val> Subset_Map::get_v(const Compound_Selector_Obj& sel)
+  std::vector<SubSetMapPair> Subset_Map::get_v(const Compound_Selector_Obj& sel)
   {
     return get_kv(sel);
   }
diff --git a/libsass/src/subset_map.hpp b/libsass/src/subset_map.hpp
--- a/libsass/src/subset_map.hpp
+++ b/libsass/src/subset_map.hpp
@@ -60,15 +60,15 @@
 
   class Subset_Map {
   private:
-    std::vector<Subset_Map_Val> values_;
-    std::map<Simple_Selector_Obj, std::vector<std::pair<Compound_Selector_Obj, size_t> > > hash_;
+    std::vector<SubSetMapPair> values_;
+    std::map<Simple_Selector_Obj, std::vector<std::pair<Compound_Selector_Obj, size_t> >, OrderNodes > hash_;
   public:
-    void put(const Compound_Selector_Obj& sel, const Subset_Map_Val& value);
-    std::vector<Subset_Map_Val> get_kv(const Compound_Selector_Obj& s);
-    std::vector<Subset_Map_Val> get_v(const Compound_Selector_Obj& s);
+    void put(const Compound_Selector_Obj& sel, const SubSetMapPair& value);
+    std::vector<SubSetMapPair> get_kv(const Compound_Selector_Obj& s);
+    std::vector<SubSetMapPair> get_v(const Compound_Selector_Obj& s);
     bool empty() { return values_.empty(); }
     void clear() { values_.clear(); hash_.clear(); }
-    const std::vector<Subset_Map_Val> values(void) { return values_; }
+    const std::vector<SubSetMapPair> values(void) { return values_; }
   };
 
 }
diff --git a/libsass/src/to_c.cpp b/libsass/src/to_c.cpp
--- a/libsass/src/to_c.cpp
+++ b/libsass/src/to_c.cpp
@@ -36,7 +36,7 @@
 
   union Sass_Value* To_C::operator()(List_Ptr l)
   {
-    union Sass_Value* v = sass_make_list(l->length(), l->separator());
+    union Sass_Value* v = sass_make_list(l->length(), l->separator(), l->is_bracketed());
     for (size_t i = 0, L = l->length(); i < L; ++i) {
       sass_list_set_value(v, i, (*l)[i]->perform(this));
     }
@@ -57,7 +57,7 @@
 
   union Sass_Value* To_C::operator()(Arguments_Ptr a)
   {
-    union Sass_Value* v = sass_make_list(a->length(), SASS_COMMA);
+    union Sass_Value* v = sass_make_list(a->length(), SASS_COMMA, false);
     for (size_t i = 0, L = a->length(); i < L; ++i) {
       sass_list_set_value(v, i, (*a)[i]->perform(this));
     }
diff --git a/libsass/src/to_value.cpp b/libsass/src/to_value.cpp
--- a/libsass/src/to_value.cpp
+++ b/libsass/src/to_value.cpp
@@ -9,8 +9,6 @@
     // throw a runtime error if this happens
     // we want a well defined set of possible nodes
     throw std::runtime_error("invalid node for to_value");
-    // mute warning
-    return 0;
   }
 
   // Custom_Error is a valid value
@@ -62,7 +60,8 @@
                                l->pstate(),
                                l->length(),
                                l->separator(),
-                               l->is_arglist());
+                               l->is_arglist(),
+                               l->is_bracketed());
     for (size_t i = 0, L = l->length(); i < L; ++i) {
       ll->append((*l)[i]->perform(this));
     }
@@ -77,6 +76,12 @@
 
   // Null is a valid value
   Value_Ptr To_Value::operator()(Null_Ptr n)
+  {
+    return n;
+  }
+
+  // Function is a valid value
+  Value_Ptr To_Value::operator()(Function_Ptr n)
   {
     return n;
   }
diff --git a/libsass/src/to_value.hpp b/libsass/src/to_value.hpp
--- a/libsass/src/to_value.hpp
+++ b/libsass/src/to_value.hpp
@@ -34,6 +34,7 @@
     Value_Ptr operator()(List_Ptr);
     Value_Ptr operator()(Map_Ptr);
     Value_Ptr operator()(Null_Ptr);
+    Value_Ptr operator()(Function_Ptr);
 
     // convert to string via `To_String`
     Value_Ptr operator()(Selector_List_Ptr);
diff --git a/libsass/src/units.cpp b/libsass/src/units.cpp
--- a/libsass/src/units.cpp
+++ b/libsass/src/units.cpp
@@ -1,6 +1,7 @@
 #include "sass.hpp"
 #include <stdexcept>
 #include "units.hpp"
+#include "error_handling.hpp"
 
 namespace Sass {
 
@@ -53,12 +54,12 @@
   {
     switch (unit & 0xFF00)
     {
-      case UnitClass::LENGTH:      return UnitClass::LENGTH; break;
-      case UnitClass::ANGLE:       return UnitClass::ANGLE; break;
-      case UnitClass::TIME:        return UnitClass::TIME; break;
-      case UnitClass::FREQUENCY:   return UnitClass::FREQUENCY; break;
-      case UnitClass::RESOLUTION:  return UnitClass::RESOLUTION; break;
-      default:                     return UnitClass::INCOMMENSURABLE; break;
+      case UnitClass::LENGTH:      return UnitClass::LENGTH;
+      case UnitClass::ANGLE:       return UnitClass::ANGLE;
+      case UnitClass::TIME:        return UnitClass::TIME;
+      case UnitClass::FREQUENCY:   return UnitClass::FREQUENCY;
+      case UnitClass::RESOLUTION:  return UnitClass::RESOLUTION;
+      default:                     return UnitClass::INCOMMENSURABLE;
     }
   };
 
@@ -66,15 +67,28 @@
   {
     switch (unit & 0xFF00)
     {
-      case UnitClass::LENGTH:      return "LENGTH"; break;
-      case UnitClass::ANGLE:       return "ANGLE"; break;
-      case UnitClass::TIME:        return "TIME"; break;
-      case UnitClass::FREQUENCY:   return "FREQUENCY"; break;
-      case UnitClass::RESOLUTION:  return "RESOLUTION"; break;
-      default:                     return "INCOMMENSURABLE"; break;
+      case UnitClass::LENGTH:      return "LENGTH";
+      case UnitClass::ANGLE:       return "ANGLE";
+      case UnitClass::TIME:        return "TIME";
+      case UnitClass::FREQUENCY:   return "FREQUENCY";
+      case UnitClass::RESOLUTION:  return "RESOLUTION";
+      default:                     return "INCOMMENSURABLE";
     }
   };
 
+  UnitType get_main_unit(const UnitClass unit)
+  {
+    switch (unit)
+    {
+      case UnitClass::LENGTH:      return UnitType::PX;
+      case UnitClass::ANGLE:       return UnitType::DEG;
+      case UnitClass::TIME:        return UnitType::SEC;
+      case UnitClass::FREQUENCY:   return UnitType::HERTZ;
+      case UnitClass::RESOLUTION:  return UnitType::DPI;
+      default:                     return UnitType::UNKNOWN;
+    }
+  };
+
   UnitType string_to_unit(const std::string& s)
   {
     // size units
@@ -107,29 +121,29 @@
   {
     switch (unit) {
       // size units
-      case UnitType::PX:      return "px"; break;
-      case UnitType::PT:      return "pt"; break;
-      case UnitType::PC:      return "pc"; break;
-      case UnitType::MM:      return "mm"; break;
-      case UnitType::CM:      return "cm"; break;
-      case UnitType::IN:      return "in"; break;
+      case UnitType::PX:      return "px";
+      case UnitType::PT:      return "pt";
+      case UnitType::PC:      return "pc";
+      case UnitType::MM:      return "mm";
+      case UnitType::CM:      return "cm";
+      case UnitType::IN:      return "in";
       // angle units
-      case UnitType::DEG:     return "deg"; break;
-      case UnitType::GRAD:    return "grad"; break;
-      case UnitType::RAD:     return "rad"; break;
-      case UnitType::TURN:    return "turn"; break;
+      case UnitType::DEG:     return "deg";
+      case UnitType::GRAD:    return "grad";
+      case UnitType::RAD:     return "rad";
+      case UnitType::TURN:    return "turn";
       // time units
-      case UnitType::SEC:     return "s"; break;
-      case UnitType::MSEC:    return "ms"; break;
+      case UnitType::SEC:     return "s";
+      case UnitType::MSEC:    return "ms";
       // frequency units
-      case UnitType::HERTZ:   return "Hz"; break;
-      case UnitType::KHERTZ:  return "kHz"; break;
+      case UnitType::HERTZ:   return "Hz";
+      case UnitType::KHERTZ:  return "kHz";
       // resolutions units
-      case UnitType::DPI:     return "dpi"; break;
-      case UnitType::DPCM:    return "dpcm"; break;
-      case UnitType::DPPX:    return "dppx"; break;
+      case UnitType::DPI:     return "dpi";
+      case UnitType::DPCM:    return "dpcm";
+      case UnitType::DPPX:    return "dppx";
       // for unknown units
-      default:                return ""; break;
+      default:                return "";
     }
   }
 
@@ -161,7 +175,7 @@
   }
 
   // throws incompatibleUnits exceptions
-  double conversion_factor(const std::string& s1, const std::string& s2, bool strict)
+  double conversion_factor(const std::string& s1, const std::string& s2)
   {
     // assert for same units
     if (s1 == s2) return 1;
@@ -171,27 +185,317 @@
     // query unit group types
     UnitClass t1 = get_unit_type(u1);
     UnitClass t2 = get_unit_type(u2);
+    // return the conversion factor
+    return conversion_factor(u1, u2, t1, t2);
+  }
+
+  // throws incompatibleUnits exceptions
+  double conversion_factor(UnitType u1, UnitType u2, UnitClass t1, UnitClass t2)
+  {
+    // can't convert between groups
+    if (t1 != t2) return 0;
     // 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
-    // don't error for multiplication and division
-    if (strict && t1 != t2) throw incompatibleUnits(u1, u2);
-    // only process known units
-    if (u1 != UNKNOWN && u2 != UNKNOWN) {
-      switch (t1) {
-        case UnitClass::LENGTH:            return size_conversion_factors[i1][i2]; break;
-        case UnitClass::ANGLE:             return angle_conversion_factors[i1][i2]; break;
-        case UnitClass::TIME:              return time_conversion_factors[i1][i2]; break;
-        case UnitClass::FREQUENCY:         return frequency_conversion_factors[i1][i2]; break;
-        case UnitClass::RESOLUTION:        return resolution_conversion_factors[i1][i2]; break;
-        // ToDo: should we throw error here?
-        case UnitClass::INCOMMENSURABLE:   return 0; break;
-      }
+    // process known units
+    switch (t1) {
+      case LENGTH:
+        return size_conversion_factors[i1][i2];
+      case ANGLE:
+        return angle_conversion_factors[i1][i2];
+      case TIME:
+        return time_conversion_factors[i1][i2];
+      case FREQUENCY:
+        return frequency_conversion_factors[i1][i2];
+      case RESOLUTION:
+        return resolution_conversion_factors[i1][i2];
+      case INCOMMENSURABLE:
+        return 0;
     }
     // fallback
     return 0;
+  }
+
+  double convert_units(const std::string& lhs, const std::string& rhs, int& lhsexp, int& rhsexp)
+  {
+    double f = 0;
+    // do not convert same ones
+    if (lhs == rhs) return 0;
+    // skip already canceled out unit
+    if (lhsexp == 0) return 0;
+    if (rhsexp == 0) return 0;
+    // check if it can be converted
+    UnitType ulhs = string_to_unit(lhs);
+    UnitType urhs = string_to_unit(rhs);
+    // skip units we cannot convert
+    if (ulhs == UNKNOWN) return 0;
+    if (urhs == UNKNOWN) return 0;
+    // query unit group types
+    UnitClass clhs = get_unit_type(ulhs);
+    UnitClass crhs = get_unit_type(urhs);
+    // skip units we cannot convert
+    if (clhs != crhs) return 0;
+    // if right denominator is bigger than lhs, we want to keep it in rhs unit
+    if (rhsexp < 0 && lhsexp > 0 && - rhsexp > lhsexp) {
+      // get the conversion factor for units
+      f = conversion_factor(urhs, ulhs, clhs, crhs);
+      // left hand side has been consumned
+      f = std::pow(f, lhsexp);
+      rhsexp += lhsexp;
+      lhsexp = 0;
+    }
+    else {
+      // get the conversion factor for units
+      f = conversion_factor(ulhs, urhs, clhs, crhs);
+      // right hand side has been consumned
+      f = std::pow(f, rhsexp);
+      lhsexp += rhsexp;
+      rhsexp = 0;
+    }
+    return f;
+  }
+
+  bool Units::operator< (const Units& rhs) const
+  {
+    return (numerators < rhs.numerators) &&
+           (denominators < rhs.denominators);
+  }
+  bool Units::operator== (const Units& rhs) const
+  {
+    return (numerators == rhs.numerators) &&
+           (denominators == rhs.denominators);
+  }
+
+  double Units::normalize()
+  {
+
+    size_t iL = numerators.size();
+    size_t nL = denominators.size();
+
+    // the final conversion factor
+    double factor = 1;
+
+    for (size_t i = 0; i < iL; i++) {
+      std::string &lhs = numerators[i];
+      UnitType ulhs = string_to_unit(lhs);
+      if (ulhs == UNKNOWN) continue;
+      UnitClass clhs = get_unit_type(ulhs);
+      UnitType umain = get_main_unit(clhs);
+      if (ulhs == umain) continue;
+      double f(conversion_factor(umain, ulhs, clhs, clhs));
+      if (f == 0) throw std::runtime_error("INVALID");
+      numerators[i] = unit_to_string(umain);
+      factor /= f;
+    }
+
+    for (size_t n = 0; n < nL; n++) {
+      std::string &rhs = denominators[n];
+      UnitType urhs = string_to_unit(rhs);
+      if (urhs == UNKNOWN) continue;
+      UnitClass crhs = get_unit_type(urhs);
+      UnitType umain = get_main_unit(crhs);
+      if (urhs == umain) continue;
+      double f(conversion_factor(umain, urhs, crhs, crhs));
+      if (f == 0) throw std::runtime_error("INVALID");
+      denominators[n] = unit_to_string(umain);
+      factor /= f;
+    }
+
+    std::sort (numerators.begin(), numerators.end());
+    std::sort (denominators.begin(), denominators.end());
+
+    // return for conversion
+    return factor;
+  }
+
+  double Units::reduce()
+  {
+
+    size_t iL = numerators.size();
+    size_t nL = denominators.size();
+
+    // have less than two units?
+    if (iL + nL < 2) return 1;
+
+    // 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
+    std::map<std::string, int> exponents;
+
+    // initialize by summing up occurences in unit vectors
+    // this will already cancel out equivalent units (e.q. px/px)
+    for (size_t i = 0; i < iL; i ++) exponents[numerators[i]] += 1;
+    for (size_t n = 0; n < nL; n ++) exponents[denominators[n]] -= 1;
+
+    // the final conversion factor
+    double factor = 1;
+
+    // convert between compatible units
+    for (size_t i = 0; i < iL; i++) {
+      for (size_t n = 0; n < nL; n++) {
+        std::string &lhs = numerators[i], &rhs = denominators[n];
+        int &lhsexp = exponents[lhs], &rhsexp = exponents[rhs];
+        double f(convert_units(lhs, rhs, lhsexp, rhsexp));
+        if (f == 0) continue;
+        factor /= f;
+      }
+    }
+
+    // now we can build up the new unit arrays
+    numerators.clear();
+    denominators.clear();
+
+    // recreate sorted units vectors
+    for (auto exp : exponents) {
+      int &exponent = exp.second;
+      while (exponent > 0 && exponent --)
+        numerators.push_back(exp.first);
+      while (exponent < 0 && exponent ++)
+        denominators.push_back(exp.first);
+    }
+
+    // return for conversion
+    return factor;
+
+  }
+
+  std::string Units::unit() const
+  {
+    std::string u;
+    size_t iL = numerators.size();
+    size_t nL = denominators.size();
+    for (size_t i = 0; i < iL; i += 1) {
+      if (i) u += '*';
+      u += numerators[i];
+    }
+    if (nL != 0) u += '/';
+    for (size_t n = 0; n < nL; n += 1) {
+      if (n) u += '*';
+      u += denominators[n];
+    }
+    return u;
+  }
+
+  bool Units::is_unitless() const
+  {
+    return numerators.empty() &&
+           denominators.empty();
+  }
+
+  bool Units::is_valid_css_unit() const
+  {
+    return numerators.size() <= 1 &&
+           denominators.size() == 0;
+  }
+
+  // this does not cover all cases (multiple prefered units)
+  double Units::convert_factor(const Units& r) const
+  {
+
+    std::vector<std::string> miss_nums(0);
+    std::vector<std::string> miss_dens(0);
+    // create copy since we need these for state keeping
+    std::vector<std::string> r_nums(r.numerators);
+    std::vector<std::string> r_dens(r.denominators);
+
+    auto l_num_it = numerators.begin();
+    auto l_num_end = numerators.end();
+
+    bool l_unitless = is_unitless();
+    auto r_unitless = r.is_unitless();
+
+    // overall conversion
+    double factor = 1;
+
+    // process all left numerators
+    while (l_num_it != l_num_end)
+    {
+      // get and increment afterwards
+      const std::string l_num = *(l_num_it ++);
+
+      auto r_num_it = r_nums.begin(), r_num_end = r_nums.end();
+
+      bool found = false;
+      // search for compatible numerator
+      while (r_num_it != r_num_end)
+      {
+        // get and increment afterwards
+        const std::string r_num = *(r_num_it);
+        // get possible conversion factor for units
+        double conversion = conversion_factor(l_num, r_num);
+        // skip incompatible numerator
+        if (conversion == 0) {
+          ++ r_num_it;
+          continue;
+        }
+        // apply to global factor
+        factor *= conversion;
+        // remove item from vector
+        r_nums.erase(r_num_it);
+        // found numerator
+        found = true;
+        break;
+      }
+      // maybe we did not find any
+      // left numerator is leftover
+      if (!found) miss_nums.push_back(l_num);
+    }
+
+    auto l_den_it = denominators.begin();
+    auto l_den_end = denominators.end();
+
+    // process all left denominators
+    while (l_den_it != l_den_end)
+    {
+      // get and increment afterwards
+      const std::string l_den = *(l_den_it ++);
+
+      auto r_den_it = r_dens.begin();
+      auto r_den_end = r_dens.end();
+
+      bool found = false;
+      // search for compatible denominator
+      while (r_den_it != r_den_end)
+      {
+        // get and increment afterwards
+        const std::string r_den = *(r_den_it);
+        // get possible converstion factor for units
+        double conversion = conversion_factor(l_den, r_den);
+        // skip incompatible denominator
+        if (conversion == 0) {
+          ++ r_den_it;
+          continue;
+        }
+        // apply to global factor
+        factor /= conversion;
+        // remove item from vector
+        r_dens.erase(r_den_it);
+        // found denominator
+        found = true;
+        break;
+      }
+      // maybe we did not find any
+      // left denominator is leftover
+      if (!found) miss_dens.push_back(l_den);
+    }
+
+    // check left-overs (ToDo: might cancel out?)
+    if (miss_nums.size() > 0 && !r_unitless) {
+      throw Exception::IncompatibleUnits(r, *this);
+    }
+    else if (miss_dens.size() > 0 && !r_unitless) {
+      throw Exception::IncompatibleUnits(r, *this);
+    }
+    else if (r_nums.size() > 0 && !l_unitless) {
+      throw Exception::IncompatibleUnits(r, *this);
+    }
+    else if (r_dens.size() > 0 && !l_unitless) {
+      throw Exception::IncompatibleUnits(r, *this);
+    }
+
+    return factor;
   }
 
 }
diff --git a/libsass/src/units.hpp b/libsass/src/units.hpp
--- a/libsass/src/units.hpp
+++ b/libsass/src/units.hpp
@@ -4,6 +4,7 @@
 #include <cmath>
 #include <string>
 #include <sstream>
+#include <vector>
 
 namespace Sass {
 
@@ -52,40 +53,56 @@
 
   };
 
+  class Units {
+  public:
+    std::vector<std::string> numerators;
+    std::vector<std::string> denominators;
+  public:
+    // default constructor
+    Units() :
+      numerators(),
+      denominators()
+    { }
+    // copy constructor
+    Units(const Units* ptr) :
+      numerators(ptr->numerators),
+      denominators(ptr->denominators)
+    { }
+    // convert to string
+    std::string unit() const;
+    // get if units are empty
+    bool is_unitless() const;
+    // return if valid for css
+    bool is_valid_css_unit() const;
+    // reduce units for output
+    // returns conversion factor
+    double reduce();
+    // normalize units for compare
+    // returns conversion factor
+    double normalize();
+    // compare operations
+    bool operator< (const Units& rhs) const;
+    bool operator== (const Units& rhs) const;
+    // factor to convert into given units
+    double convert_factor(const Units&) const;
+  };
+
   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];
 
+  UnitType get_main_unit(const UnitClass unit);
   enum Sass::UnitType string_to_unit(const std::string&);
   const char* unit_to_string(Sass::UnitType unit);
   enum Sass::UnitClass get_unit_type(Sass::UnitType unit);
   std::string get_unit_class(Sass::UnitType unit);
   std::string unit_to_class(const std::string&);
   // throws incompatibleUnits exceptions
-  double conversion_factor(const std::string&, const std::string&, bool = true);
-
-  class incompatibleUnits: public std::exception
-  {
-    public:
-      const char* msg;
-      incompatibleUnits(Sass::UnitType a, Sass::UnitType b)
-      : exception()
-      {
-        std::stringstream ss;
-        ss << "Incompatible units: ";
-        ss << "'" << unit_to_string(a) << "' and ";
-        ss << "'" << unit_to_string(b) << "'";
-        // hold on to string on stack!
-        std::string str(ss.str());
-        msg = str.c_str();
-      }
-      virtual const char* what() const throw()
-      {
-        return msg;
-      }
-  };
+  double conversion_factor(const std::string&, const std::string&);
+  double conversion_factor(UnitType, UnitType, UnitClass, UnitClass);
+  double convert_units(const std::string&, const std::string&, int&, int&);
 
 }
 
diff --git a/libsass/src/utf8/checked.h b/libsass/src/utf8/checked.h
--- a/libsass/src/utf8/checked.h
+++ b/libsass/src/utf8/checked.h
@@ -193,6 +193,13 @@
             utf8::next(it, end);
     }
 
+    template <typename octet_iterator, typename distance_type>
+    void retreat (octet_iterator& it, distance_type n, octet_iterator start)
+    {
+        for (distance_type i = 0; i < n; ++i)
+            utf8::prior(it, start);
+    }
+
     template <typename octet_iterator>
     typename std::iterator_traits<octet_iterator>::difference_type
     distance (octet_iterator first, octet_iterator last)
diff --git a/libsass/src/utf8/unchecked.h b/libsass/src/utf8/unchecked.h
--- a/libsass/src/utf8/unchecked.h
+++ b/libsass/src/utf8/unchecked.h
@@ -116,6 +116,13 @@
                 utf8::unchecked::next(it);
         }
 
+        template <typename octet_iterator, typename distance_type>
+        void retreat (octet_iterator& it, distance_type n)
+        {
+            for (distance_type i = 0; i < n; ++i)
+                utf8::unchecked::prior(it);
+        }
+
         template <typename octet_iterator>
         typename std::iterator_traits<octet_iterator>::difference_type
         distance (octet_iterator first, octet_iterator last)
diff --git a/libsass/src/utf8_string.cpp b/libsass/src/utf8_string.cpp
--- a/libsass/src/utf8_string.cpp
+++ b/libsass/src/utf8_string.cpp
@@ -28,7 +28,7 @@
     size_t offset_at_position(const string& str, size_t position) {
       string::const_iterator it = str.begin();
       utf8::advance(it, position, str.end());
-      return distance(str.begin(), it);
+      return std::distance(str.begin(), it);
     }
 
     // function that returns number of bytes in a character at offset
diff --git a/libsass/src/util.cpp b/libsass/src/util.cpp
--- a/libsass/src/util.cpp
+++ b/libsass/src/util.cpp
@@ -9,11 +9,22 @@
 
 #include <cmath>
 #include <stdint.h>
+#if defined(_MSC_VER) && _MSC_VER >= 1800 && _MSC_VER < 1900 && defined(_M_X64)
+#include <mutex>
+#endif
 
 namespace Sass {
 
   double round(double val, size_t precision)
   {
+    // Disable FMA3-optimized implementation when compiling with VS2013 for x64 targets
+    // See https://github.com/sass/node-sass/issues/1854 for details
+    // FIXME: Remove this workaround when we switch to VS2015+
+    #if defined(_MSC_VER) && _MSC_VER >= 1800 && _MSC_VER < 1900 && defined(_M_X64)
+      static std::once_flag flag;
+      std::call_once(flag, []() { _set_FMA3_enable(0); });
+    #endif
+
     // https://github.com/sass/sass/commit/4e3e1d5684cc29073a507578fc977434ff488c93
     if (fmod(val, 1) - 0.5 > - std::pow(0.1, precision + 1)) return std::ceil(val);
     else if (fmod(val, 1) - 0.5 > std::pow(0.1, precision)) return std::floor(val);
@@ -24,7 +35,7 @@
   }
 
   /* Locale unspecific atof function. */
-  double sass_atof(const char *str)
+  double sass_strtod(const char *str)
   {
     char separator = *(localeconv()->decimal_point);
     if(separator != '.'){
@@ -37,13 +48,13 @@
         // of the string. This is slower but it is thread safe.
         char *copy = sass_copy_c_string(str);
         *(copy + (found - str)) = separator;
-        double res = atof(copy);
+        double res = strtod(copy, NULL);
         free(copy);
         return res;
       }
     }
 
-    return atof(str);
+    return strtod(str, NULL);
   }
 
   // helper for safe access to c_ctx
@@ -85,8 +96,9 @@
   }
 
   // read css string (handle multiline DELIM)
-  std::string read_css_string(const std::string& str)
+  std::string read_css_string(const std::string& str, bool css)
   {
+    if (!css) return str;
     std::string out("");
     bool esc = false;
     for (auto i : str) {
@@ -169,6 +181,23 @@
     return out;
   }
 
+  std::string escape_string(const std::string& str)
+  {
+    std::string out("");
+    for (auto i : str) {
+      if (i == '\n') {
+        out += "\\n";
+      } else if (i == '\r') {
+        out += "\\r";
+      } else if (i == '\t') {
+        out += "\\t";
+      } else {
+        out += i;
+      }
+    }
+    return out;
+  }
+
   std::string comment_to_string(const std::string& text)
   {
     std::string str = "";
@@ -221,6 +250,75 @@
     return quote_mark;
   }
 
+  std::string read_hex_escapes(const std::string& s)
+  {
+
+    std::string result;
+    bool skipped = false;
+
+    for (size_t i = 0, L = s.length(); i < L; ++i) {
+
+      // implement the same strange ruby sass behavior
+      // an escape sequence can also mean a unicode char
+      if (s[i] == '\\' && !skipped) {
+
+        // remember
+        skipped = true;
+
+        // 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;
+
+        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(), NULL, 16);
+
+          if (s[i + len] == ' ') ++ len;
+
+          // assert invalid code points
+          if (cp == 0) cp = 0xFFFD;
+          // replace bell character
+          // if (cp == '\n') cp = 32;
+
+          // use a very simple approach to convert via utf8 lib
+          // maybe there is a more elegant way; maybe we shoud
+          // convert the whole output from string to a stream!?
+          // allocate memory for utf8 char and convert to utf8
+          unsigned char u[5] = {0,0,0,0,0}; utf8::append(cp, u);
+          for(size_t m = 0; m < 5 && u[m]; m++) result.push_back(u[m]);
+
+          // skip some more chars?
+          i += len - 1; skipped = false;
+
+        }
+
+        else {
+
+          skipped = false;
+
+          result.push_back(s[i]);
+
+        }
+
+      }
+
+      else {
+
+        result.push_back(s[i]);
+
+      }
+
+    }
+
+    return result;
+
+  }
+
   std::string unquote(const std::string& s, char* qd, bool keep_utf8_sequences, bool strict)
   {
 
@@ -281,7 +379,7 @@
           // convert the whole output from string to a stream!?
           // allocate memory for utf8 char and convert to utf8
           unsigned char u[5] = {0,0,0,0,0}; utf8::append(cp, u);
-          for(size_t m = 0; u[m] && m < 5; m++) unq.push_back(u[m]);
+          for(size_t m = 0; m < 5 && u[m]; m++) unq.push_back(u[m]);
 
           // skip some more chars?
           i += len - 1; skipped = false;
@@ -445,7 +543,7 @@
 
       Block_Obj b = r->block();
 
-      Selector_List_Ptr sl = SASS_MEMORY_CAST(Selector_List, r->selector());
+      Selector_List_Ptr sl = Cast<Selector_List>(r->selector());
       bool hasSelectors = sl ? sl->length() > 0 : false;
 
       if (!hasSelectors) {
@@ -456,16 +554,16 @@
       bool hasPrintableChildBlocks = false;
       for (size_t i = 0, L = b->length(); i < L; ++i) {
         Statement_Obj stm = b->at(i);
-        if (dynamic_cast<Directive_Ptr>(&stm)) {
+        if (Cast<Directive>(stm)) {
           return true;
-        } else if (Declaration_Ptr d = dynamic_cast<Declaration_Ptr>(&stm)) {
+        } else if (Declaration_Ptr d = Cast<Declaration>(stm)) {
           return isPrintable(d, style);
-        } else if (dynamic_cast<Has_Block_Ptr>(&stm)) {
-          Block_Obj pChildBlock = ((Has_Block_Ptr)&stm)->block();
-          if (isPrintable(&pChildBlock, style)) {
+        } else if (Has_Block_Ptr p = Cast<Has_Block>(stm)) {
+          Block_Obj pChildBlock = p->block();
+          if (isPrintable(pChildBlock, style)) {
             hasPrintableChildBlocks = true;
           }
-        } else if (Comment_Ptr c = dynamic_cast<Comment_Ptr>(&stm)) {
+        } else if (Comment_Ptr c = Cast<Comment>(stm)) {
           // keep for uncompressed
           if (style != COMPRESSED) {
             hasDeclarations = true;
@@ -499,8 +597,8 @@
     bool isPrintable(Declaration_Ptr d, Sass_Output_Style style)
     {
       Expression_Obj val = d->value();
-      if (String_Quoted_Obj sq = SASS_MEMORY_CAST(String_Quoted, val)) return isPrintable(&sq, style);
-      if (String_Constant_Obj sc = SASS_MEMORY_CAST(String_Constant, val)) return isPrintable(&sc, style);
+      if (String_Quoted_Obj sq = Cast<String_Quoted>(val)) return isPrintable(sq.ptr(), style);
+      if (String_Constant_Obj sc = Cast<String_Constant>(val)) return isPrintable(sc.ptr(), style);
       return true;
     }
 
@@ -511,19 +609,19 @@
 
       Block_Obj b = f->block();
 
-//      bool hasSelectors = f->selector() && static_cast<Selector_List_Ptr>(f->selector())->length() > 0;
-
       bool hasDeclarations = false;
       bool hasPrintableChildBlocks = false;
       for (size_t i = 0, L = b->length(); i < L; ++i) {
         Statement_Obj stm = b->at(i);
-        if (dynamic_cast<Declaration_Ptr>(&stm) || dynamic_cast<Directive_Ptr>(&stm)) {
+        if (Cast<Declaration>(stm) || Cast<Directive>(stm)) {
           hasDeclarations = true;
         }
-        else if (dynamic_cast<Has_Block_Ptr>(&stm)) {
-          Block_Obj pChildBlock = ((Has_Block_Ptr)&stm)->block();
-          if (isPrintable(&pChildBlock, style)) {
-            hasPrintableChildBlocks = true;
+        else if (Has_Block_Ptr b = Cast<Has_Block>(stm)) {
+          Block_Obj pChildBlock = b->block();
+          if (!b->is_invisible()) {
+            if (isPrintable(pChildBlock, style)) {
+              hasPrintableChildBlocks = true;
+            }
           }
         }
 
@@ -542,34 +640,32 @@
       if (b == 0) return false;
       for (size_t i = 0, L = b->length(); i < L; ++i) {
         Statement_Obj stm = b->at(i);
-        if (dynamic_cast<Directive_Ptr>(&stm)) return true;
-        else if (dynamic_cast<Declaration_Ptr>(&stm)) return true;
-        else if (dynamic_cast<Comment_Ptr>(&stm)) {
-          Comment_Ptr c = (Comment_Ptr) &stm;
+        if (Cast<Directive>(stm)) return true;
+        else if (Cast<Declaration>(stm)) return true;
+        else if (Comment_Ptr c = Cast<Comment>(stm)) {
           if (isPrintable(c, style)) {
             return true;
           }
         }
-        else if (dynamic_cast<Ruleset_Ptr>(&stm)) {
-          Ruleset_Ptr r = (Ruleset_Ptr) &stm;
+        else if (Ruleset_Ptr r = Cast<Ruleset>(stm)) {
           if (isPrintable(r, style)) {
             return true;
           }
         }
-        else if (dynamic_cast<Supports_Block_Ptr>(&stm)) {
-          Supports_Block_Ptr f = (Supports_Block_Ptr) &stm;
+        else if (Supports_Block_Ptr f = Cast<Supports_Block>(stm)) {
           if (isPrintable(f, style)) {
             return true;
           }
         }
-        else if (dynamic_cast<Media_Block_Ptr>(&stm)) {
-          Media_Block_Ptr m = (Media_Block_Ptr) &stm;
-          if (isPrintable(m, style)) {
+        else if (Media_Block_Ptr mb = Cast<Media_Block>(stm)) {
+          if (isPrintable(mb, style)) {
             return true;
           }
         }
-        else if (dynamic_cast<Has_Block_Ptr>(&stm) && isPrintable(((Has_Block_Ptr)&stm)->block(), style)) {
-          return true;
+        else if (Has_Block_Ptr b = Cast<Has_Block>(stm)) {
+          if (isPrintable(b->block(), style)) {
+            return true;
+          }
         }
       }
       return false;
@@ -596,35 +692,33 @@
 
       for (size_t i = 0, L = b->length(); i < L; ++i) {
         Statement_Obj stm = b->at(i);
-        if (dynamic_cast<Declaration_Ptr>(&stm) || dynamic_cast<Directive_Ptr>(&stm)) {
+        if (Cast<Declaration>(stm) || Cast<Directive>(stm)) {
           return true;
         }
-        else if (dynamic_cast<Comment_Ptr>(&stm)) {
-          Comment_Ptr c = (Comment_Ptr) &stm;
+        else if (Comment_Ptr c = Cast<Comment>(stm)) {
           if (isPrintable(c, style)) {
             return true;
           }
         }
-        else if (dynamic_cast<Ruleset_Ptr>(&stm)) {
-          Ruleset_Ptr r = (Ruleset_Ptr) &stm;
+        else if (Ruleset_Ptr r = Cast<Ruleset>(stm)) {
           if (isPrintable(r, style)) {
             return true;
           }
         }
-        else if (dynamic_cast<Supports_Block_Ptr>(&stm)) {
-          Supports_Block_Ptr f = (Supports_Block_Ptr) &stm;
+        else if (Supports_Block_Ptr f = Cast<Supports_Block>(stm)) {
           if (isPrintable(f, style)) {
             return true;
           }
         }
-        else if (dynamic_cast<Media_Block_Ptr>(&stm)) {
-          Media_Block_Ptr m = (Media_Block_Ptr) &stm;
+        else if (Media_Block_Ptr m = Cast<Media_Block>(stm)) {
           if (isPrintable(m, style)) {
             return true;
           }
         }
-        else if (dynamic_cast<Has_Block_Ptr>(&stm) && isPrintable(((Has_Block_Ptr)&stm)->block(), style)) {
-          return true;
+        else if (Has_Block_Ptr b = Cast<Has_Block>(stm)) {
+          if (isPrintable(b->block(), style)) {
+            return true;
+          }
         }
       }
 
diff --git a/libsass/src/util.hpp b/libsass/src/util.hpp
--- a/libsass/src/util.hpp
+++ b/libsass/src/util.hpp
@@ -18,14 +18,16 @@
     } while (0)
 
   double round(double val, size_t precision = 0);
-  double sass_atof(const char* str);
+  double sass_strtod(const char* str);
   const char* safe_str(const char *, const char* = "");
   void free_string_array(char **);
   char **copy_strings(const std::vector<std::string>&, char ***, int = 0);
-  std::string read_css_string(const std::string& str);
+  std::string read_css_string(const std::string& str, bool css = true);
   std::string evacuate_escapes(const std::string& str);
   std::string string_to_output(const std::string& str);
   std::string comment_to_string(const std::string& text);
+  std::string read_hex_escapes(const std::string& str);
+  std::string escape_string(const std::string& str);
   void newline_to_space(std::string& str);
 
   std::string quote(const std::string&, char q = 0);
diff --git a/libsass/src/values.cpp b/libsass/src/values.cpp
--- a/libsass/src/values.cpp
+++ b/libsass/src/values.cpp
@@ -11,32 +11,32 @@
   {
     if (val->concrete_type() == Expression::NUMBER)
     {
-      Number_Ptr_Const res = dynamic_cast<Number_Ptr_Const>(val);
+      Number_Ptr_Const res = Cast<Number>(val);
       return sass_make_number(res->value(), res->unit().c_str());
     }
     else if (val->concrete_type() == Expression::COLOR)
     {
-      Color_Ptr_Const col = dynamic_cast<Color_Ptr_Const>(val);
+      Color_Ptr_Const col = Cast<Color>(val);
       return sass_make_color(col->r(), col->g(), col->b(), col->a());
     }
     else if (val->concrete_type() == Expression::LIST)
     {
-      List_Ptr_Const l = dynamic_cast<List_Ptr_Const>(val);
-      union Sass_Value* list = sass_make_list(l->size(), l->separator());
+      List_Ptr_Const l = Cast<List>(val);
+      union Sass_Value* list = sass_make_list(l->size(), l->separator(), l->is_bracketed());
       for (size_t i = 0, L = l->length(); i < L; ++i) {
         Expression_Obj obj = l->at(i);
-        auto val = ast_node_to_sass_value(&obj);
+        auto val = ast_node_to_sass_value(obj);
         sass_list_set_value(list, i, val);
       }
       return list;
     }
     else if (val->concrete_type() == Expression::MAP)
     {
-      Map_Ptr_Const m = dynamic_cast<Map_Ptr_Const>(val);
+      Map_Ptr_Const m = Cast<Map>(val);
       union Sass_Value* map = sass_make_map(m->length());
       size_t i = 0; for (Expression_Obj key : m->keys()) {
-        sass_map_set_key(map, i, ast_node_to_sass_value(&key));
-        sass_map_set_value(map, i, ast_node_to_sass_value(&m->at(key)));
+        sass_map_set_key(map, i, ast_node_to_sass_value(key));
+        sass_map_set_value(map, i, ast_node_to_sass_value(m->at(key)));
         ++ i;
       }
       return map;
@@ -47,16 +47,16 @@
     }
     else if (val->concrete_type() == Expression::BOOLEAN)
     {
-      Boolean_Ptr_Const res = dynamic_cast<Boolean_Ptr_Const>(val);
+      Boolean_Ptr_Const res = Cast<Boolean>(val);
       return sass_make_boolean(res->value());
     }
     else if (val->concrete_type() == Expression::STRING)
     {
-      if (String_Quoted_Ptr_Const qstr = dynamic_cast<String_Quoted_Ptr_Const>(val))
+      if (String_Quoted_Ptr_Const qstr = Cast<String_Quoted>(val))
       {
         return sass_make_qstring(qstr->value().c_str());
       }
-      else if (String_Constant_Ptr_Const cstr = dynamic_cast<String_Constant_Ptr_Const>(val))
+      else if (String_Constant_Ptr_Const cstr = Cast<String_Constant>(val))
       {
         return sass_make_string(cstr->value().c_str());
       }
@@ -73,12 +73,10 @@
                                ParserState("[C-VALUE]"),
                                sass_number_get_value(val),
                                sass_number_get_unit(val));
-      break;
       case SASS_BOOLEAN:
         return SASS_MEMORY_NEW(Boolean,
                                ParserState("[C-VALUE]"),
                                sass_boolean_get_value(val));
-      break;
       case SASS_COLOR:
         return SASS_MEMORY_NEW(Color,
                                ParserState("[C-VALUE]"),
@@ -86,18 +84,15 @@
                                sass_color_get_g(val),
                                sass_color_get_b(val),
                                sass_color_get_a(val));
-      break;
       case SASS_STRING:
         if (sass_string_is_quoted(val)) {
           return SASS_MEMORY_NEW(String_Quoted,
                                  ParserState("[C-VALUE]"),
                                  sass_string_get_value(val));
-        } else {
-          return SASS_MEMORY_NEW(String_Constant,
+        }
+        return SASS_MEMORY_NEW(String_Constant,
                                  ParserState("[C-VALUE]"),
                                  sass_string_get_value(val));
-        }
-      break;
       case SASS_LIST: {
         List_Ptr l = SASS_MEMORY_NEW(List,
                                   ParserState("[C-VALUE]"),
@@ -106,9 +101,9 @@
         for (size_t i = 0, L = sass_list_get_length(val); i < L; ++i) {
           l->append(sass_value_to_ast_node(sass_list_get_value(val, i)));
         }
+        l->is_bracketed(sass_list_get_is_bracketed(val));
         return l;
       }
-      break;
       case SASS_MAP: {
         Map_Ptr m = SASS_MEMORY_NEW(Map, ParserState("[C-VALUE]"));
         for (size_t i = 0, L = sass_map_get_length(val); i < L; ++i) {
@@ -118,20 +113,17 @@
         }
         return m;
       }
-      break;
       case SASS_NULL:
         return SASS_MEMORY_NEW(Null, ParserState("[C-VALUE]"));
-      break;
       case SASS_ERROR:
         return SASS_MEMORY_NEW(Custom_Error,
                                ParserState("[C-VALUE]"),
                                sass_error_get_message(val));
-      break;
       case SASS_WARNING:
         return SASS_MEMORY_NEW(Custom_Warning,
                                ParserState("[C-VALUE]"),
                                sass_warning_get_message(val));
-      break;
+      default: break;
     }
     return 0;
   }
diff --git a/tests/Main.hs b/tests/Main.hs
--- a/tests/Main.hs
+++ b/tests/Main.hs
@@ -35,7 +35,7 @@
 #ifndef EXTERNAL_LIBSASS
     it "should report correct version" $ do
         str <- peekCString libsass_version
-        str `shouldBe` "3.4.3"
+        str `shouldBe` "3.5.2"
 #endif
 
     it "should support quoted strings" $ withCString "sample" $ \cstr -> do
