diff --git a/Bindings/Libsass.hs b/Bindings/Libsass.hs
--- a/Bindings/Libsass.hs
+++ b/Bindings/Libsass.hs
@@ -5,15 +5,12 @@
 {-# LANGUAGE ForeignFunctionInterface #-}
 module Bindings.Libsass
   (
-    libsass_version
-  , module Libsass
+    module Libsass
   ) where
 
+import           Bindings.Libsass.Types     as Libsass
+import           Bindings.Libsass.Base      as Libsass
 import           Bindings.Libsass.Context   as Libsass
 import           Bindings.Libsass.Functions as Libsass
-import           Bindings.Libsass.Types     as Libsass
-import           Bindings.Libsass.Wrappers  as Libsass
 import           Bindings.Libsass.Values    as Libsass
-import           Foreign.C.String
-
-foreign import ccall unsafe "sass/base.h" libsass_version :: CString
+import           Bindings.Libsass.Wrappers  as Libsass
diff --git a/Bindings/Libsass/Base.hs b/Bindings/Libsass/Base.hs
new file mode 100644
--- /dev/null
+++ b/Bindings/Libsass/Base.hs
@@ -0,0 +1,37 @@
+{-# LANGUAGE ForeignFunctionInterface #-}
+module Bindings.Libsass.Base where
+
+import           Foreign
+import           Foreign.C
+
+foreign import ccall unsafe "sass/base.h" sass_alloc_memory
+    :: CSize
+    -> IO (Ptr ())
+
+foreign import ccall unsafe "sass/base.h" sass_copy_c_string
+    :: CString
+    -> IO CString
+
+foreign import ccall unsafe "sass/base.h" sass_free_memory
+    :: Ptr ()
+    -> IO ()
+
+foreign import ccall unsafe "sass/base.h" sass_string_quote
+    :: CString
+    -> CChar
+    -> IO CString
+
+foreign import ccall unsafe "sass/base.h" sass_string_unquote
+    :: 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
+
+foreign import ccall unsafe "sass/base.h" libsass_language_version
+    :: CString
diff --git a/Bindings/Libsass/Context.hs b/Bindings/Libsass/Context.hs
--- a/Bindings/Libsass/Context.hs
+++ b/Bindings/Libsass/Context.hs
@@ -3,8 +3,7 @@
 
 import           Bindings.Libsass.Types
 import           Foreign
-import           Foreign.C.String
-import           Foreign.C.Types
+import           Foreign.C
 
 foreign import ccall unsafe "sass/context.h" sass_make_options
     :: IO (Ptr SassOptions)
@@ -50,6 +49,10 @@
     :: Ptr SassCompiler
     -> IO ()
 
+foreign import ccall unsafe "sass/context.h" sass_delete_options
+    :: Ptr SassOptions
+    -> IO ()
+
 foreign import ccall unsafe "sass/context.h" sass_delete_file_context
     :: Ptr SassFileContext
     -> IO ()
@@ -108,6 +111,10 @@
     :: Ptr SassOptions
     -> IO Bool
 
+foreign import ccall unsafe "sass/context.h" sass_option_get_source_map_file_urls
+    :: Ptr SassOptions
+    -> IO Bool
+
 foreign import ccall unsafe "sass/context.h" sass_option_get_omit_source_map_url
     :: Ptr SassOptions
     -> IO Bool
@@ -185,6 +192,11 @@
     -> Bool
     -> IO ()
 
+foreign import ccall unsafe "sass/context.h" sass_option_set_source_map_file_urls
+    :: Ptr SassOptions
+    -> Bool
+    -> IO ()
+
 foreign import ccall unsafe "sass/context.h" sass_option_set_omit_source_map_url
     :: Ptr SassOptions
     -> Bool
@@ -333,6 +345,10 @@
 foreign import ccall unsafe "sass/context.h" sass_compiler_get_context
     :: Ptr SassCompiler
     -> IO (Ptr SassContext)
+
+foreign import ccall unsafe "sass/context.h" sass_compiler_get_options
+    :: Ptr SassCompiler
+    -> IO (Ptr SassOptions)
 
 foreign import ccall unsafe "sass/context.h" sass_compiler_get_import_stack_size
     :: Ptr SassCompiler
diff --git a/Bindings/Libsass/Types.hs b/Bindings/Libsass/Types.hs
--- a/Bindings/Libsass/Types.hs
+++ b/Bindings/Libsass/Types.hs
@@ -2,15 +2,17 @@
 module Bindings.Libsass.Types where
 
 import           Foreign
-import           Foreign.C.String
+import           Foreign.C
 
--- From sass.h
+-- From sass/base.h
 
 -- | Defines output style of compiled CSS.
 data SassOutputStyle = SassStyleNested
                      | SassStyleExpanded
                      | SassStyleCompact
                      | SassStyleCompressed
+                     | SassStyleInspect -- ^ Marked as internal
+                     | SassStyleToSass -- ^ Marked as internal
                      deriving (Eq, Show)
 
 instance Enum SassOutputStyle where
@@ -18,14 +20,18 @@
     fromEnum SassStyleExpanded   = 1
     fromEnum SassStyleCompact    = 2
     fromEnum SassStyleCompressed = 3
+    fromEnum SassStyleInspect    = 4
+    fromEnum SassStyleToSass     = 5
 
     toEnum 0 = SassStyleNested
     toEnum 1 = SassStyleExpanded
     toEnum 2 = SassStyleCompact
     toEnum 3 = SassStyleCompressed
+    toEnum 4 = SassStyleInspect
+    toEnum 5 = SassStyleToSass
     toEnum u = error ("SassOutputStyle.toEnum: Cannot match " ++ show u)
 
--- From sass_context.h
+-- From sass/context.h
 
 data SassCompiler
 data SassOptions
@@ -48,7 +54,7 @@
     toEnum 2 = SassCompilerExecuted
     toEnum u = error ("SassCompilerState.toEnum: Cannot match " ++ show u)
 
--- From sass_functions.h
+-- From sass/functions.h
 
 data SassImport
 data SassImporter
@@ -76,7 +82,7 @@
   -> IO (Ptr SassValue)
 type SassFunctionFn = FunPtr SassFunctionFnType
 
--- From sass_values.h
+-- From sass/values.h
 
 data SassValue
 
@@ -113,20 +119,23 @@
     toEnum 8 = SassWarning
     toEnum u = error ("SassTag.toEnum: Cannot match " ++ show u)
 
--- ^ Separator used in Sass lists.
+-- | Separator used in Sass lists.
 data SassSeparator = SassSeparatorComma
                    | SassSeparatorSpace
+                   | SassSeparatorHash -- ^ Marked as internal
                    deriving (Eq, Show)
 
 instance Enum SassSeparator where
     fromEnum SassSeparatorComma = 0
-    fromEnum SassSeparatorSpace  = 1
+    fromEnum SassSeparatorSpace = 1
+    fromEnum SassSeparatorHash  = 2
 
     toEnum 0 = SassSeparatorComma
     toEnum 1 = SassSeparatorSpace
+    toEnum 2 = SassSeparatorHash
     toEnum u = error ("SassSeparator.toEnum: Cannot match " ++ show u)
 
--- ^ Operator used to combine two 'SassValue's.
+-- | Operator used to combine two 'SassValue's.
 data SassOp = SassAnd
             | SassOr
             | SassEq
diff --git a/Bindings/Libsass/Values.hs b/Bindings/Libsass/Values.hs
--- a/Bindings/Libsass/Values.hs
+++ b/Bindings/Libsass/Values.hs
@@ -5,6 +5,70 @@
 import           Foreign
 import           Foreign.C
 
+foreign import ccall unsafe "sass/values.h" sass_make_null
+    :: IO (Ptr SassValue)
+
+foreign import ccall unsafe "sass/values.h" sass_make_boolean
+    :: Bool
+    -> IO (Ptr SassValue)
+
+foreign import ccall unsafe "sass/values.h" sass_make_string
+    :: CString
+    -> IO (Ptr SassValue)
+
+foreign import ccall unsafe "sass/values.h" sass_make_qstring
+    :: CString
+    -> IO (Ptr SassValue)
+
+foreign import ccall unsafe "sass/values.h" sass_make_number
+    :: CDouble
+    -> CString
+    -> IO (Ptr SassValue)
+
+foreign import ccall unsafe "sass/values.h" sass_make_color
+    :: CDouble
+    -> CDouble
+    -> CDouble
+    -> CDouble
+    -> IO (Ptr SassValue)
+
+foreign import ccall unsafe "sass/values.h" sass_make_list
+    :: CSize
+    -> CInt -- ^ 'SassSeparator'
+    -> IO (Ptr SassValue)
+
+foreign import ccall unsafe "sass/values.h" sass_make_map
+    :: CSize
+    -> IO (Ptr SassValue)
+
+foreign import ccall unsafe "sass/values.h" sass_make_error
+    :: CString
+    -> IO (Ptr SassValue)
+
+foreign import ccall unsafe "sass/values.h" sass_make_warning
+    :: CString
+    -> IO (Ptr SassValue)
+
+foreign import ccall unsafe "sass/values.h" sass_delete_value
+    :: Ptr SassValue
+    -> IO ()
+
+foreign import ccall unsafe "sass/values.h" sass_clone_value
+    :: Ptr SassValue
+    -> IO (Ptr SassValue)
+
+foreign import ccall unsafe "sass/values.h" sass_value_op
+    :: CInt -- ^ 'SassOp'
+    -> Ptr SassValue
+    -> Ptr SassValue
+    -> IO (Ptr SassValue)
+
+foreign import ccall unsafe "sass/values.h" sass_value_stringify
+    :: Ptr SassValue
+    -> Bool
+    -> CInt
+    -> IO (Ptr SassValue)
+
 foreign import ccall unsafe "sass/values.h" sass_value_get_tag
     :: Ptr SassValue
     -> IO CInt -- ^ Returns 'SassTag'
@@ -193,67 +257,3 @@
     :: Ptr SassValue
     -> CString
     -> IO ()
-
-foreign import ccall unsafe "sass/values.h" sass_make_null
-    :: IO (Ptr SassValue)
-
-foreign import ccall unsafe "sass/values.h" sass_make_boolean
-    :: Bool
-    -> IO (Ptr SassValue)
-
-foreign import ccall unsafe "sass/values.h" sass_make_string
-    :: CString
-    -> IO (Ptr SassValue)
-
-foreign import ccall unsafe "sass/values.h" sass_make_qstring
-    :: CString
-    -> IO (Ptr SassValue)
-
-foreign import ccall unsafe "sass/values.h" sass_make_number
-    :: CDouble
-    -> CString
-    -> IO (Ptr SassValue)
-
-foreign import ccall unsafe "sass/values.h" sass_make_color
-    :: CDouble
-    -> CDouble
-    -> CDouble
-    -> CDouble
-    -> IO (Ptr SassValue)
-
-foreign import ccall unsafe "sass/values.h" sass_make_list
-    :: CSize
-    -> CInt -- ^ 'SassSeparator'
-    -> IO (Ptr SassValue)
-
-foreign import ccall unsafe "sass/values.h" sass_make_map
-    :: CSize
-    -> IO (Ptr SassValue)
-
-foreign import ccall unsafe "sass/values.h" sass_make_error
-    :: CString
-    -> IO (Ptr SassValue)
-
-foreign import ccall unsafe "sass/values.h" sass_make_warning
-    :: CString
-    -> IO (Ptr SassValue)
-
-foreign import ccall unsafe "sass/values.h" sass_delete_value
-    :: Ptr SassValue
-    -> IO ()
-
-foreign import ccall unsafe "sass/values.h" sass_clone_value
-    :: Ptr SassValue
-    -> IO (Ptr SassValue)
-
-foreign import ccall unsafe "sass/values.h" sass_value_stringify
-    :: Ptr SassValue
-    -> Bool
-    -> CInt
-    -> IO (Ptr SassValue)
-
-foreign import ccall unsafe "sass/values.h" sass_value_op
-    :: CInt -- ^ 'SassOp'
-    -> Ptr SassValue
-    -> Ptr SassValue
-    -> IO (Ptr SassValue)
diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,13 @@
 # Change Log
 All notable changes to this project will be documented in this file.
 
+## [0.1.6.0] - 2017-03-25
+### Fixed
+- `tools/libpath.sh` recognizes `stack`
+
+### Changed
+- Update to Libsass 3.4.3
+
 ## [0.1.5.2] - 2017-03-19
 ### Fixed
 - Build process for dependant libraries works with Cabal 1.24 & Stack 1.4
@@ -63,6 +70,7 @@
 - Bindings to Libsass C API
 - Basic tests
 
+[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
 [0.1.5.0]: https://github.com/jakubfijalkowski/hlibsass/compare/v0.1.4.0...v0.1.5.0
 [0.1.4.0]: https://github.com/jakubfijalkowski/hlibsass/compare/v0.1.3.0...v0.1.4.0
diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2015 Jakub Fijałkowski
+Copyright (c) 2015-2017 Jakub Fijałkowski
 
 Permission is hereby granted, free of charge, to any person obtaining
 a copy of this software and associated documentation files (the
diff --git a/hlibsass.cabal b/hlibsass.cabal
--- a/hlibsass.cabal
+++ b/hlibsass.cabal
@@ -1,5 +1,5 @@
 name:                hlibsass
-version:             0.1.5.2
+version:             0.1.6.0
 license:             MIT
 license-file:        LICENSE
 author:              Jakub Fijałkowski <fiolek94@gmail.com>
@@ -26,6 +26,8 @@
   libsass/src/b64/*.h
   libsass/src/utf8/*.h
   libsass/src/support/*.pc.in
+  libsass/src/memory/*.hpp
+  libsass/src/memory/*.cpp
   libsass/include/*.h
   libsass/include/sass/*.h
   libsass/include/sass/*.h.in
@@ -54,6 +56,7 @@
 library
   exposed-modules:
       Bindings.Libsass
+    , Bindings.Libsass.Base
     , Bindings.Libsass.Types
     , Bindings.Libsass.Wrappers
     , Bindings.Libsass.Context
@@ -64,10 +67,12 @@
   default-language:    Haskell2010
   default-extensions:  ForeignFunctionInterface
   ghc-options:         -Wall
-  if flag(externalLibsass)
-    extra-libraries:   sass
-  else
-    extra-libraries:   sass, stdc++
+  extra-libraries:     sass
+  if !flag(externalLibsass) && !flag(sharedLibsass)
+    if os(darwin)
+      extra-libraries: c++
+    else
+      extra-libraries: stdc++
 
 test-suite tests
   hs-source-dirs:      tests
diff --git a/libsass/LICENSE b/libsass/LICENSE
--- a/libsass/LICENSE
+++ b/libsass/LICENSE
@@ -1,5 +1,5 @@
 
-Copyright (C) 2012 by Hampton Catlin
+Copyright (C) 2012-2016 by the Sass Open Source Foundation
 
 Permission is hereby granted, free of charge, to any person obtaining a copy of
 this software and associated documentation files (the "Software"), to deal in
diff --git a/libsass/Makefile b/libsass/Makefile
--- a/libsass/Makefile
+++ b/libsass/Makefile
@@ -1,3 +1,4 @@
+OS       ?= $(shell uname -s)
 CC       ?= gcc
 CXX      ?= g++
 RM       ?= rm -f
@@ -5,6 +6,11 @@
 MKDIR    ?= mkdir
 RMDIR    ?= rmdir
 WINDRES  ?= windres
+# Solaris/Illumos flavors
+# ginstall from coreutils
+ifeq ($(OS),SunOS)
+INSTALL  ?= ginstall
+endif
 INSTALL  ?= install
 CFLAGS   ?= -Wall
 CXXFLAGS ?= -Wall
@@ -20,14 +26,14 @@
 ifneq (,$(findstring /cygdrive/,$(PATH)))
 	UNAME := Cygwin
 else
-	ifneq (,$(findstring WINDOWS,$(PATH)))
+	ifneq (,$(findstring Windows_NT,$(OS)))
 		UNAME := Windows
 	else
 		ifneq (,$(findstring mingw32,$(MAKE)))
-			UNAME := MinGW
+			UNAME := Windows
 		else
 			ifneq (,$(findstring MINGW32,$(shell uname -s)))
-				UNAME = MinGW
+				UNAME = Windows
 			else
 				UNAME := $(shell uname -s)
 			endif
@@ -57,7 +63,7 @@
 endif
 
 # enable mandatory flag
-ifeq (MinGW,$(UNAME))
+ifeq (Windows,$(UNAME))
 	ifneq ($(BUILD),shared)
 		STATIC_ALL     ?= 1
 	endif
@@ -117,25 +123,33 @@
 	LDFLAGS += -stdlib=libc++
 endif
 
-ifneq (MinGW,$(UNAME))
+ifneq (Windows,$(UNAME))
 	ifneq (FreeBSD,$(UNAME))
-		LDFLAGS += -ldl
-		LDLIBS += -ldl
+		ifneq (OpenBSD,$(UNAME))
+			LDFLAGS += -ldl
+			LDLIBS += -ldl
+		endif
 	endif
 endif
 
 ifneq ($(BUILD),shared)
-	BUILD = static
+	BUILD := static
 endif
+ifeq ($(DEBUG),1)
+	BUILD := debug-$(BUILD)
+endif
 
-ifeq (,$(PREFIX))
-	ifeq (,$(TRAVIS_BUILD_DIR))
-		PREFIX = /usr/local
+ifeq (,$(TRAVIS_BUILD_DIR))
+	ifeq ($(OS),SunOS)
+		PREFIX ?= /opt/local
 	else
-		PREFIX = $(TRAVIS_BUILD_DIR)
+		PREFIX ?= /usr/local
 	endif
+else
+	PREFIX ?= $(TRAVIS_BUILD_DIR)
 endif
 
+
 SASS_SASSC_PATH ?= sassc
 SASS_SPEC_PATH ?= sass-spec
 SASS_SPEC_SPEC_DIR ?= spec
@@ -145,7 +159,7 @@
 LIB_STATIC = $(SASS_LIBSASS_PATH)/lib/libsass.a
 LIB_SHARED = $(SASS_LIBSASS_PATH)/lib/libsass.so
 
-ifeq (MinGW,$(UNAME))
+ifeq (Windows,$(UNAME))
 	ifeq (shared,$(BUILD))
 		CFLAGS     += -D ADD_EXPORTS
 		CXXFLAGS   += -D ADD_EXPORTS
@@ -159,9 +173,6 @@
 	endif
 endif
 
-ifeq (MinGW,$(UNAME))
-	SASSC_BIN = $(SASS_SASSC_PATH)/bin/sassc.exe
-endif
 ifeq (Windows,$(UNAME))
 	SASSC_BIN = $(SASS_SASSC_PATH)/bin/sassc.exe
 endif
@@ -171,7 +182,7 @@
 RESOURCES =
 STATICLIB = lib/libsass.a
 SHAREDLIB = lib/libsass.so
-ifeq (MinGW,$(UNAME))
+ifeq (Windows,$(UNAME))
 	RESOURCES += res/resource.rc
 	SHAREDLIB  = lib/libsass.dll
 	ifeq (shared,$(BUILD))
@@ -294,13 +305,16 @@
 	$(SASSC_BIN) -v
 
 test: $(SASSC_BIN)
-	$(RUBY_BIN) $(SASS_SPEC_PATH)/sass-spec.rb -c $(SASSC_BIN) -s $(LOG_FLAGS) $(SASS_SPEC_PATH)/$(SASS_SPEC_SPEC_DIR)
+	$(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)
 
 test_build: $(SASSC_BIN)
-	$(RUBY_BIN) $(SASS_SPEC_PATH)/sass-spec.rb -c $(SASSC_BIN) -s --ignore-todo $(LOG_FLAGS) $(SASS_SPEC_PATH)/$(SASS_SPEC_SPEC_DIR)
+	$(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)
 
-test_issues: $(SASSC_BIN)
-	$(RUBY_BIN) $(SASS_SPEC_PATH)/sass-spec.rb -c $(SASSC_BIN) $(LOG_FLAGS) $(SASS_SPEC_PATH)/spec/issues
+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)
+
+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)
 
 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
@@ -1,47 +1,52 @@
 # this is merely a common Makefile multiple implementers can use
+# bigger files (in terms of compile time) tend to go to the top,
+# so they don't end up as the last compile unit when compiling
+# in parallel. But we also want to mix them a little too avoid
+# heavy RAM usage peaks. Other than that the order is arbitrary.
 
+
 SOURCES = \
 	ast.cpp \
-	base64vlq.cpp \
-	bind.cpp \
-	color_maps.cpp \
-	constants.cpp \
+	node.cpp \
 	context.cpp \
-	cssize.cpp \
-	emitter.cpp \
+	constants.cpp \
+	functions.cpp \
+	color_maps.cpp \
 	environment.cpp \
-	error_handling.cpp \
-	eval.cpp \
-	expand.cpp \
-	extend.cpp \
+	bind.cpp \
 	file.cpp \
-	functions.cpp \
-	inspect.cpp \
+	util.cpp \
 	json.cpp \
-	lexer.cpp \
-	listize.cpp \
-	memory_manager.cpp \
-	node.cpp \
-	output.cpp \
-	parser.cpp \
+	units.cpp \
+	values.cpp \
 	plugins.cpp \
 	position.cpp \
+	lexer.cpp \
+	parser.cpp \
 	prelexer.cpp \
+	eval.cpp \
+	expand.cpp \
+	listize.cpp \
+	cssize.cpp \
+	extend.cpp \
+	output.cpp \
+	inspect.cpp \
+	emitter.cpp \
+	check_nesting.cpp \
 	remove_placeholders.cpp \
 	sass.cpp \
 	sass_util.cpp \
 	sass_values.cpp \
 	sass_context.cpp \
 	sass_functions.cpp \
-	sass_interface.cpp \
 	sass2scss.cpp \
-	source_map.cpp \
 	to_c.cpp \
-	to_string.cpp \
 	to_value.cpp \
-	units.cpp \
+	source_map.cpp \
+	subset_map.cpp \
+	error_handling.cpp \
+	memory/SharedPtr.cpp \
 	utf8_string.cpp \
-	values.cpp \
-	util.cpp
+	base64vlq.cpp
 
 CSOURCES = cencode.c
diff --git a/libsass/VERSION b/libsass/VERSION
--- a/libsass/VERSION
+++ b/libsass/VERSION
@@ -1,1 +1,1 @@
-3.3.2
+3.4.3
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
@@ -1,6 +1,8 @@
 #ifndef SASS_BASE_H
 #define SASS_BASE_H
 
+// #define DEBUG_SHARED_PTR
+
 #ifdef _MSC_VER
   #pragma warning(disable : 4503)
   #ifndef _SCL_SECURE_NO_WARNINGS
@@ -56,9 +58,19 @@
   SASS_STYLE_NESTED,
   SASS_STYLE_EXPANDED,
   SASS_STYLE_COMPACT,
-  SASS_STYLE_COMPRESSED
+  SASS_STYLE_COMPRESSED,
+  // only used internaly
+  SASS_STYLE_INSPECT,
+  SASS_STYLE_TO_SASS
 };
 
+// to allocate buffer to be filled
+ADDAPI void* ADDCALL sass_alloc_memory(size_t size);
+// to allocate a buffer from existing string
+ADDAPI char* ADDCALL sass_copy_c_string(const char* str);
+// to free overtaken memory when done
+ADDAPI void ADDCALL sass_free_memory(void* ptr);
+
 // Some convenient string helper function
 ADDAPI char* ADDCALL sass_string_quote (const char* str, const char quote_mark);
 ADDAPI char* ADDCALL sass_string_unquote (const char* str);
@@ -66,8 +78,12 @@
 // 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[]);
 
-// Get compiled libsass version
+// Implemented sass language version
+// Hardcoded version 3.4 for time being
 ADDAPI const char* ADDCALL libsass_version(void);
+
+// Get compiled libsass language
+ADDAPI const char* ADDCALL libsass_language_version(void);
 
 #ifdef __cplusplus
 } // __cplusplus defined.
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
@@ -50,6 +50,7 @@
 // Release all memory allocated with the compiler
 // This does _not_ include any contexts or options
 ADDAPI void ADDCALL sass_delete_compiler(struct Sass_Compiler* compiler);
+ADDAPI void ADDCALL sass_delete_options(struct Sass_Options* options);
 
 // Release all memory allocated and also ourself
 ADDAPI void ADDCALL sass_delete_file_context (struct Sass_File_Context* ctx);
@@ -73,6 +74,7 @@
 ADDAPI bool ADDCALL sass_option_get_source_comments (struct Sass_Options* options);
 ADDAPI bool ADDCALL sass_option_get_source_map_embed (struct Sass_Options* options);
 ADDAPI bool ADDCALL sass_option_get_source_map_contents (struct Sass_Options* options);
+ADDAPI bool ADDCALL sass_option_get_source_map_file_urls (struct Sass_Options* options);
 ADDAPI bool ADDCALL sass_option_get_omit_source_map_url (struct Sass_Options* options);
 ADDAPI bool ADDCALL sass_option_get_is_indented_syntax_src (struct Sass_Options* options);
 ADDAPI const char* ADDCALL sass_option_get_indent (struct Sass_Options* options);
@@ -93,6 +95,7 @@
 ADDAPI void ADDCALL sass_option_set_source_comments (struct Sass_Options* options, bool source_comments);
 ADDAPI void ADDCALL sass_option_set_source_map_embed (struct Sass_Options* options, bool source_map_embed);
 ADDAPI void ADDCALL sass_option_set_source_map_contents (struct Sass_Options* options, bool source_map_contents);
+ADDAPI void ADDCALL sass_option_set_source_map_file_urls (struct Sass_Options* options, bool source_map_file_urls);
 ADDAPI void ADDCALL sass_option_set_omit_source_map_url (struct Sass_Options* options, bool omit_source_map_url);
 ADDAPI void ADDCALL sass_option_set_is_indented_syntax_src (struct Sass_Options* options, bool is_indented_syntax_src);
 ADDAPI void ADDCALL sass_option_set_indent (struct Sass_Options* options, const char* indent);
diff --git a/libsass/include/sass/interface.h b/libsass/include/sass/interface.h
deleted file mode 100644
--- a/libsass/include/sass/interface.h
+++ /dev/null
@@ -1,105 +0,0 @@
-#ifndef SASS_C_INTERFACE_H
-#define SASS_C_INTERFACE_H
-
-// the API in this header has been deprecated
-// please use the new API from sass/context.h
-
-#include <stddef.h>
-#include <stdbool.h>
-#include <sass/base.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-// Please ensure there are no null values.
-// Thar be dragons.
-struct sass_options {
-  // Output style for the generated css code
-  // A value from above SASS_STYLE_* constants
-  int output_style;
-  // If you want inline source comments
-  bool source_comments;
-  // Path to source map file
-  // Enables the source map generating
-  // Used to create sourceMappingUrl
-  const char* source_map_file;
-  // Disable sourceMappingUrl in css output
-  bool omit_source_map_url;
-  // embed sourceMappingUrl as data uri
-  bool source_map_embed;
-  // embed include contents in maps
-  bool source_map_contents;
-  // Pass-through as sourceRoot property
-  const char* source_map_root;
-  // Treat source_string as sass (as opposed to scss)
-  bool is_indented_syntax_src;
-  // Colon-separated list of paths
-  // Semicolon-separated on Windows
-  const char* include_paths;
-  const char* plugin_paths;
-  // String to be used for indentation
-  const char* indent;
-  // String to be used to for line feeds
-  const char* linefeed;
-  // Precision for outputting fractional numbers
-  int precision;
-};
-
-struct sass_context {
-  const char* input_path;
-  const char* output_path;
-  char* source_string;
-  char* output_string;
-  char* source_map_string;
-  struct sass_options options;
-  int error_status;
-  char* error_message;
-  Sass_Function_List c_functions;
-  char** included_files;
-  int num_included_files;
-};
-
-struct sass_file_context {
-  const char* input_path;
-  const char* output_path;
-  char* output_string;
-  char* source_map_string;
-  struct sass_options options;
-  int error_status;
-  char* error_message;
-  Sass_Function_List c_functions;
-  char** included_files;
-  int num_included_files;
-};
-
-struct sass_folder_context {
-  const char* search_path;
-  const char* output_path;
-  struct sass_options options;
-  int error_status;
-  char* error_message;
-  Sass_Function_List c_functions;
-  char** included_files;
-  int num_included_files;
-};
-
-struct sass_context* sass_new_context (void);
-struct sass_file_context* sass_new_file_context (void);
-struct sass_folder_context* sass_new_folder_context (void);
-
-void sass_free_context (struct sass_context* ctx);
-void sass_free_file_context (struct sass_file_context* ctx);
-void sass_free_folder_context(struct sass_folder_context* ctx);
-
-int sass_compile (struct sass_context* ctx);
-int sass_compile_file (struct sass_file_context* ctx);
-int sass_compile_folder (struct sass_folder_context* ctx);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
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
@@ -29,7 +29,10 @@
 // Tags for denoting Sass list separators
 enum Sass_Separator {
   SASS_COMMA,
-  SASS_SPACE
+  SASS_SPACE,
+  // only used internally to represent a hash map before evaluation
+  // otherwise we would be too early to check for duplicate keys
+  SASS_HASH
 };
 
 // Value Operators
@@ -40,6 +43,32 @@
   NUM_OPS                    // so we know how big to make the op table
 };
 
+// Creator functions for all value types
+ADDAPI union Sass_Value* ADDCALL sass_make_null    (void);
+ADDAPI union Sass_Value* ADDCALL sass_make_boolean (bool val);
+ADDAPI union Sass_Value* ADDCALL sass_make_string  (const char* val);
+ADDAPI union Sass_Value* ADDCALL sass_make_qstring (const char* val);
+ADDAPI union Sass_Value* ADDCALL sass_make_number  (double val, const char* unit);
+ADDAPI union Sass_Value* ADDCALL sass_make_color   (double r, double g, double b, double a);
+ADDAPI union Sass_Value* ADDCALL sass_make_list    (size_t len, enum Sass_Separator sep);
+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);
+
+// Generic destructor function for all types
+// Will release memory of all associated Sass_Values
+// Means we will delete recursively for lists and maps
+ADDAPI void ADDCALL sass_delete_value (union Sass_Value* val);
+
+// Make a deep cloned copy of the given sass value
+ADDAPI union Sass_Value* ADDCALL sass_clone_value (const union Sass_Value* val);
+
+// Execute an operation for two Sass_Values and return the result as a Sass_Value too
+ADDAPI union Sass_Value* ADDCALL sass_value_op (enum Sass_OP op, const union Sass_Value* a, const union Sass_Value* b);
+
+// Stringify a Sass_Values and also return the result as a Sass_Value (of type STRING)
+ADDAPI union Sass_Value* ADDCALL sass_value_stringify (const union Sass_Value* a, bool compressed, int precision);
+
 // Return the sass tag for a generic sass value
 // Check is needed before accessing specific values!
 ADDAPI enum Sass_Tag ADDCALL sass_value_get_tag (const union Sass_Value* v);
@@ -106,33 +135,6 @@
 // Getters and setters for Sass_Warning
 ADDAPI char* ADDCALL sass_warning_get_message (const union Sass_Value* v);
 ADDAPI void ADDCALL sass_warning_set_message (union Sass_Value* v, char* msg);
-
-// Creator functions for all value types
-ADDAPI union Sass_Value* ADDCALL sass_make_null    (void);
-ADDAPI union Sass_Value* ADDCALL sass_make_boolean (bool val);
-ADDAPI union Sass_Value* ADDCALL sass_make_string  (const char* val);
-ADDAPI union Sass_Value* ADDCALL sass_make_qstring (const char* val);
-ADDAPI union Sass_Value* ADDCALL sass_make_number  (double val, const char* unit);
-ADDAPI union Sass_Value* ADDCALL sass_make_color   (double r, double g, double b, double a);
-ADDAPI union Sass_Value* ADDCALL sass_make_list    (size_t len, enum Sass_Separator sep);
-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);
-
-// Generic destructor function for all types
-// Will release memory of all associated Sass_Values
-// Means we will delete recursively for lists and maps
-ADDAPI void ADDCALL sass_delete_value (union Sass_Value* val);
-
-// Make a deep cloned copy of the given sass value
-ADDAPI union Sass_Value* ADDCALL sass_clone_value (const union Sass_Value* val);
-
-// Stringify a Sass_Values and also return the result as a Sass_Value (of type STRING)
-ADDAPI union Sass_Value* ADDCALL sass_value_stringify (const union Sass_Value* a, bool compressed, int precision);
-
-// Execute an operation for two Sass_Values and return the result as a Sass_Value too
-ADDAPI union Sass_Value* ADDCALL sass_value_op (enum Sass_OP op, const union Sass_Value* a, const union Sass_Value* b);
-
 
 #ifdef __cplusplus
 } // __cplusplus defined.
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
@@ -5,4 +5,8 @@
 #define LIBSASS_VERSION "[NA]"
 #endif
 
+#ifndef LIBSASS_LANGUAGE_VERSION
+#define LIBSASS_LANGUAGE_VERSION "3.4"
+#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
@@ -5,4 +5,8 @@
 #define LIBSASS_VERSION "@PACKAGE_VERSION@"
 #endif
 
+#ifndef LIBSASS_LANGUAGE_VERSION
+#define LIBSASS_LANGUAGE_VERSION "3.4"
+#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.0.5"
+#define SASS2SCSS_VERSION "1.1.0"
 #endif
 
 // add namespace for c++
diff --git a/libsass/src/ast.cpp b/libsass/src/ast.cpp
--- a/libsass/src/ast.cpp
+++ b/libsass/src/ast.cpp
@@ -1,2134 +1,2451 @@
-#include "ast.hpp"
-#include "context.hpp"
-#include "node.hpp"
-#include "extend.hpp"
-#include "to_string.hpp"
-#include "color_maps.hpp"
-#include <set>
-#include <iomanip>
-#include <algorithm>
-#include <iostream>
-
-namespace Sass {
-
-  static Null sass_null(Sass::Null(ParserState("null")));
-
-  bool Supports_Operator::needs_parens(Supports_Condition* cond) const {
-    return dynamic_cast<Supports_Negation*>(cond) ||
-          (dynamic_cast<Supports_Operator*>(cond) &&
-           dynamic_cast<Supports_Operator*>(cond)->operand() != operand());
-  }
-
-  bool Supports_Negation::needs_parens(Supports_Condition* cond) const {
-    return dynamic_cast<Supports_Negation*>(cond) ||
-          dynamic_cast<Supports_Operator*>(cond);
-  }
-
-  void AST_Node::update_pstate(const ParserState& pstate)
-  {
-    pstate_.offset += pstate - pstate_ + pstate.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* l = (*this)[i];
-      Simple_Selector* 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()
-  {
-    return has_parent_reference();
-  }
-
-  bool Complex_Selector::has_parent_ref()
-  {
-    return (head() && head()->has_parent_ref()) ||
-           (tail() && tail()->has_parent_ref());
-  }
-
-  bool Complex_Selector::operator< (const Complex_Selector& rhs) const
-  {
-    // const iterators for tails
-    const Complex_Selector* l = this;
-    const Complex_Selector* r = &rhs;
-    Compound_Selector* l_h = l ? l->head() : 0;
-    Compound_Selector* 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
-    const Complex_Selector* l = this;
-    const Complex_Selector* r = &rhs;
-    Compound_Selector* l_h = l ? l->head() : 0;
-    Compound_Selector* 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;
-      }
-      // fail if only one is null
-      else if (!r_h) return !l_h;
-      else if (!l_h) return !r_h;
-      // 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 heads
-        l_h = l ? l->head() : 0;
-        r_h = r ? r->head() : 0;
-      }
-      // abort
-      else break;
-    }
-    // unreachable
-    return false;
-  }
-
-  Compound_Selector* Compound_Selector::unify_with(Compound_Selector* rhs, Context& ctx)
-  {
-    Compound_Selector* unified = rhs;
-    for (size_t i = 0, L = length(); i < L; ++i)
-    {
-      if (!unified) break;
-      unified = (*this)[i]->unify_with(unified, ctx);
-    }
-    return unified;
-  }
-
-  bool Simple_Selector::operator== (const Simple_Selector& rhs) const
-  {
-    const Attribute_Selector* ll = dynamic_cast<const Attribute_Selector*>(this);
-    const Attribute_Selector* rr = dynamic_cast<const Attribute_Selector*>(&rhs);
-    if (ll && rr) return *ll == *rr;
-
-    if (is_ns_eq(ns(), rhs.ns()))
-    { return name() == rhs.name(); }
-    return ns() == rhs.ns();
-  }
-
-  bool Simple_Selector::operator< (const Simple_Selector& rhs) const
-  {
-    const Attribute_Selector* ll = dynamic_cast<const Attribute_Selector*>(this);
-    const Attribute_Selector* rr = dynamic_cast<const Attribute_Selector*>(&rhs);
-    if (ll && rr) return *ll < *rr;
-
-    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 (const Selector_List* ls = dynamic_cast<const Selector_List*>(&rhs)) { return *this == *ls; }
-    else if (const Complex_Selector* ls = dynamic_cast<const Complex_Selector*>(&rhs)) { return *this == *ls; }
-    else if (const Compound_Selector* ls = dynamic_cast<const Compound_Selector*>(&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 (const List* ls = dynamic_cast<const List*>(&rhs)) { return *this == *ls; }
-    if (const Selector* ls = dynamic_cast<const 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*> l_lst = this->elements();
-    std::vector<Complex_Selector*> 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* l = l_lst[i];
-      Complex_Selector* 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;
-  }
-
-  Compound_Selector* Simple_Selector::unify_with(Compound_Selector* rhs, Context& ctx)
-  {
-    To_String to_string(&ctx);
-    for (size_t i = 0, L = rhs->length(); i < L; ++i)
-    { if (perform(&to_string) == (*rhs)[i]->perform(&to_string)) return rhs; }
-
-    // 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 ((typeid(*(*rhs)[i]) == typeid(Pseudo_Selector) || typeid(*(*rhs)[i]) == typeid(Wrapped_Selector)) && (*rhs)[L-1]->is_pseudo_element())
-        { found = true; break; }
-      }
-    }
-    else
-    {
-      for (i = 0, L = rhs->length(); i < L; ++i)
-      {
-        if (typeid(*(*rhs)[i]) == typeid(Pseudo_Selector) || typeid(*(*rhs)[i]) == typeid(Wrapped_Selector))
-        { found = true; break; }
-      }
-    }
-    if (!found)
-    {
-      Compound_Selector* cpy = SASS_MEMORY_NEW(ctx.mem, Compound_Selector, *rhs);
-      (*cpy) << this;
-      return cpy;
-    }
-    Compound_Selector* cpy = SASS_MEMORY_NEW(ctx.mem, Compound_Selector, rhs->pstate());
-    for (size_t j = 0; j < i; ++j)
-    { (*cpy) << (*rhs)[j]; }
-    (*cpy) << this;
-    for (size_t j = i; j < L; ++j)
-    { (*cpy) << (*rhs)[j]; }
-    return cpy;
-  }
-
-  Simple_Selector* Type_Selector::unify_with(Simple_Selector* 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())
-      {
-        // creaty the copy inside (avoid unnecessary copies)
-        Type_Selector* ts = SASS_MEMORY_NEW(ctx.mem, Type_Selector, *this);
-        // overwrite the name if star is given as name
-        if (ts->name() == "*") { ts->name(rhs->name()); }
-        // now overwrite the namespace name and flag
-        ts->ns(rhs->ns()); ts->has_ns(rhs->has_ns());
-        // return copy
-        return ts;
-      }
-    }
-    // namespace may changed, check the name now
-    // overwrite star (but not with another star)
-    if (name() == "*" && rhs->name() != "*")
-    {
-      // creaty the copy inside (avoid unnecessary copies)
-      Type_Selector* ts = SASS_MEMORY_NEW(ctx.mem, Type_Selector, *this);
-      // simply set the new name
-      ts->name(rhs->name());
-      // return copy
-      return ts;
-    }
-    // return original
-    return this;
-  }
-
-  Compound_Selector* Type_Selector::unify_with(Compound_Selector* rhs, Context& ctx)
-  {
-    // TODO: handle namespaces
-
-    // if the rhs is empty, just return a copy of this
-    if (rhs->length() == 0) {
-      Compound_Selector* cpy = SASS_MEMORY_NEW(ctx.mem, Compound_Selector, rhs->pstate());
-      (*cpy) << this;
-      return cpy;
-    }
-
-    Simple_Selector* rhs_0 = (*rhs)[0];
-    // otherwise, this is a tag name
-    if (name() == "*")
-    {
-      if (typeid(*rhs_0) == typeid(Type_Selector))
-      {
-        // if rhs is universal, just return this tagname + rhs's qualifiers
-        Compound_Selector* cpy = SASS_MEMORY_NEW(ctx.mem, Compound_Selector, *rhs);
-        Type_Selector* ts = static_cast<Type_Selector*>(rhs_0);
-        (*cpy)[0] = this->unify_with(ts, ctx);
-        return cpy;
-      }
-      else if (dynamic_cast<Selector_Qualifier*>(rhs_0)) {
-        // qualifier is `.class`, so we can prefix with `ns|*.class`
-        Compound_Selector* cpy = SASS_MEMORY_NEW(ctx.mem, Compound_Selector, rhs->pstate());
-        if (has_ns() && !rhs_0->has_ns()) {
-          if (ns() != "*") (*cpy) << this;
-        }
-        for (size_t i = 0, L = rhs->length(); i < L; ++i)
-        { (*cpy) << (*rhs)[i]; }
-        return cpy;
-      }
-
-
-      return rhs;
-    }
-
-    if (typeid(*rhs_0) == typeid(Type_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
-      Compound_Selector* copy = SASS_MEMORY_NEW(ctx.mem, Compound_Selector, *rhs);
-      (*copy)[0] = this->unify_with(rhs_0, ctx);
-      return copy;
-
-    }
-    // else it's a tag name and a bunch of qualifiers -- just append them
-    Compound_Selector* cpy = SASS_MEMORY_NEW(ctx.mem, Compound_Selector, rhs->pstate());
-    if (name() != "*") (*cpy) << this;
-    (*cpy) += rhs;
-    return cpy;
-  }
-
-  Compound_Selector* Selector_Qualifier::unify_with(Compound_Selector* rhs, Context& ctx)
-  {
-    if (name()[0] == '#')
-    {
-      for (size_t i = 0, L = rhs->length(); i < L; ++i)
-      {
-        Simple_Selector* rhs_i = (*rhs)[i];
-        if (typeid(*rhs_i) == typeid(Selector_Qualifier) &&
-            static_cast<Selector_Qualifier*>(rhs_i)->name()[0] == '#' &&
-            static_cast<Selector_Qualifier*>(rhs_i)->name() != name())
-          return 0;
-      }
-    }
-    rhs->has_line_break(has_line_break());
-    return Simple_Selector::unify_with(rhs, ctx);
-  }
-
-  Compound_Selector* Pseudo_Selector::unify_with(Compound_Selector* rhs, Context& ctx)
-  {
-    if (is_pseudo_element())
-    {
-      for (size_t i = 0, L = rhs->length(); i < L; ++i)
-      {
-        Simple_Selector* rhs_i = (*rhs)[i];
-        if (typeid(*rhs_i) == typeid(Pseudo_Selector) &&
-            static_cast<Pseudo_Selector*>(rhs_i)->is_pseudo_element() &&
-            static_cast<Pseudo_Selector*>(rhs_i)->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()) {
-          return value() < rhs.value();
-        } else { return matcher() < rhs.matcher(); }
-      } else { return name() < rhs.name(); }
-    }
-    else return false;
-  }
-
-  bool Attribute_Selector::operator< (const Simple_Selector& rhs) const
-  {
-    if (const Attribute_Selector* w = dynamic_cast<const Attribute_Selector*>(&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
-  {
-    if (is_ns_eq(ns(), rhs.ns()) && name() == rhs.name())
-    { return matcher() == rhs.matcher() && value() == rhs.value(); }
-    else return false;
-  }
-
-  bool Attribute_Selector::operator== (const Simple_Selector& rhs) const
-  {
-    if (const Attribute_Selector* w = dynamic_cast<const Attribute_Selector*>(&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 (const Wrapped_Selector* w = dynamic_cast<const Wrapped_Selector*>(&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* sub)
-  {
-    if (this->name() != sub->name()) return false;
-    if (this->name() == ":current") return false;
-    if (Selector_List* rhs_list = dynamic_cast<Selector_List*>(sub->selector())) {
-      if (Selector_List* lhs_list = dynamic_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* rhs, std::string wrapped)
-  {
-    for (Complex_Selector* item : rhs->elements()) {
-      if (is_superselector_of(item, wrapped)) return true;
-    }
-    return false;
-  }
-
-  bool Compound_Selector::is_superselector_of(Complex_Selector* rhs, std::string wrapped)
-  {
-    if (rhs->head()) return is_superselector_of(rhs->head(), wrapped);
-    return false;
-  }
-
-  bool Compound_Selector::is_superselector_of(Compound_Selector* rhs, std::string wrapping)
-  {
-    To_String to_string;
-
-    Compound_Selector* lhs = this;
-    Simple_Selector* lbase = lhs->base();
-    Simple_Selector* 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]->perform(&to_string));
-        pseudo = pseudo.substr(pseudo.find_first_not_of(":")); // strip off colons to ensure :after matches ::after since ruby sass is forgiving
-        lpsuedoset.insert(pseudo);
-      }
-    }
-    for (size_t i = 0, L = rhs->length(); i < L; ++i)
-    {
-      if ((*rhs)[i]->is_pseudo_element()) {
-        std::string pseudo((*rhs)[i]->perform(&to_string));
-        pseudo = pseudo.substr(pseudo.find_first_not_of(":")); // strip off colons to ensure :after matches ::after since ruby sass is forgiving
-        rpsuedoset.insert(pseudo);
-      }
-    }
-    if (lpsuedoset != rpsuedoset) {
-      return false;
-    }
-
-    std::set<std::string> lset, rset;
-
-    if (lbase && rbase)
-    {
-      if (lbase->perform(&to_string) == rbase->perform(&to_string)) {
-        for (size_t i = 1, L = length(); i < L; ++i)
-        { lset.insert((*this)[i]->perform(&to_string)); }
-        for (size_t i = 1, L = rhs->length(); i < L; ++i)
-        { rset.insert((*rhs)[i]->perform(&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* lhs = (*this)[i];
-      // very special case for wrapped matches selector
-      if (Wrapped_Selector* wrapped = dynamic_cast<Wrapped_Selector*>(lhs)) {
-        if (wrapped->name() == ":not") {
-          if (Selector_List* not_list = dynamic_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* list = dynamic_cast<Selector_List*>(wrapped->selector())) {
-            if (Compound_Selector* comp = dynamic_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* rhs_sel = rhs->elements().size() > i ? (*rhs)[i] : 0;
-        if (Wrapped_Selector* wrapped_r = dynamic_cast<Wrapped_Selector*>(rhs_sel)) {
-          if (wrapped->name() == wrapped_r->name()) {
-          if (wrapped->is_superselector_of(wrapped_r)) {
-             continue;
-             rset.insert(lhs->perform(&to_string));
-
-          }}
-        }
-      }
-      // match from here on as strings
-      lset.insert(lhs->perform(&to_string));
-    }
-
-    for (size_t n = 0, nL = rhs->length(); n < nL; ++n)
-    {
-      auto r = (*rhs)[n];
-      if (Wrapped_Selector* wrapped = dynamic_cast<Wrapped_Selector*>(r)) {
-        if (wrapped->name() == ":not") {
-          if (Selector_List* ls = dynamic_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* ls = dynamic_cast<Selector_List*>(wrapped->selector())) {
-            ls->remove_parent_selectors();
-            return (is_superselector_of(ls, wrapped->name()));
-          }
-        }
-      }
-      rset.insert(r->perform(&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* Compound_Selector::to_complex(Memory_Manager& mem)
-  {
-    // create an intermediate complex selector
-    return SASS_MEMORY_NEW(mem, Complex_Selector,
-                           pstate(),
-                           Complex_Selector::ANCESTOR_OF,
-                           this,
-                           0);
-  }
-
-  Selector_List* Complex_Selector::unify_with(Complex_Selector* other, Context& ctx)
-  {
-
-    // get last tails (on the right side)
-    Complex_Selector* l_last = this->last();
-    Complex_Selector* 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* l_last_head = l_last->head();
-    Compound_Selector* 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* 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* fake = unified->to_complex(ctx.mem);
-      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* result = SASS_MEMORY_NEW(ctx.mem, 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) << 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*> l_lst = this->elements();
-    std::vector<Simple_Selector*> 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* l = l_lst[i];
-      Simple_Selector* 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* const pLeft, const Complex_Selector* const pRight) const {
-    return *pLeft < *pRight;
-  }
-
-  bool Complex_Selector::is_superselector_of(Compound_Selector* rhs, std::string wrapping)
-  {
-    return last()->head() && last()->head()->is_superselector_of(rhs, wrapping);
-  }
-
-  bool Complex_Selector::is_superselector_of(Complex_Selector* rhs, std::string wrapping)
-  {
-    Complex_Selector* lhs = this;
-    To_String to_string;
-    // check for selectors with leading or trailing combinators
-    if (!lhs->head() || !rhs->head())
-    { return false; }
-    const Complex_Selector* l_innermost = lhs->innermost();
-    if (l_innermost->combinator() != Complex_Selector::ANCESTOR_OF)
-    { return false; }
-    const Complex_Selector* 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* lhs_tail = lhs->tail();
-      Complex_Selector* 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() && lhs_tail->head()) {
-        if (!lhs_tail->head()->is_superselector_of(rhs_tail->head())) return false;
-      }
-    }
-
-    bool found = false;
-    Complex_Selector* marker = rhs;
-    for (size_t i = 0, L = rhs->length(); i < L; ++i) {
-      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* Complex_Selector::context(Context& ctx)
-  {
-    if (!tail()) return 0;
-    if (!head()) return tail()->context(ctx);
-    Complex_Selector* cpy = SASS_MEMORY_NEW(ctx.mem, 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* ss)
-  {
-
-    Complex_Selector* t = ss->tail();
-    Combinator c = ss->combinator();
-    String* r = ss->reference();
-    Compound_Selector* 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* rh = last()->head();
-        size_t i = 0, L = h->length();
-        if (dynamic_cast<Type_Selector*>(h->first())) {
-          if (Selector_Qualifier* sq = dynamic_cast<Selector_Qualifier*>(rh->last())) {
-            Selector_Qualifier* sqs = new Selector_Qualifier(*sq);
-            sqs->name(sqs->name() + (*h)[0]->name());
-            (*rh)[rh->length()-1] = sqs;
-            for (i = 1; i < L; ++i) *rh << (*h)[i];
-          } else if (Type_Selector* ts = dynamic_cast<Type_Selector*>(rh->last())) {
-            Type_Selector* tss = new Type_Selector(*ts);
-            tss->name(tss->name() + (*h)[0]->name());
-            (*rh)[rh->length()-1] = tss;
-            for (i = 1; i < L; ++i) *rh << (*h)[i];
-          } else if (Selector_Placeholder* ps = dynamic_cast<Selector_Placeholder*>(rh->last())) {
-            Selector_Placeholder* pss = new Selector_Placeholder(*ps);
-            pss->name(pss->name() + (*h)[0]->name());
-            (*rh)[rh->length()-1] = pss;
-            for (i = 1; i < L; ++i) *rh << (*h)[i];
-          } else {
-            *last()->head_ += h;
-          }
-        } else {
-          *last()->head_ += h;
-        }
-      } else {
-        *last()->head_ += h;
-      }
-    } else {
-      // std::cerr << "has no or empty head\n";
-    }
-
-    if (last()) {
-      if (last()->combinator() != ANCESTOR_OF && c != ANCESTOR_OF) {
-        Complex_Selector* inter = SASS_MEMORY_NEW(ctx.mem, 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* Selector_List::parentize(Selector_List* ps, Context& ctx)
-  {
-    Selector_List* ss = SASS_MEMORY_NEW(ctx.mem, Selector_List, pstate());
-    for (size_t pi = 0, pL = ps->length(); pi < pL; ++pi) {
-      Selector_List* list = SASS_MEMORY_NEW(ctx.mem, Selector_List, pstate());
-      *list << (*ps)[pi];
-      for (size_t si = 0, sL = this->length(); si < sL; ++si) {
-        *ss += (*this)[si]->parentize(list, ctx);
-      }
-    }
-    return ss;
-  }
-
-  Selector_List* Complex_Selector::parentize(Selector_List* parents, Context& ctx)
-  {
-
-    Complex_Selector* tail = this->tail();
-    Compound_Selector* head = this->head();
-
-    // first parentize the tail (which may return an expanded list)
-    Selector_List* tails = tail ? tail->parentize(parents, ctx) : 0;
-
-    if (head && head->length() > 0) {
-
-      // we have a parent selector in a simple compound list
-      // mix parent complex selector into the compound list
-      if (dynamic_cast<Parent_Selector*>((*head)[0])) {
-        if (parents && parents->length()) {
-          Selector_List* retval = SASS_MEMORY_NEW(ctx.mem, Selector_List, pstate());
-          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* t = (*tails)[n];
-                Complex_Selector* parent = (*parents)[i];
-                Complex_Selector* s = parent->cloneFully(ctx);
-                Complex_Selector* ss = this->clone(ctx);
-                ss->tail(t ? t->clone(ctx) : 0);
-                Compound_Selector* h = head_->clone(ctx);
-                if (h->length()) h->erase(h->begin());
-                ss->head(h->length() ? h : 0);
-                s->append(ctx, ss);
-                *retval << 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* parent = (*parents)[i];
-              Complex_Selector* s = parent->cloneFully(ctx);
-              Complex_Selector* ss = this->clone(ctx);
-              // 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 ? tail->clone(ctx) : 0);
-              Compound_Selector* h = head_->clone(ctx);
-              if (h->length()) h->erase(h->begin());
-              ss->head(h->length() ? h : 0);
-              // \/ IMO ruby sass bug \/
-              ss->has_line_feed(false);
-              s->append(ctx, ss);
-              *retval << s;
-            }
-          }
-          return retval;
-        }
-        // have no parent but some tails
-        else {
-          Selector_List* retval = SASS_MEMORY_NEW(ctx.mem, Selector_List, pstate());
-          if (tails && tails->length() > 0) {
-            for (size_t n = 0, nL = tails->length(); n < nL; ++n) {
-              Complex_Selector* cpy = this->clone(ctx);
-              cpy->tail((*tails)[n]->cloneFully(ctx));
-              cpy->head(SASS_MEMORY_NEW(ctx.mem, Compound_Selector, head->pstate()));
-              for (size_t i = 1, L = this->head()->length(); i < L; ++i)
-                *cpy->head() << (*this->head())[i];
-              if (!cpy->head()->length()) cpy->head(0);
-              *retval << cpy->skip_empty_reference();
-            }
-          }
-          // have no parent nor tails
-          else {
-            Complex_Selector* cpy = this->clone(ctx);
-            cpy->head(SASS_MEMORY_NEW(ctx.mem, Compound_Selector, head->pstate()));
-            for (size_t i = 1, L = this->head()->length(); i < L; ++i)
-              *cpy->head() << (*this->head())[i];
-            if (!cpy->head()->length()) cpy->head(0);
-            *retval << cpy->skip_empty_reference();
-          }
-          return retval;
-        }
-      }
-      // no parent selector in head
-      else {
-        return this->tails(ctx, tails);
-      }
-
-    }
-    // has no head
-    else {
-      return this->tails(ctx, tails);
-    }
-
-    // unreachable
-    return 0;
-  }
-
-  Selector_List* Complex_Selector::tails(Context& ctx, Selector_List* tails)
-  {
-    Selector_List* rv = SASS_MEMORY_NEW(ctx.mem, Selector_List, pstate_);
-    if (tails && tails->length()) {
-      for (size_t i = 0, iL = tails->length(); i < iL; ++i) {
-        Complex_Selector* pr = this->clone(ctx);
-        pr->tail((*tails)[i]);
-        *rv << pr;
-      }
-    }
-    else {
-      *rv << this;
-    }
-    return rv;
-  }
-
-  // return the last tail that is defined
-  Complex_Selector* Complex_Selector::first()
-  {
-    // declare variables used in loop
-    Complex_Selector* cur = this->tail_;
-    const Compound_Selector* head = head_;
-    // processing loop
-    while (cur)
-    {
-      // get the head
-      head = cur->head_;
-      // check for single parent ref
-      if (head && head->length() == 1)
-      {
-        // abort (and return) if it is not a parent selector
-        if (!dynamic_cast<Parent_Selector*>((*head)[0])) break;
-      }
-      // advance to next
-      cur = cur->tail_;
-    }
-    // result
-    return cur;
-  }
-
-  // return the last tail that is defined
-  const Complex_Selector* Complex_Selector::first() const
-  {
-    // declare variables used in loop
-    const Complex_Selector* cur = this->tail_;
-    const Compound_Selector* head = head_;
-    // processing loop
-    while (cur)
-    {
-      // get the head
-      head = cur->head_;
-      // check for single parent ref
-      if (head && head->length() == 1)
-      {
-        // abort (and return) if it is not a parent selector
-        if (!dynamic_cast<Parent_Selector*>((*head)[0])) break;
-      }
-      // advance to next
-      cur = cur->tail_;
-    }
-    // result
-    return cur;
-  }
-
-  // return the last tail that is defined
-  Complex_Selector* Complex_Selector::last()
-  {
-    // ToDo: implement with a while loop
-    return tail_? tail_->last() : this;
-  }
-
-  // return the last tail that is defined
-  const Complex_Selector* Complex_Selector::last() const
-  {
-    // 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* val, Combinator c)
-  {
-    if (!tail())
-    { tail(val); combinator(c); }
-    else
-    { tail()->set_innermost(val, c); }
-  }
-
-  Complex_Selector* Complex_Selector::clone(Context& ctx) const
-  {
-    Complex_Selector* cpy = SASS_MEMORY_NEW(ctx.mem, Complex_Selector, *this);
-    cpy->media_block(this->media_block());
-    if (tail()) cpy->tail(tail()->clone(ctx));
-    return cpy;
-  }
-
-  Complex_Selector* Complex_Selector::cloneFully(Context& ctx) const
-  {
-    Complex_Selector* cpy = SASS_MEMORY_NEW(ctx.mem, Complex_Selector, *this);
-
-    if (head()) {
-      cpy->head(head()->clone(ctx));
-    }
-
-    if (tail()) {
-      cpy->tail(tail()->cloneFully(ctx));
-    }
-
-    return cpy;
-  }
-
-  Compound_Selector* Compound_Selector::clone(Context& ctx) const
-  {
-    Compound_Selector* cpy = SASS_MEMORY_NEW(ctx.mem, Compound_Selector, *this);
-    cpy->media_block(this->media_block());
-    return cpy;
-  }
-
-  Selector_List* Selector_List::clone(Context& ctx) const
-  {
-    Selector_List* cpy = SASS_MEMORY_NEW(ctx.mem, Selector_List, *this);
-    cpy->media_block(this->media_block());
-    return cpy;
-  }
-
-  Selector_List* Selector_List::cloneFully(Context& ctx) const
-  {
-    Selector_List* cpy = SASS_MEMORY_NEW(ctx.mem, Selector_List, pstate());
-    for (size_t i = 0, L = length(); i < L; ++i) {
-      *cpy << (*this)[i]->cloneFully(ctx);
-    }
-    return cpy;
-  }
-
-  /* not used anymore - remove?
-  Selector_Placeholder* Selector::find_placeholder()
-  {
-    return 0;
-  }*/
-
-  // 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() && (*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());
-        }
-      }
-    }
-  }
-
-  void Selector_List::adjust_after_pushing(Complex_Selector* 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 *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 *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 *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 *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* Selector_List::unify_with(Selector_List* rhs, Context& ctx) {
-    std::vector<Complex_Selector*> 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* seq1 = (*this)[lhs_i];
-      for(size_t rhs_i = 0, rhs_L = rhs->length(); rhs_i < rhs_L; ++rhs_i) {
-        Complex_Selector* seq2 = (*rhs)[rhs_i];
-
-        Selector_List* 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* final_result = SASS_MEMORY_NEW(ctx.mem, Selector_List, pstate());
-    for (auto itr = unified_complex_selectors.begin(); itr != unified_complex_selectors.end(); ++itr) {
-      *final_result << *itr;
-    }
-    return final_result;
-  }
-
-  void Selector_List::populate_extends(Selector_List* extendee, Context& ctx, ExtensionSubsetMap& extends) {
-    To_String to_string;
-
-    Selector_List* extender = this;
-    for (auto complex_sel : extendee->elements()) {
-      Complex_Selector* c = complex_sel;
-
-
-      // Ignore any parent selectors, until we find the first non Selector_Reference head
-      Compound_Selector* compound_sel = c->head();
-      Complex_Selector* pIter = complex_sel;
-      while (pIter) {
-        Compound_Selector* pHead = pIter->head();
-        if (pHead && dynamic_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->to_str_vec(), std::make_pair((*extender)[i], compound_sel));
-      }
-    }
-  };
-
-  std::vector<std::string> Compound_Selector::to_str_vec()
-  {
-    To_String to_string;
-    std::vector<std::string> result;
-    result.reserve(length());
-    for (size_t i = 0, L = length(); i < L; ++i)
-    { result.push_back((*this)[i]->perform(&to_string)); }
-    return result;
-  }
-
-  Compound_Selector* Compound_Selector::minus(Compound_Selector* rhs, Context& ctx)
-  {
-    To_String to_string(&ctx);
-    Compound_Selector* result = SASS_MEMORY_NEW(ctx.mem, 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]->perform(&to_string));
-      for (size_t j = 0, M = rhs->length(); j < M; ++j)
-      {
-        if (thisSelector == (*rhs)[j]->perform(&to_string))
-        {
-          found = true;
-          break;
-        }
-      }
-      if (!found) (*result) << (*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((*iterator)->clone(ctx));
-    }
-  }
-
-  void Arguments::adjust_after_pushing(Argument* 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 {
-    Selector_List* sl = static_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) {
-      if (!(*block())[i]->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_unitless()
-  { 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; }
-
-  }
-
-  void Number::convert(const std::string& prefered, bool strict)
-  {
-    // abort if unit is empty
-    if (prefered.empty()) return;
-
-    // first make sure same units cancel each other out
-    // it seems that a map table will fit nicely to do this
-    // we basically construct exponents for each unit
-    // has the advantage that they will be pre-sorted
-    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;
-
-  }
-
-  // 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 (const Custom_Warning* r = dynamic_cast<const Custom_Warning*>(&rhs)) {
-      return message() == r->message();
-    }
-    return false;
-  }
-
-  bool Custom_Error::operator== (const Expression& rhs) const
-  {
-    if (const Custom_Error* r = dynamic_cast<const Custom_Error*>(&rhs)) {
-      return message() == r->message();
-    }
-    return false;
-  }
-
-  bool Number::operator== (const Expression& rhs) const
-  {
-    if (const Number* r = dynamic_cast<const Number*>(&rhs)) {
-      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
-  {
-    Number tmp_r(rhs);
-    tmp_r.normalize(find_convertible_unit());
-    std::string l_unit(unit());
-    std::string r_unit(tmp_r.unit());
-    if (!l_unit.empty() && !r_unit.empty() && 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 (const String_Quoted* qstr = dynamic_cast<const String_Quoted*>(&rhs)) {
-      return (value() == qstr->value());
-    } else if (const String_Constant* cstr = dynamic_cast<const String_Constant*>(&rhs)) {
-      return (value() == cstr->value());
-    }
-    return false;
-  }
-
-  bool String_Constant::operator== (const Expression& rhs) const
-  {
-    if (const String_Quoted* qstr = dynamic_cast<const String_Quoted*>(&rhs)) {
-      return (value() == qstr->value());
-    } else if (const String_Constant* cstr = dynamic_cast<const String_Constant*>(&rhs)) {
-      return (value() == cstr->value());
-    }
-    return false;
-  }
-
-  bool String_Schema::operator== (const Expression& rhs) const
-  {
-    if (const String_Schema* r = dynamic_cast<const String_Schema*>(&rhs)) {
-      if (length() != r->length()) return false;
-      for (size_t i = 0, L = length(); i < L; ++i) {
-        Expression* rv = (*r)[i];
-        Expression* 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 (const Boolean* r = dynamic_cast<const Boolean*>(&rhs)) {
-      return (value() == r->value());
-    }
-    return false;
-  }
-
-  bool Color::operator== (const Expression& rhs) const
-  {
-    if (const Color* r = dynamic_cast<const 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 (const List* r = dynamic_cast<const List*>(&rhs)) {
-      if (length() != r->length()) return false;
-      if (separator() != r->separator()) return false;
-      for (size_t i = 0, L = length(); i < L; ++i) {
-        Expression* rv = (*r)[i];
-        Expression* lv = (*this)[i];
-        if (!lv || !rv) return false;
-        if (!(*lv == *rv)) return false;
-      }
-      return true;
-    }
-    return false;
-  }
-
-  bool Map::operator== (const Expression& rhs) const
-  {
-    if (const Map* r = dynamic_cast<const Map*>(&rhs)) {
-      if (length() != r->length()) return false;
-      for (auto key : keys()) {
-        Expression* lv = at(key);
-        Expression* 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) {
-      if (Argument* arg = dynamic_cast<Argument*>((*this)[i])) {
-        if (!arg->name().empty()) return i;
-      }
-    }
-    return length();
-  }
-
-  Expression* Hashed::at(Expression* k) const
-  {
-    if (elements_.count(k))
-    { return elements_.at(k); }
-    else { return &sass_null; }
-  }
-
-  std::string Map::to_string(bool compressed, int precision) const
-  {
-    std::string res("");
-    if (empty()) return res;
-    if (is_invisible()) return res;
-    bool items_output = false;
-    for (auto key : keys()) {
-      if (key->is_invisible()) continue;
-      if (at(key)->is_invisible()) continue;
-      if (items_output) res += compressed ? "," : ", ";
-      Value* v_key = dynamic_cast<Value*>(key);
-      Value* v_val = dynamic_cast<Value*>(at(key));
-      if (v_key) res += v_key->to_string(compressed, precision);
-      res += compressed ? ":" : ": ";
-      if (v_val) res += v_val->to_string(compressed, precision);
-      items_output = true;
-    }
-    return res;
-  }
-
-  std::string List::to_string(bool compressed, int precision) const
-  {
-    std::string res("");
-    if (empty()) return res;
-    if (is_invisible()) return res;
-    bool items_output = false;
-    std::string sep = separator() == SASS_COMMA ? "," : " ";
-    if (!compressed && sep == ",") sep += " ";
-    for (size_t i = 0, L = size(); i < L; ++i) {
-      Expression* item = (*this)[i];
-      if (item->is_invisible()) continue;
-      if (items_output) res += sep;
-      if (Value* v_val = dynamic_cast<Value*>(item))
-      { res += v_val->to_string(compressed, precision); }
-      items_output = true;
-    }
-    return res;
-  }
-
-  std::string String_Schema::to_string(bool compressed, int precision) const
-  {
-    std::string res("");
-    for (size_t i = 0, L = length(); i < L; ++i) {
-      if ((*this)[i]->is_interpolant()) res += "#{";
-      if (Value* val = dynamic_cast<Value*>((*this)[i]))
-      { res += val->to_string(compressed, precision); }
-      if ((*this)[i]->is_interpolant()) res += "}";
-    }
-    return res;
-  }
-
-  std::string Null::to_string(bool compressed, int precision) const
-  {
-    return "null";
-  }
-
-  std::string Boolean::to_string(bool compressed, int precision) const
-  {
-    return value_ ? "true" : "false";
-  }
-
-  // helper function for serializing colors
-  template <size_t range>
-  static double cap_channel(double c) {
-    if      (c > range) return range;
-    else if (c < 0)     return 0;
-    else                return c;
-  }
-
-  std::string Color::to_string(bool compressed, int precision) const
-  {
-    std::stringstream ss;
-
-    // original color name
-    // maybe an unknown token
-    std::string name = disp();
-
-    // resolved color
-    std::string res_name = name;
-
-    double r = Sass::round(cap_channel<0xff>(r_));
-    double g = Sass::round(cap_channel<0xff>(g_));
-    double b = Sass::round(cap_channel<0xff>(b_));
-    double a = cap_channel<1>   (a_);
-
-    // get color from given name (if one was given at all)
-    if (name != "" && name_to_color(name)) {
-      const Color* n = name_to_color(name);
-      r = Sass::round(cap_channel<0xff>(n->r()));
-      g = Sass::round(cap_channel<0xff>(n->g()));
-      b = Sass::round(cap_channel<0xff>(n->b()));
-      a = cap_channel<1>   (n->a());
-    }
-    // otherwise get the possible resolved color name
-    else {
-      double numval = r * 0x10000 + g * 0x100 + b;
-      if (color_to_name(numval))
-        res_name = color_to_name(numval);
-    }
-
-    std::stringstream hexlet;
-    hexlet << '#' << std::setw(1) << std::setfill('0');
-    // create a short color hexlet if there is any need for it
-    if (compressed && is_color_doublet(r, g, b) && a == 1) {
-      hexlet << std::hex << std::setw(1) << (static_cast<unsigned long>(r) >> 4);
-      hexlet << std::hex << std::setw(1) << (static_cast<unsigned long>(g) >> 4);
-      hexlet << std::hex << std::setw(1) << (static_cast<unsigned long>(b) >> 4);
-    } else {
-      hexlet << std::hex << std::setw(2) << static_cast<unsigned long>(r);
-      hexlet << std::hex << std::setw(2) << static_cast<unsigned long>(g);
-      hexlet << std::hex << std::setw(2) << static_cast<unsigned long>(b);
-    }
-
-    if (compressed && !this->is_delayed()) name = "";
-
-    // retain the originally specified color definition if unchanged
-    if (name != "") {
-      ss << name;
-    }
-    else if (r == 0 && g == 0 && b == 0 && a == 0) {
-        ss << "transparent";
-    }
-    else if (a >= 1) {
-      if (res_name != "") {
-        if (compressed && hexlet.str().size() < res_name.size()) {
-          ss << hexlet.str();
-        } else {
-          ss << res_name;
-        }
-      }
-      else {
-        ss << hexlet.str();
-      }
-    }
-    else {
-      ss << "rgba(";
-      ss << static_cast<unsigned long>(r) << ",";
-      if (!compressed) ss << " ";
-      ss << static_cast<unsigned long>(g) << ",";
-      if (!compressed) ss << " ";
-      ss << static_cast<unsigned long>(b) << ",";
-      if (!compressed) ss << " ";
-      ss << a << ')';
-    }
-
-    return ss.str();
-
-  }
-
-  std::string Number::to_string(bool compressed, int precision) const
-  {
-
-    std::string res;
-
-    // check if the fractional part of the value equals to zero
-    // neat trick from http://stackoverflow.com/a/1521682/1550314
-    // double int_part; bool is_int = modf(value, &int_part) == 0.0;
-
-    // this all cannot be done with one run only, since fixed
-    // output differs from normal output and regular output
-    // can contain scientific notation which we do not want!
-
-    // first sample
-    std::stringstream ss;
-    ss.precision(12);
-    ss << value_;
-
-    // check if we got scientific notation in result
-    if (ss.str().find_first_of("e") != std::string::npos) {
-      ss.clear(); ss.str(std::string());
-      ss.precision(std::max(12, precision));
-      ss << std::fixed << value_;
-    }
-
-    std::string tmp = ss.str();
-    size_t pos_point = tmp.find_first_of(".,");
-    size_t pos_fract = tmp.find_last_not_of("0");
-    bool is_int = pos_point == pos_fract ||
-                  pos_point == std::string::npos;
-
-    // reset stream for another run
-    ss.clear(); ss.str(std::string());
-
-    // take a shortcut for integers
-    if (is_int)
-    {
-      ss.precision(0);
-      ss << std::fixed << value_;
-      res = std::string(ss.str());
-    }
-    // process floats
-    else
-    {
-      // do we have have too much precision?
-      if (pos_fract < precision + pos_point)
-      { precision = (int)(pos_fract - pos_point); }
-      // round value again
-      ss.precision(precision);
-      ss << std::fixed << value_;
-      res = std::string(ss.str());
-      // maybe we truncated up to decimal point
-      size_t pos = res.find_last_not_of("0");
-      bool at_dec_point = res[pos] == '.' ||
-                          res[pos] == ',';
-      // don't leave a blank point
-      if (at_dec_point) ++ pos;
-      res.resize (pos + 1);
-    }
-
-    // some final cosmetics
-    if (res == "-0.0") res.erase(0, 1);
-    else if (res == "-0") res.erase(0, 1);
-    else if (res == "") res = "0";
-
-    // add unit now
-    res += unit();
-
-    // and return
-    return res;
-
-  }
-
-  std::string String_Quoted::to_string(bool compressed, int precision) const
-  {
-    return quote_mark_ ? quote(value_, quote_mark_, true) : value_;
-  }
-
-  std::string String_Constant::to_string(bool compressed, int precision) const
-  {
-    return quote_mark_ ? quote(value_, quote_mark_, true) : value_;
-  }
-
-  std::string Custom_Error::to_string(bool compressed, int precision) const
-  {
-    return message();
-  }
-  std::string Custom_Warning::to_string(bool compressed, int precision) const
-  {
-    return message();
-  }
-
-  std::string Selector_List::to_string(bool compressed, int precision) const
-  {
-    std::string str("");
-    auto end = this->end();
-    auto start = this->begin();
-    while (start < end && *start) {
-      Complex_Selector* sel = *start;
-      if (!str.empty()) str += ", ";
-      str += sel->to_string(compressed, precision);
-      ++ start;
-    }
-    return str;
-  }
-
-  std::string Compound_Selector::to_string(bool compressed, int precision) const
-  {
-    std::string str("");
-    auto end = this->end();
-    auto start = this->begin();
-    while (start < end && *start) {
-      Simple_Selector* sel = *start;
-      str += sel->to_string(compressed, precision);
-      ++ start;
-    }
-    return str;
-  }
-
-  std::string Complex_Selector::to_string(bool compressed, int precision) const
-  {
-    // first render head and tail if they are available
-    std::string str_head(head() ? head()->to_string(compressed, precision) : "");
-    std::string str_tail(tail() ? tail()->to_string(compressed, precision) : "");
-    std::string str_ref(reference() ? reference()->to_string(compressed, precision) : "");
-    // combinator in between
-    std::string str_op("");
-    // use a switch statement
-    switch (combinator()) {
-      case ANCESTOR_OF: str_op = " "; break;
-      case PARENT_OF:   str_op = ">"; break;
-      case PRECEDES:    str_op = "~"; break;
-      case ADJACENT_TO: str_op = "+"; break;
-      case REFERENCE:   str_op = "/" + str_ref + "/"; break;
-    }
-    // prettify for non ancestors
-    if (combinator() != ANCESTOR_OF) {
-      // no spaces needed for compressed
-      if (compressed == false) {
-        // make sure we add some spaces where needed
-        if (str_tail != "") str_op += " ";
-        if (str_head != "") str_head += " ";
-      }
-    }
-    // is ancestor with no tail
-    else if (str_tail == "") {
-      str_op = ""; // superflous
-    }
-    // now build the final result
-    return str_head + str_op + str_tail;
-  }
-
-  std::string Selector_Schema::to_string(bool compressed, int precision) const
-  {
-    return contents()->to_string(compressed, precision);
-  }
-
-  std::string Parent_Selector::to_string(bool compressed, int precision) const
-  {
-    return "&";
-  }
-
-  std::string Attribute_Selector::to_string(bool compressed, int precision) const
-  {
-    std::string val(value() ? value()->to_string(compressed, precision) : "");
-    return "[" + this->ns_name() + this->matcher() + val + "]";
-  }
-
-  std::string Wrapped_Selector::to_string(bool compressed, int precision) const
-  {
-    // first render the
-    std::string main(this->Simple_Selector::to_string(compressed, precision));
-    std::string wrapped(selector() ? selector()->to_string(compressed, precision) : "");
-    // now build the final result
-    return main + "(" + wrapped + ")";
-  }
-
-  //////////////////////////////////////////////////////////////////////////////////////////
-  // Additional method on Lists to retrieve values directly or from an encompassed Argument.
-  //////////////////////////////////////////////////////////////////////////////////////////
-  Expression* List::value_at_index(size_t i) {
-    if (is_arglist_) {
-      if (Argument* arg = dynamic_cast<Argument*>((*this)[i])) {
-        return arg->value();
-      } else {
-        return (*this)[i];
-      }
-    } else {
-      return (*this)[i];
-    }
-  }
-
-}
-
+#include "sass.hpp"
+#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);
+
+}
diff --git a/libsass/src/ast.hpp b/libsass/src/ast.hpp
--- a/libsass/src/ast.hpp
+++ b/libsass/src/ast.hpp
@@ -9,2332 +9,3076 @@
 #include <iostream>
 #include <typeinfo>
 #include <algorithm>
-#include <unordered_map>
-#include "sass/base.h"
-
-#ifdef __clang__
-
-/*
- * There are some overloads used here that trigger the clang overload
- * hiding warning. Specifically:
- *
- * Type type() which hides string type() from Expression
- *
- * and
- *
- * Block* block() which hides virtual Block* block() from Statement
- *
- */
-
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Woverloaded-virtual"
-
-#endif
-
-#include "util.hpp"
-#include "units.hpp"
-#include "context.hpp"
-#include "position.hpp"
-#include "constants.hpp"
-#include "operation.hpp"
-#include "position.hpp"
-#include "inspect.hpp"
-#include "source_map.hpp"
-#include "environment.hpp"
-#include "error_handling.hpp"
-#include "ast_def_macros.hpp"
-#include "ast_fwd_decl.hpp"
-#include "to_string.hpp"
-#include "source_map.hpp"
-
-#include "sass.h"
-
-namespace Sass {
-
-  const double NUMBER_EPSILON = 0.00000000000001;
-
-  // from boost (functional/hash):
-  // http://www.boost.org/doc/libs/1_35_0/doc/html/hash/combine.html
-  // Boost Software License - Version 1.0
-  // http://www.boost.org/users/license.html
-  template <typename T>
-  void hash_combine (std::size_t& seed, const T& val)
-  {
-    seed ^= std::hash<T>()(val) + 0x9e3779b9
-             + (seed<<6) + (seed>>2);
-  }
-
-  //////////////////////////////////////////////////////////
-  // Abstract base class for all abstract syntax tree nodes.
-  //////////////////////////////////////////////////////////
-  class AST_Node : public Memory_Object {
-    ADD_PROPERTY(ParserState, pstate)
-  public:
-    AST_Node(ParserState pstate)
-    : pstate_(pstate)
-    { }
-    virtual ~AST_Node() = 0;
-    // virtual Block* block() { return 0; }
-  public:
-    void update_pstate(const ParserState& pstate);
-  public:
-    Offset off() { return pstate(); }
-    Position pos() { return pstate(); }
-    ATTACH_OPERATIONS()
-  };
-  inline AST_Node::~AST_Node() { }
-
-
-  //////////////////////////////////////////////////////////////////////
-  // Abstract base class for expressions. This side of the AST hierarchy
-  // represents elements in value contexts, which exist primarily to be
-  // evaluated and returned.
-  //////////////////////////////////////////////////////////////////////
-  class Expression : public AST_Node {
-  public:
-    enum Concrete_Type {
-      NONE,
-      BOOLEAN,
-      NUMBER,
-      COLOR,
-      STRING,
-      LIST,
-      MAP,
-      SELECTOR,
-      NULL_VAL,
-      C_WARNING,
-      C_ERROR,
-      NUM_TYPES
-    };
-  private:
-    // expressions in some contexts shouldn't be evaluated
-    ADD_PROPERTY(bool, is_delayed)
-    ADD_PROPERTY(bool, is_expanded)
-    ADD_PROPERTY(bool, is_interpolant)
-    ADD_PROPERTY(Concrete_Type, concrete_type)
-  public:
-    Expression(ParserState pstate,
-               bool d = false, bool e = false, bool i = false, Concrete_Type ct = NONE)
-    : AST_Node(pstate),
-      is_delayed_(d),
-      is_expanded_(d),
-      is_interpolant_(i),
-      concrete_type_(ct)
-    { }
-    virtual operator bool() { return true; }
-    virtual ~Expression() { }
-    virtual std::string type() { return ""; /* TODO: raise an error? */ }
-    virtual bool is_invisible() const { return false; }
-    static std::string type_name() { return ""; }
-    virtual bool is_false() { return false; }
-    virtual bool operator== (const Expression& rhs) const { return false; }
-    virtual void set_delayed(bool delayed) { is_delayed(delayed); }
-    virtual size_t hash() { return 0; }
-  };
-
-  //////////////////////////////////////////////////////////////////////
-  // base class for values that support operations
-  //////////////////////////////////////////////////////////////////////
-  class Value : public Expression {
-  public:
-    Value(ParserState pstate,
-          bool d = false, bool e = false, bool i = false, Concrete_Type ct = NONE)
-    : Expression(pstate, d, e, i, ct)
-    { }
-    virtual bool operator== (const Expression& rhs) const = 0;
-    virtual std::string to_string(bool compressed = false, int precision = 5) const = 0;
-  };
-}
-
-/////////////////////////////////////////////////////////////////////////////////////
-// Hash method specializations for std::unordered_map to work with Sass::Expression
-/////////////////////////////////////////////////////////////////////////////////////
-
-namespace std {
-  template<>
-  struct hash<Sass::Expression*>
-  {
-    size_t operator()(Sass::Expression* s) const
-    {
-      return s->hash();
-    }
-  };
-  template<>
-  struct equal_to<Sass::Expression*>
-  {
-    bool operator()( Sass::Expression* lhs,  Sass::Expression* rhs) const
-    {
-      return lhs->hash() == rhs->hash();
-    }
-  };
-}
-
-namespace Sass {
-
-  /////////////////////////////////////////////////////////////////////////////
-  // Mixin class for AST nodes that should behave like vectors. Uses the
-  // "Template Method" design pattern to allow subclasses to adjust their flags
-  // when certain objects are pushed.
-  /////////////////////////////////////////////////////////////////////////////
-  template <typename T>
-  class Vectorized {
-    std::vector<T> elements_;
-  protected:
-    size_t hash_;
-    void reset_hash() { hash_ = 0; }
-    virtual void adjust_after_pushing(T element) { }
-  public:
-    Vectorized(size_t s = 0) : elements_(std::vector<T>())
-    { elements_.reserve(s); }
-    virtual ~Vectorized() = 0;
-    size_t length() const   { return elements_.size(); }
-    bool empty() const      { return elements_.empty(); }
-    T last()                { return elements_.back(); }
-    T first()               { return elements_.front(); }
-    T& operator[](size_t i) { return elements_[i]; }
-    virtual const T& at(size_t i) const { return elements_.at(i); }
-    const T& operator[](size_t i) const { return elements_[i]; }
-    Vectorized& operator<<(T element)
-    {
-      if (!element) return *this;
-      reset_hash();
-      elements_.push_back(element);
-      adjust_after_pushing(element);
-      return *this;
-    }
-    Vectorized& operator+=(Vectorized* v)
-    {
-      for (size_t i = 0, L = v->length(); i < L; ++i) *this << (*v)[i];
-      return *this;
-    }
-    Vectorized& unshift(T element)
-    {
-      elements_.insert(elements_.begin(), element);
-      return *this;
-    }
-    std::vector<T>& elements() { return elements_; }
-    const std::vector<T>& elements() const { return elements_; }
-    std::vector<T>& elements(std::vector<T>& e) { elements_ = e; return elements_; }
-
-    typename std::vector<T>::iterator end() { return elements_.end(); }
-    typename std::vector<T>::iterator begin() { return elements_.begin(); }
-    typename std::vector<T>::const_iterator end() const { return elements_.end(); }
-    typename std::vector<T>::const_iterator begin() const { return elements_.begin(); }
-    typename std::vector<T>::iterator erase(typename std::vector<T>::iterator el) { return elements_.erase(el); }
-    typename std::vector<T>::const_iterator erase(typename std::vector<T>::const_iterator el) { return elements_.erase(el); }
-
-  };
-  template <typename T>
-  inline Vectorized<T>::~Vectorized() { }
-
-  /////////////////////////////////////////////////////////////////////////////
-  // Mixin class for AST nodes that should behave like a hash table. Uses an
-  // extra <std::vector> internally to maintain insertion order for interation.
-  /////////////////////////////////////////////////////////////////////////////
-  class Hashed {
-  private:
-    std::unordered_map<Expression*, Expression*> elements_;
-    std::vector<Expression*> list_;
-  protected:
-    size_t hash_;
-    Expression* duplicate_key_;
-    void reset_hash() { hash_ = 0; }
-    void reset_duplicate_key() { duplicate_key_ = 0; }
-    virtual void adjust_after_pushing(std::pair<Expression*, Expression*> p) { }
-  public:
-    Hashed(size_t s = 0) : elements_(std::unordered_map<Expression*, Expression*>(s)), list_(std::vector<Expression*>())
-    { elements_.reserve(s); list_.reserve(s); reset_duplicate_key(); }
-    virtual ~Hashed();
-    size_t length() const                  { return list_.size(); }
-    bool empty() const                     { return list_.empty(); }
-    bool has(Expression* k) const          { return elements_.count(k) == 1; }
-    Expression* at(Expression* k) const;
-    bool has_duplicate_key() const         { return duplicate_key_ != 0; }
-    Expression* get_duplicate_key() const  { return duplicate_key_; }
-    const std::unordered_map<Expression*, Expression*> elements() { return elements_; }
-    Hashed& operator<<(std::pair<Expression*, Expression*> p)
-    {
-      reset_hash();
-
-      if (!has(p.first)) list_.push_back(p.first);
-      else if (!duplicate_key_) duplicate_key_ = p.first;
-
-      elements_[p.first] = p.second;
-
-      adjust_after_pushing(p);
-      return *this;
-    }
-    Hashed& operator+=(Hashed* h)
-    {
-      if (length() == 0) {
-        this->elements_ = h->elements_;
-        this->list_ = h->list_;
-        return *this;
-      }
-
-      for (auto key : h->keys()) {
-        *this << std::make_pair(key, h->at(key));
-      }
-
-      reset_duplicate_key();
-      return *this;
-    }
-    const std::unordered_map<Expression*, Expression*>& pairs() const { return elements_; }
-    const std::vector<Expression*>& keys() const { return list_; }
-
-    std::unordered_map<Expression*, Expression*>::iterator end() { return elements_.end(); }
-    std::unordered_map<Expression*, Expression*>::iterator begin() { return elements_.begin(); }
-    std::unordered_map<Expression*, Expression*>::const_iterator end() const { return elements_.end(); }
-    std::unordered_map<Expression*, Expression*>::const_iterator begin() const { return elements_.begin(); }
-
-  };
-  inline Hashed::~Hashed() { }
-
-
-  /////////////////////////////////////////////////////////////////////////
-  // Abstract base class for statements. This side of the AST hierarchy
-  // represents elements in expansion contexts, which exist primarily to be
-  // rewritten and macro-expanded.
-  /////////////////////////////////////////////////////////////////////////
-  class Statement : public AST_Node {
-  public:
-    enum Statement_Type {
-      NONE,
-      RULESET,
-      MEDIA,
-      DIRECTIVE,
-      SUPPORTS,
-      ATROOT,
-      BUBBLE,
-      CONTENT,
-      KEYFRAMERULE,
-      DECLARATION,
-      ASSIGNMENT,
-      IMPORT_STUB,
-      IMPORT,
-      COMMENT,
-      WARNING,
-      RETURN,
-      EXTEND,
-      ERROR,
-      DEBUGSTMT,
-      WHILE,
-      EACH,
-      FOR,
-      IF
-    };
-  private:
-    ADD_PROPERTY(Block*, block)
-    ADD_PROPERTY(Statement_Type, statement_type)
-    ADD_PROPERTY(size_t, tabs)
-    ADD_PROPERTY(bool, group_end)
-  public:
-    Statement(ParserState pstate, Statement_Type st = NONE, size_t t = 0)
-    : AST_Node(pstate), statement_type_(st), tabs_(t), group_end_(false)
-     { }
-    virtual ~Statement() = 0;
-    // needed for rearranging nested rulesets during CSS emission
-    virtual bool   is_hoistable() { return false; }
-    virtual bool   is_invisible() const { return false; }
-    virtual bool   bubbles() { return false; }
-    virtual Block* block()  { return 0; }
-    virtual bool has_content()
-    {
-      return statement_type_ == CONTENT;
-    }
-  };
-  inline Statement::~Statement() { }
-
-  ////////////////////////
-  // Blocks of statements.
-  ////////////////////////
-  class Block : public Statement, public Vectorized<Statement*> {
-    ADD_PROPERTY(bool, is_root)
-    ADD_PROPERTY(bool, is_at_root);
-    // needed for properly formatted CSS emission
-    ADD_PROPERTY(bool, has_hoistable)
-    ADD_PROPERTY(bool, has_non_hoistable)
-  protected:
-    void adjust_after_pushing(Statement* s)
-    {
-      if (s->is_hoistable()) has_hoistable_     = true;
-      else                   has_non_hoistable_ = true;
-    }
-  public:
-    Block(ParserState pstate, size_t s = 0, bool r = false)
-    : Statement(pstate),
-      Vectorized<Statement*>(s),
-      is_root_(r),
-      is_at_root_(false),
-      has_hoistable_(false),
-      has_non_hoistable_(false)
-    { }
-    virtual bool has_content()
-    {
-      for (size_t i = 0, L = elements().size(); i < L; ++i) {
-        if (elements()[i]->has_content()) return true;
-      }
-      return Statement::has_content();
-    }
-    Block* block() { return this; }
-    ATTACH_OPERATIONS()
-  };
-
-  ////////////////////////////////////////////////////////////////////////
-  // Abstract base class for statements that contain blocks of statements.
-  ////////////////////////////////////////////////////////////////////////
-  class Has_Block : public Statement {
-    ADD_PROPERTY(Block*, block)
-  public:
-    Has_Block(ParserState pstate, Block* b)
-    : Statement(pstate), block_(b)
-    { }
-    virtual bool has_content()
-    {
-      return (block_ && block_->has_content()) || Statement::has_content();
-    }
-    virtual ~Has_Block() = 0;
-  };
-  inline Has_Block::~Has_Block() { }
-
-  /////////////////////////////////////////////////////////////////////////////
-  // Rulesets (i.e., sets of styles headed by a selector and containing a block
-  // of style declarations.
-  /////////////////////////////////////////////////////////////////////////////
-  class Ruleset : public Has_Block {
-    ADD_PROPERTY(Selector*, selector)
-    ADD_PROPERTY(bool, at_root);
-    ADD_PROPERTY(bool, is_root);
-  public:
-    Ruleset(ParserState pstate, Selector* s = 0, Block* b = 0)
-    : Has_Block(pstate, b), selector_(s), at_root_(false), is_root_(false)
-    { statement_type(RULESET); }
-    bool is_invisible() const;
-    // nested rulesets need to be hoisted out of their enclosing blocks
-    bool is_hoistable() { return true; }
-    ATTACH_OPERATIONS()
-  };
-
-  /////////////////////////////////////////////////////////
-  // Nested declaration sets (i.e., namespaced properties).
-  /////////////////////////////////////////////////////////
-  class Propset : public Has_Block {
-    ADD_PROPERTY(String*, property_fragment)
-  public:
-    Propset(ParserState pstate, String* pf, Block* b = 0)
-    : Has_Block(pstate, b), property_fragment_(pf)
-    { }
-    ATTACH_OPERATIONS()
-  };
-
-  /////////////////
-  // Bubble.
-  /////////////////
-  class Bubble : public Statement {
-    ADD_PROPERTY(Statement*, node)
-    ADD_PROPERTY(bool, group_end)
-  public:
-    Bubble(ParserState pstate, Statement* n, Statement* g = 0, size_t t = 0)
-    : Statement(pstate, Statement::BUBBLE, t), node_(n), group_end_(g == 0)
-    { }
-    bool bubbles() { return true; }
-    ATTACH_OPERATIONS()
-  };
-
-  /////////////////
-  // Media queries.
-  /////////////////
-  class Media_Block : public Has_Block {
-    ADD_PROPERTY(List*, media_queries)
-  public:
-    Media_Block(ParserState pstate, List* mqs, Block* b)
-    : Has_Block(pstate, b), media_queries_(mqs)
-    { statement_type(MEDIA); }
-    Media_Block(ParserState pstate, List* mqs, Block* b, Selector* s)
-    : Has_Block(pstate, b), media_queries_(mqs)
-    { statement_type(MEDIA); }
-    bool bubbles() { return true; }
-    bool is_hoistable() { return true; }
-    bool is_invisible() const;
-    ATTACH_OPERATIONS()
-  };
-
-  ///////////////////////////////////////////////////////////////////////
-  // At-rules -- arbitrary directives beginning with "@" that may have an
-  // optional statement block.
-  ///////////////////////////////////////////////////////////////////////
-  class At_Rule : public Has_Block {
-    ADD_PROPERTY(std::string, keyword)
-    ADD_PROPERTY(Selector*, selector)
-    ADD_PROPERTY(Expression*, value)
-  public:
-    At_Rule(ParserState pstate, std::string kwd, Selector* sel = 0, Block* b = 0, Expression* val = 0)
-    : Has_Block(pstate, b), keyword_(kwd), selector_(sel), value_(val) // set value manually if needed
-    { statement_type(DIRECTIVE); }
-    bool bubbles() { return is_keyframes() || is_media(); }
-    bool is_media() {
-      return keyword_.compare("@-webkit-media") == 0 ||
-             keyword_.compare("@-moz-media") == 0 ||
-             keyword_.compare("@-o-media") == 0 ||
-             keyword_.compare("@media") == 0;
-    }
-    bool is_keyframes() {
-      return keyword_.compare("@-webkit-keyframes") == 0 ||
-             keyword_.compare("@-moz-keyframes") == 0 ||
-             keyword_.compare("@-o-keyframes") == 0 ||
-             keyword_.compare("@keyframes") == 0;
-    }
-    ATTACH_OPERATIONS()
-  };
-
-  ///////////////////////////////////////////////////////////////////////
-  // Keyframe-rules -- the child blocks of "@keyframes" nodes.
-  ///////////////////////////////////////////////////////////////////////
-  class Keyframe_Rule : public Has_Block {
-    ADD_PROPERTY(Selector*, selector)
-  public:
-    Keyframe_Rule(ParserState pstate, Block* b)
-    : Has_Block(pstate, b), selector_(0)
-    { statement_type(KEYFRAMERULE); }
-    ATTACH_OPERATIONS()
-  };
-
-  ////////////////////////////////////////////////////////////////////////
-  // Declarations -- style rules consisting of a property name and values.
-  ////////////////////////////////////////////////////////////////////////
-  class Declaration : public Statement {
-    ADD_PROPERTY(String*, property)
-    ADD_PROPERTY(Expression*, value)
-    ADD_PROPERTY(bool, is_important)
-    ADD_PROPERTY(bool, is_indented)
-  public:
-    Declaration(ParserState pstate,
-                String* prop, Expression* val, bool i = false)
-    : Statement(pstate), property_(prop), value_(val), is_important_(i), is_indented_(false)
-    { statement_type(DECLARATION); }
-    ATTACH_OPERATIONS()
-  };
-
-  /////////////////////////////////////
-  // Assignments -- variable and value.
-  /////////////////////////////////////
-  class Assignment : public Statement {
-    ADD_PROPERTY(std::string, variable)
-    ADD_PROPERTY(Expression*, value)
-    ADD_PROPERTY(bool, is_default)
-    ADD_PROPERTY(bool, is_global)
-  public:
-    Assignment(ParserState pstate,
-               std::string var, Expression* val,
-               bool is_default = false,
-               bool is_global = false)
-    : Statement(pstate), variable_(var), value_(val), is_default_(is_default), is_global_(is_global)
-    { statement_type(ASSIGNMENT); }
-    ATTACH_OPERATIONS()
-  };
-
-  ////////////////////////////////////////////////////////////////////////////
-  // Import directives. CSS and Sass import lists can be intermingled, so it's
-  // necessary to store a list of each in an Import node.
-  ////////////////////////////////////////////////////////////////////////////
-  class Import : public Statement {
-    std::vector<Expression*> urls_;
-    std::vector<Include>     incs_;
-    ADD_PROPERTY(List*,      media_queries);
-  public:
-    Import(ParserState pstate)
-    : Statement(pstate),
-      urls_(std::vector<Expression*>()),
-      incs_(std::vector<Include>()),
-      media_queries_(0)
-    { statement_type(IMPORT); }
-    std::vector<Expression*>& urls() { return urls_; }
-    std::vector<Include>& incs() { return incs_; }
-    ATTACH_OPERATIONS()
-  };
-
-  // not yet resolved single import
-  // so far we only know requested name
-  class Import_Stub : public Statement {
-    Include resource_;
-  public:
-    std::string abs_path() { return resource_.abs_path; };
-    std::string imp_path() { return resource_.imp_path; };
-    Include resource() { return resource_; };
-
-    Import_Stub(ParserState pstate, Include res)
-    : Statement(pstate), resource_(res)
-    { statement_type(IMPORT_STUB); }
-    ATTACH_OPERATIONS()
-  };
-
-  //////////////////////////////
-  // The Sass `@warn` directive.
-  //////////////////////////////
-  class Warning : public Statement {
-    ADD_PROPERTY(Expression*, message)
-  public:
-    Warning(ParserState pstate, Expression* msg)
-    : Statement(pstate), message_(msg)
-    { statement_type(WARNING); }
-    ATTACH_OPERATIONS()
-  };
-
-  ///////////////////////////////
-  // The Sass `@error` directive.
-  ///////////////////////////////
-  class Error : public Statement {
-    ADD_PROPERTY(Expression*, message)
-  public:
-    Error(ParserState pstate, Expression* msg)
-    : Statement(pstate), message_(msg)
-    { statement_type(ERROR); }
-    ATTACH_OPERATIONS()
-  };
-
-  ///////////////////////////////
-  // The Sass `@debug` directive.
-  ///////////////////////////////
-  class Debug : public Statement {
-    ADD_PROPERTY(Expression*, value)
-  public:
-    Debug(ParserState pstate, Expression* val)
-    : Statement(pstate), value_(val)
-    { statement_type(DEBUGSTMT); }
-    ATTACH_OPERATIONS()
-  };
-
-  ///////////////////////////////////////////
-  // CSS comments. These may be interpolated.
-  ///////////////////////////////////////////
-  class Comment : public Statement {
-    ADD_PROPERTY(String*, text)
-    ADD_PROPERTY(bool, is_important)
-  public:
-    Comment(ParserState pstate, String* txt, bool is_important)
-    : Statement(pstate), text_(txt), is_important_(is_important)
-    { statement_type(COMMENT); }
-    virtual bool is_invisible() const
-    { return is_important() == false; }
-    ATTACH_OPERATIONS()
-  };
-
-  ////////////////////////////////////
-  // The Sass `@if` control directive.
-  ////////////////////////////////////
-  class If : public Has_Block {
-    ADD_PROPERTY(Expression*, predicate)
-    ADD_PROPERTY(Block*, alternative)
-  public:
-    If(ParserState pstate, Expression* pred, Block* con, Block* alt = 0)
-    : Has_Block(pstate, con), predicate_(pred), alternative_(alt)
-    { statement_type(IF); }
-    virtual bool has_content()
-    {
-      return Has_Block::has_content() || (alternative_ && alternative_->has_content());
-    }
-    ATTACH_OPERATIONS()
-  };
-
-  /////////////////////////////////////
-  // The Sass `@for` control directive.
-  /////////////////////////////////////
-  class For : public Has_Block {
-    ADD_PROPERTY(std::string, variable)
-    ADD_PROPERTY(Expression*, lower_bound)
-    ADD_PROPERTY(Expression*, upper_bound)
-    ADD_PROPERTY(bool, is_inclusive)
-  public:
-    For(ParserState pstate,
-        std::string var, Expression* lo, Expression* hi, Block* b, bool inc)
-    : Has_Block(pstate, b),
-      variable_(var), lower_bound_(lo), upper_bound_(hi), is_inclusive_(inc)
-    { statement_type(FOR); }
-    ATTACH_OPERATIONS()
-  };
-
-  //////////////////////////////////////
-  // The Sass `@each` control directive.
-  //////////////////////////////////////
-  class Each : public Has_Block {
-    ADD_PROPERTY(std::vector<std::string>, variables)
-    ADD_PROPERTY(Expression*, list)
-  public:
-    Each(ParserState pstate, std::vector<std::string> vars, Expression* lst, Block* b)
-    : Has_Block(pstate, b), variables_(vars), list_(lst)
-    { statement_type(EACH); }
-    ATTACH_OPERATIONS()
-  };
-
-  ///////////////////////////////////////
-  // The Sass `@while` control directive.
-  ///////////////////////////////////////
-  class While : public Has_Block {
-    ADD_PROPERTY(Expression*, predicate)
-  public:
-    While(ParserState pstate, Expression* pred, Block* b)
-    : Has_Block(pstate, b), predicate_(pred)
-    { statement_type(WHILE); }
-    ATTACH_OPERATIONS()
-  };
-
-  /////////////////////////////////////////////////////////////
-  // The @return directive for use inside SassScript functions.
-  /////////////////////////////////////////////////////////////
-  class Return : public Statement {
-    ADD_PROPERTY(Expression*, value)
-  public:
-    Return(ParserState pstate, Expression* val)
-    : Statement(pstate), value_(val)
-    { statement_type(RETURN); }
-    ATTACH_OPERATIONS()
-  };
-
-  ////////////////////////////////
-  // The Sass `@extend` directive.
-  ////////////////////////////////
-  class Extension : public Statement {
-    ADD_PROPERTY(Selector*, selector)
-  public:
-    Extension(ParserState pstate, Selector* s)
-    : Statement(pstate), selector_(s)
-    { statement_type(EXTEND); }
-    ATTACH_OPERATIONS()
-  };
-
-  /////////////////////////////////////////////////////////////////////////////
-  // Definitions for both mixins and functions. The two cases are distinguished
-  // by a type tag.
-  /////////////////////////////////////////////////////////////////////////////
-  struct Backtrace;
-  typedef Environment<AST_Node*> Env;
-  typedef const char* Signature;
-  typedef Expression* (*Native_Function)(Env&, Env&, Context&, Signature, ParserState, Backtrace*);
-  typedef const char* Signature;
-  class Definition : public Has_Block {
-  public:
-    enum Type { MIXIN, FUNCTION };
-    ADD_PROPERTY(std::string, name)
-    ADD_PROPERTY(Parameters*, parameters)
-    ADD_PROPERTY(Env*, environment)
-    ADD_PROPERTY(Type, type)
-    ADD_PROPERTY(Native_Function, native_function)
-    ADD_PROPERTY(Sass_Function_Entry, c_function)
-    ADD_PROPERTY(void*, cookie)
-    ADD_PROPERTY(bool, is_overload_stub)
-    ADD_PROPERTY(Signature, signature)
-  public:
-    Definition(ParserState pstate,
-               std::string n,
-               Parameters* params,
-               Block* b,
-               Type t)
-    : Has_Block(pstate, b),
-      name_(n),
-      parameters_(params),
-      environment_(0),
-      type_(t),
-      native_function_(0),
-      c_function_(0),
-      cookie_(0),
-      is_overload_stub_(false),
-      signature_(0)
-    { }
-    Definition(ParserState pstate,
-               Signature sig,
-               std::string n,
-               Parameters* params,
-               Native_Function func_ptr,
-               bool overload_stub = false)
-    : Has_Block(pstate, 0),
-      name_(n),
-      parameters_(params),
-      environment_(0),
-      type_(FUNCTION),
-      native_function_(func_ptr),
-      c_function_(0),
-      cookie_(0),
-      is_overload_stub_(overload_stub),
-      signature_(sig)
-    { }
-    Definition(ParserState pstate,
-               Signature sig,
-               std::string n,
-               Parameters* params,
-               Sass_Function_Entry c_func,
-               bool whatever,
-               bool whatever2)
-    : Has_Block(pstate, 0),
-      name_(n),
-      parameters_(params),
-      environment_(0),
-      type_(FUNCTION),
-      native_function_(0),
-      c_function_(c_func),
-      cookie_(sass_function_get_cookie(c_func)),
-      is_overload_stub_(false),
-      signature_(sig)
-    { }
-    ATTACH_OPERATIONS()
-  };
-
-  //////////////////////////////////////
-  // Mixin calls (i.e., `@include ...`).
-  //////////////////////////////////////
-  class Mixin_Call : public Has_Block {
-    ADD_PROPERTY(std::string, name)
-    ADD_PROPERTY(Arguments*, arguments)
-  public:
-    Mixin_Call(ParserState pstate, std::string n, Arguments* args, Block* b = 0)
-    : Has_Block(pstate, b), name_(n), arguments_(args)
-    { }
-    ATTACH_OPERATIONS()
-  };
-
-  ///////////////////////////////////////////////////
-  // The @content directive for mixin content blocks.
-  ///////////////////////////////////////////////////
-  class Content : public Statement {
-  public:
-    Content(ParserState pstate) : Statement(pstate)
-    { statement_type(CONTENT); }
-    ATTACH_OPERATIONS()
-  };
-
-  ///////////////////////////////////////////////////////////////////////
-  // Lists of values, both comma- and space-separated (distinguished by a
-  // type-tag.) Also used to represent variable-length argument lists.
-  ///////////////////////////////////////////////////////////////////////
-  class List : public Value, public Vectorized<Expression*> {
-    void adjust_after_pushing(Expression* e) { is_expanded(false); }
-  private:
-    ADD_PROPERTY(enum Sass_Separator, separator)
-    ADD_PROPERTY(bool, is_arglist)
-  public:
-    List(ParserState pstate,
-         size_t size = 0, enum Sass_Separator sep = SASS_SPACE, bool argl = false)
-    : Value(pstate),
-      Vectorized<Expression*>(size),
-      separator_(sep), is_arglist_(argl)
-    { concrete_type(LIST); }
-    std::string type() { return is_arglist_ ? "arglist" : "list"; }
-    static std::string type_name() { return "list"; }
-    const char* sep_string(bool compressed = false) const {
-      return separator() == SASS_COMMA ?
-        (compressed ? "," : ", ") : " ";
-    }
-    bool is_invisible() const { return empty(); }
-    Expression* value_at_index(size_t i);
-
-    virtual size_t size() const;
-
-    virtual size_t hash()
-    {
-      if (hash_ == 0) {
-        hash_ = std::hash<std::string>()(sep_string());
-        for (size_t i = 0, L = length(); i < L; ++i)
-          hash_combine(hash_, (elements()[i])->hash());
-      }
-      return hash_;
-    }
-
-    virtual void set_delayed(bool delayed)
-    {
-      for (size_t i = 0, L = length(); i < L; ++i)
-        (elements()[i])->set_delayed(delayed);
-      is_delayed(delayed);
-    }
-
-    virtual bool operator== (const Expression& rhs) const;
-    virtual std::string to_string(bool compressed = false, int precision = 5) const;
-
-    ATTACH_OPERATIONS()
-  };
-
-  ///////////////////////////////////////////////////////////////////////
-  // Key value paris.
-  ///////////////////////////////////////////////////////////////////////
-  class Map : public Value, public Hashed {
-    void adjust_after_pushing(std::pair<Expression*, Expression*> p) { is_expanded(false); }
-  public:
-    Map(ParserState pstate,
-         size_t size = 0)
-    : Value(pstate),
-      Hashed(size)
-    { concrete_type(MAP); }
-    std::string type() { return "map"; }
-    static std::string type_name() { return "map"; }
-    bool is_invisible() const { return empty(); }
-
-    virtual size_t hash()
-    {
-      if (hash_ == 0) {
-        for (auto key : keys()) {
-          hash_combine(hash_, key->hash());
-          hash_combine(hash_, at(key)->hash());
-        }
-      }
-
-      return hash_;
-    }
-
-    virtual bool operator== (const Expression& rhs) const;
-    virtual std::string to_string(bool compressed = false, int precision = 5) const;
-
-    ATTACH_OPERATIONS()
-  };
-
-  //////////////////////////////////////////////////////////////////////////
-  // Binary expressions. Represents logical, relational, and arithmetic
-  // operations. Templatized to avoid large switch statements and repetitive
-  // subclassing.
-  //////////////////////////////////////////////////////////////////////////
-  class Binary_Expression : public Expression {
-  private:
-    ADD_HASHED(enum Sass_OP, type)
-    ADD_HASHED(Expression*, left)
-    ADD_HASHED(Expression*, right)
-    size_t hash_;
-  public:
-    Binary_Expression(ParserState pstate,
-                      enum Sass_OP t, Expression* lhs, Expression* rhs)
-    : Expression(pstate), type_(t), left_(lhs), right_(rhs), hash_(0)
-    { }
-    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;
-        case NUM_OPS: return "num_ops"; break;
-        default: return "invalid"; break;
-      }
-    }
-    virtual void set_delayed(bool delayed)
-    {
-      right()->set_delayed(delayed);
-      left()->set_delayed(delayed);
-      is_delayed(delayed);
-    }
-    virtual bool operator==(const Expression& rhs) const
-    {
-      try
-      {
-        const Binary_Expression* m = dynamic_cast<const Binary_Expression*>(&rhs);
-        if (m == 0) return false;
-        return type() == m->type() &&
-               left() == m->left() &&
-               right() == m->right();
-      }
-      catch (std::bad_cast&)
-      {
-        return false;
-      }
-      catch (...) { throw; }
-    }
-    virtual size_t hash()
-    {
-      if (hash_ == 0) {
-        hash_ = std::hash<size_t>()(type_);
-        hash_combine(hash_, left()->hash());
-        hash_combine(hash_, right()->hash());
-      }
-      return hash_;
-    }
-    ATTACH_OPERATIONS()
-  };
-
-  ////////////////////////////////////////////////////////////////////////////
-  // Arithmetic negation (logical negation is just an ordinary function call).
-  ////////////////////////////////////////////////////////////////////////////
-  class Unary_Expression : public Expression {
-  public:
-    enum Type { PLUS, MINUS, NOT };
-  private:
-    ADD_HASHED(Type, type)
-    ADD_HASHED(Expression*, operand)
-    size_t hash_;
-  public:
-    Unary_Expression(ParserState pstate, Type t, Expression* o)
-    : Expression(pstate), type_(t), operand_(o), hash_(0)
-    { }
-    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;
-      }
-    }
-    virtual bool operator==(const Expression& rhs) const
-    {
-      try
-      {
-        const Unary_Expression* m = dynamic_cast<const Unary_Expression*>(&rhs);
-        if (m == 0) return false;
-        return type() == m->type() &&
-               operand() == m->operand();
-      }
-      catch (std::bad_cast&)
-      {
-        return false;
-      }
-      catch (...) { throw; }
-    }
-    virtual size_t hash()
-    {
-      if (hash_ == 0) {
-        hash_ = std::hash<size_t>()(type_);
-        hash_combine(hash_, operand()->hash());
-      };
-      return hash_;
-    }
-    ATTACH_OPERATIONS()
-  };
-
-  ////////////////////////////////////////////////////////////
-  // Individual argument objects for mixin and function calls.
-  ////////////////////////////////////////////////////////////
-  class Argument : public Expression {
-    ADD_HASHED(Expression*, value)
-    ADD_HASHED(std::string, name)
-    ADD_PROPERTY(bool, is_rest_argument)
-    ADD_PROPERTY(bool, is_keyword_argument)
-    size_t hash_;
-  public:
-    Argument(ParserState pstate, Expression* val, std::string n = "", bool rest = false, bool keyword = false)
-    : 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);
-      }
-    }
-
-    virtual bool operator==(const Expression& rhs) const
-    {
-      try
-      {
-        const Argument* m = dynamic_cast<const Argument*>(&rhs);
-        if (!(m && name() == m->name())) return false;
-        return *value() == *m->value();
-      }
-      catch (std::bad_cast&)
-      {
-        return false;
-      }
-      catch (...) { throw; }
-    }
-
-    virtual size_t hash()
-    {
-      if (hash_ == 0) {
-        hash_ = std::hash<std::string>()(name());
-        hash_combine(hash_, value()->hash());
-      }
-      return hash_;
-    }
-
-    ATTACH_OPERATIONS()
-  };
-
-  ////////////////////////////////////////////////////////////////////////
-  // Argument lists -- in their own class to facilitate context-sensitive
-  // error checking (e.g., ensuring that all ordinal arguments precede all
-  // named arguments).
-  ////////////////////////////////////////////////////////////////////////
-  class Arguments : public Expression, public Vectorized<Argument*> {
-    ADD_PROPERTY(bool, has_named_arguments)
-    ADD_PROPERTY(bool, has_rest_argument)
-    ADD_PROPERTY(bool, has_keyword_argument)
-  protected:
-    void adjust_after_pushing(Argument* a);
-  public:
-    Arguments(ParserState pstate)
-    : Expression(pstate),
-      Vectorized<Argument*>(),
-      has_named_arguments_(false),
-      has_rest_argument_(false),
-      has_keyword_argument_(false)
-    { }
-    ATTACH_OPERATIONS()
-  };
-
-  //////////////////
-  // Function calls.
-  //////////////////
-  class Function_Call : public Expression {
-    ADD_HASHED(std::string, name)
-    ADD_HASHED(Arguments*, arguments)
-    ADD_PROPERTY(void*, cookie)
-    size_t hash_;
-  public:
-    Function_Call(ParserState pstate, std::string n, Arguments* args, void* cookie)
-    : Expression(pstate), name_(n), arguments_(args), cookie_(cookie), hash_(0)
-    { concrete_type(STRING); }
-    Function_Call(ParserState pstate, std::string n, Arguments* args)
-    : Expression(pstate), name_(n), arguments_(args), cookie_(0), hash_(0)
-    { concrete_type(STRING); }
-
-    virtual bool operator==(const Expression& rhs) const
-    {
-      try
-      {
-        const Function_Call* m = dynamic_cast<const 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;
-        return true;
-      }
-      catch (std::bad_cast&)
-      {
-        return false;
-      }
-      catch (...) { throw; }
-    }
-
-    virtual size_t hash()
-    {
-      if (hash_ == 0) {
-        hash_ = std::hash<std::string>()(name());
-        for (auto argument : arguments()->elements())
-          hash_combine(hash_, argument->hash());
-      }
-      return hash_;
-    }
-
-    ATTACH_OPERATIONS()
-  };
-
-  /////////////////////////
-  // Function call schemas.
-  /////////////////////////
-  class Function_Call_Schema : public Expression {
-    ADD_PROPERTY(String*, name)
-    ADD_PROPERTY(Arguments*, arguments)
-  public:
-    Function_Call_Schema(ParserState pstate, String* n, Arguments* args)
-    : Expression(pstate), name_(n), arguments_(args)
-    { concrete_type(STRING); }
-    ATTACH_OPERATIONS()
-  };
-
-  ///////////////////////
-  // Variable references.
-  ///////////////////////
-  class Variable : public Expression {
-    ADD_PROPERTY(std::string, name)
-  public:
-    Variable(ParserState pstate, std::string n)
-    : Expression(pstate), name_(n)
-    { }
-
-    virtual bool operator==(const Expression& rhs) const
-    {
-      try
-      {
-        const Variable* e = dynamic_cast<const Variable*>(&rhs);
-        return e && name() == e->name();
-      }
-      catch (std::bad_cast&)
-      {
-        return false;
-      }
-      catch (...) { throw; }
-    }
-
-    virtual size_t hash()
-    {
-      return std::hash<std::string>()(name());
-    }
-
-    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, true), type_(t), value_(val),
-      hash_(0)
-    { }
-
-    virtual bool operator==(const Expression& rhs) const
-    {
-      try
-      {
-        const Textual* e = dynamic_cast<const Textual*>(&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_OPERATIONS()
-  };
-
-  ////////////////////////////////////////////////
-  // Numbers, percentages, dimensions, and colors.
-  ////////////////////////////////////////////////
-  class Number : public Value {
-    ADD_HASHED(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);
-    bool            zero()              { return zero_; }
-    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"; }
-    static std::string type_name() { return "number"; }
-    std::string unit() const;
-
-    bool is_unitless();
-    void 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;
-
-    virtual size_t hash()
-    {
-      if (hash_ == 0) {
-        hash_ = std::hash<double>()(value_);
-        for (const auto numerator : numerator_units())
-          hash_combine(hash_, std::hash<std::string>()(numerator));
-        for (const auto denominator : denominator_units())
-          hash_combine(hash_, std::hash<std::string>()(denominator));
-      }
-      return hash_;
-    }
-
-    virtual bool operator< (const Number& rhs) const;
-    virtual bool operator== (const Expression& rhs) const;
-    virtual std::string to_string(bool compressed = false, int precision = 5) const;
-
-    ATTACH_OPERATIONS()
-  };
-
-  //////////
-  // Colors.
-  //////////
-  class Color : public Value {
-    ADD_HASHED(double, r)
-    ADD_HASHED(double, g)
-    ADD_HASHED(double, b)
-    ADD_HASHED(double, a)
-    ADD_PROPERTY(bool, sixtuplet)
-    ADD_PROPERTY(std::string, disp)
-    size_t hash_;
-  public:
-    Color(ParserState pstate, double r, double g, double b, double a = 1, bool sixtuplet = true, const std::string disp = "")
-    : Value(pstate), r_(r), g_(g), b_(b), a_(a), sixtuplet_(sixtuplet), disp_(disp),
-      hash_(0)
-    { concrete_type(COLOR); }
-    std::string type() { return "color"; }
-    static std::string type_name() { return "color"; }
-
-    virtual size_t hash()
-    {
-      if (hash_ == 0) {
-        hash_ = std::hash<double>()(a_);
-        hash_combine(hash_, std::hash<double>()(r_));
-        hash_combine(hash_, std::hash<double>()(g_));
-        hash_combine(hash_, std::hash<double>()(b_));
-      }
-      return hash_;
-    }
-
-    virtual bool operator== (const Expression& rhs) const;
-    virtual std::string to_string(bool compressed = false, int precision = 5) const;
-
-    ATTACH_OPERATIONS()
-  };
-
-  //////////////////////////////
-  // Errors from Sass_Values.
-  //////////////////////////////
-  class Custom_Error : public Value {
-    ADD_PROPERTY(std::string, message)
-  public:
-    Custom_Error(ParserState pstate, std::string msg)
-    : Value(pstate), message_(msg)
-    { concrete_type(C_ERROR); }
-    virtual bool operator== (const Expression& rhs) const;
-    virtual std::string to_string(bool compressed = false, int precision = 5) const;
-    ATTACH_OPERATIONS()
-  };
-
-  //////////////////////////////
-  // Warnings from Sass_Values.
-  //////////////////////////////
-  class Custom_Warning : public Value {
-    ADD_PROPERTY(std::string, message)
-  public:
-    Custom_Warning(ParserState pstate, std::string msg)
-    : Value(pstate), message_(msg)
-    { concrete_type(C_WARNING); }
-    virtual bool operator== (const Expression& rhs) const;
-    virtual std::string to_string(bool compressed = false, int precision = 5) const;
-    ATTACH_OPERATIONS()
-  };
-
-  ////////////
-  // Booleans.
-  ////////////
-  class Boolean : public Value {
-    ADD_HASHED(bool, value)
-    size_t hash_;
-  public:
-    Boolean(ParserState pstate, bool val)
-    : Value(pstate), value_(val),
-      hash_(0)
-    { concrete_type(BOOLEAN); }
-    virtual operator bool() { return value_; }
-    std::string type() { return "bool"; }
-    static std::string type_name() { return "bool"; }
-    virtual bool is_false() { return !value_; }
-
-    virtual size_t hash()
-    {
-      if (hash_ == 0) {
-        hash_ = std::hash<bool>()(value_);
-      }
-      return hash_;
-    }
-
-    virtual bool operator== (const Expression& rhs) const;
-    virtual std::string to_string(bool compressed = false, int precision = 5) const;
-
-    ATTACH_OPERATIONS()
-  };
-
-  ////////////////////////////////////////////////////////////////////////
-  // Abstract base class for Sass string values. Includes interpolated and
-  // "flat" strings.
-  ////////////////////////////////////////////////////////////////////////
-  class String : public Value {
-    ADD_PROPERTY(bool, sass_fix_1291)
-  public:
-    String(ParserState pstate, bool delayed = false, bool sass_fix_1291 = false)
-    : Value(pstate, delayed), sass_fix_1291_(sass_fix_1291)
-    { concrete_type(STRING); }
-    static std::string type_name() { return "string"; }
-    virtual ~String() = 0;
-    virtual bool operator==(const Expression& rhs) const = 0;
-    virtual std::string to_string(bool compressed = false, int precision = 5) const = 0;
-    ATTACH_OPERATIONS()
-  };
-  inline String::~String() { };
-
-  ///////////////////////////////////////////////////////////////////////
-  // Interpolated strings. Meant to be reduced to flat strings during the
-  // evaluation phase.
-  ///////////////////////////////////////////////////////////////////////
-  class String_Schema : public String, public Vectorized<Expression*> {
-    ADD_PROPERTY(bool, has_interpolants)
-    size_t hash_;
-  public:
-    String_Schema(ParserState pstate, size_t size = 0, bool has_interpolants = false)
-    : String(pstate), Vectorized<Expression*>(size), has_interpolants_(has_interpolants), hash_(0)
-    { concrete_type(STRING); }
-    std::string type() { return "string"; }
-    static std::string type_name() { return "string"; }
-
-    virtual size_t hash()
-    {
-      if (hash_ == 0) {
-        for (auto string : elements())
-          hash_combine(hash_, string->hash());
-      }
-      return hash_;
-    }
-
-    virtual bool operator==(const Expression& rhs) const;
-    virtual std::string to_string(bool compressed = false, int precision = 5) const;
-
-    ATTACH_OPERATIONS()
-  };
-
-  ////////////////////////////////////////////////////////
-  // Flat strings -- the lowest level of raw textual data.
-  ////////////////////////////////////////////////////////
-  class String_Constant : public String {
-    ADD_PROPERTY(char, quote_mark)
-    ADD_PROPERTY(bool, can_compress_whitespace)
-    ADD_HASHED(std::string, value)
-  protected:
-    size_t hash_;
-  public:
-    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, 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, 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 Token& tok)
-    : String(pstate), quote_mark_(0), can_compress_whitespace_(false), value_(read_css_string(std::string(tok.begin, tok.end))), hash_(0)
-    { }
-    std::string type() { return "string"; }
-    static std::string type_name() { return "string"; }
-
-    virtual size_t hash()
-    {
-      if (hash_ == 0) {
-        hash_ = std::hash<std::string>()(value_);
-      }
-      return hash_;
-    }
-
-    virtual bool operator==(const Expression& rhs) const;
-    virtual std::string to_string(bool compressed = false, int precision = 5) const;
-
-    // static char auto_quote() { return '*'; }
-    static char double_quote() { return '"'; }
-    static char single_quote() { return '\''; }
-
-    ATTACH_OPERATIONS()
-  };
-
-  ////////////////////////////////////////////////////////
-  // Possibly quoted string (unquote on instantiation)
-  ////////////////////////////////////////////////////////
-  class String_Quoted : public String_Constant {
-  public:
-    String_Quoted(ParserState pstate, std::string val, char q = 0, bool keep_utf8_escapes = false)
-    : String_Constant(pstate, val)
-    {
-      value_ = unquote(value_, &quote_mark_, keep_utf8_escapes);
-      if (q && quote_mark_) quote_mark_ = q;
-    }
-    virtual bool operator==(const Expression& rhs) const;
-    virtual std::string to_string(bool compressed = false, int precision = 5) const;
-    ATTACH_OPERATIONS()
-  };
-
-  /////////////////
-  // Media queries.
-  /////////////////
-  class Media_Query : public Expression,
-                      public Vectorized<Media_Query_Expression*> {
-    ADD_PROPERTY(String*, media_type)
-    ADD_PROPERTY(bool, is_negated)
-    ADD_PROPERTY(bool, is_restricted)
-  public:
-    Media_Query(ParserState pstate,
-                String* t = 0, size_t s = 0, bool n = false, bool r = false)
-    : Expression(pstate), Vectorized<Media_Query_Expression*>(s),
-      media_type_(t), is_negated_(n), is_restricted_(r)
-    { }
-    ATTACH_OPERATIONS()
-  };
-
-  ////////////////////////////////////////////////////
-  // Media expressions (for use inside media queries).
-  ////////////////////////////////////////////////////
-  class Media_Query_Expression : public Expression {
-    ADD_PROPERTY(Expression*, feature)
-    ADD_PROPERTY(Expression*, value)
-    ADD_PROPERTY(bool, is_interpolated)
-  public:
-    Media_Query_Expression(ParserState pstate,
-                           Expression* f, Expression* v, bool i = false)
-    : Expression(pstate), feature_(f), value_(v), is_interpolated_(i)
-    { }
-    ATTACH_OPERATIONS()
-  };
-
-  ////////////////////
-  // `@supports` rule.
-  ////////////////////
-  class Supports_Block : public Has_Block {
-    ADD_PROPERTY(Supports_Condition*, condition)
-  public:
-    Supports_Block(ParserState pstate, Supports_Condition* condition, Block* block = 0)
-    : Has_Block(pstate, block), condition_(condition)
-    { statement_type(SUPPORTS); }
-    bool is_hoistable() { return true; }
-    bool bubbles() { return true; }
-    ATTACH_OPERATIONS()
-  };
-
-  //////////////////////////////////////////////////////
-  // The abstract superclass of all Supports conditions.
-  //////////////////////////////////////////////////////
-  class Supports_Condition : public Expression {
-  public:
-    Supports_Condition(ParserState pstate)
-    : Expression(pstate)
-    { }
-    virtual bool needs_parens(Supports_Condition* cond) const { return false; }
-    ATTACH_OPERATIONS()
-  };
-
-  ////////////////////////////////////////////////////////////
-  // An operator condition (e.g. `CONDITION1 and CONDITION2`).
-  ////////////////////////////////////////////////////////////
-  class Supports_Operator : public Supports_Condition {
-  public:
-    enum Operand { AND, OR };
-  private:
-    ADD_PROPERTY(Supports_Condition*, left);
-    ADD_PROPERTY(Supports_Condition*, right);
-    ADD_PROPERTY(Operand, operand);
-  public:
-    Supports_Operator(ParserState pstate, Supports_Condition* l, Supports_Condition* r, Operand o)
-    : Supports_Condition(pstate), left_(l), right_(r), operand_(o)
-    { }
-    virtual bool needs_parens(Supports_Condition* cond) const;
-    ATTACH_OPERATIONS()
-  };
-
-  //////////////////////////////////////////
-  // A negation condition (`not CONDITION`).
-  //////////////////////////////////////////
-  class Supports_Negation : public Supports_Condition {
-  private:
-    ADD_PROPERTY(Supports_Condition*, condition);
-  public:
-    Supports_Negation(ParserState pstate, Supports_Condition* c)
-    : Supports_Condition(pstate), condition_(c)
-    { }
-    virtual bool needs_parens(Supports_Condition* cond) const;
-    ATTACH_OPERATIONS()
-  };
-
-  /////////////////////////////////////////////////////
-  // A declaration condition (e.g. `(feature: value)`).
-  /////////////////////////////////////////////////////
-  class Supports_Declaration : public Supports_Condition {
-  private:
-    ADD_PROPERTY(Expression*, feature);
-    ADD_PROPERTY(Expression*, value);
-  public:
-    Supports_Declaration(ParserState pstate, Expression* f, Expression* v)
-    : Supports_Condition(pstate), feature_(f), value_(v)
-    { }
-    virtual bool needs_parens(Supports_Condition* cond) const { return false; }
-    ATTACH_OPERATIONS()
-  };
-
-  ///////////////////////////////////////////////
-  // An interpolation condition (e.g. `#{$var}`).
-  ///////////////////////////////////////////////
-  class Supports_Interpolation : public Supports_Condition {
-  private:
-    ADD_PROPERTY(Expression*, value);
-  public:
-    Supports_Interpolation(ParserState pstate, Expression* v)
-    : Supports_Condition(pstate), value_(v)
-    { }
-    virtual bool needs_parens(Supports_Condition* cond) const { return false; }
-    ATTACH_OPERATIONS()
-  };
-
-  /////////////////////////////////////////////////
-  // At root expressions (for use inside @at-root).
-  /////////////////////////////////////////////////
-  class At_Root_Expression : public Expression {
-  private:
-    ADD_PROPERTY(String*, feature)
-    ADD_PROPERTY(Expression*, value)
-    ADD_PROPERTY(bool, is_interpolated)
-  public:
-    At_Root_Expression(ParserState pstate, String* f = 0, Expression* v = 0, bool i = false)
-    : Expression(pstate), feature_(f), value_(v), is_interpolated_(i)
-    { }
-    bool exclude(std::string str)
-    {
-      To_String to_string;
-      bool with = feature() && unquote(feature()->perform(&to_string)).compare("with") == 0;
-      List* l = static_cast<List*>(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]->perform(&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]->perform(&to_string));
-          if (v.compare("all") == 0 || v == str) return true;
-        }
-        return false;
-      }
-    }
-    ATTACH_OPERATIONS()
-  };
-
-  ///////////
-  // At-root.
-  ///////////
-  class At_Root_Block : public Has_Block {
-    ADD_PROPERTY(At_Root_Expression*, expression)
-  public:
-    At_Root_Block(ParserState pstate, Block* b = 0, At_Root_Expression* e = 0)
-    : Has_Block(pstate, b), expression_(e)
-    { statement_type(ATROOT); }
-    bool is_hoistable() { return true; }
-    bool bubbles() { return true; }
-    bool exclude_node(Statement* s) {
-      if (s->statement_type() == Statement::DIRECTIVE)
-      {
-        return expression()->exclude(static_cast<At_Rule*>(s)->keyword().erase(0, 1));
-      }
-      if (s->statement_type() == Statement::MEDIA)
-      {
-        return expression()->exclude("media");
-      }
-      if (s->statement_type() == Statement::RULESET)
-      {
-        return expression()->exclude("rule");
-      }
-      if (s->statement_type() == Statement::SUPPORTS)
-      {
-        return expression()->exclude("supports");
-      }
-      if (static_cast<At_Rule*>(s)->is_keyframes())
-      {
-        return expression()->exclude("keyframes");
-      }
-      return false;
-    }
-    ATTACH_OPERATIONS()
-  };
-
-  //////////////////
-  // The null value.
-  //////////////////
-  class Null : public Value {
-  public:
-    Null(ParserState pstate) : Value(pstate) { concrete_type(NULL_VAL); }
-    std::string type() { return "null"; }
-    static std::string type_name() { return "null"; }
-    bool is_invisible() const { return true; }
-    operator bool() { return false; }
-    bool is_false() { return true; }
-
-    virtual size_t hash()
-    {
-      return -1;
-    }
-
-    virtual bool operator== (const Expression& rhs) const;
-    virtual std::string to_string(bool compressed = false, int precision = 5) const;
-
-    ATTACH_OPERATIONS()
-  };
-
-  /////////////////////////////////
-  // Thunks for delayed evaluation.
-  /////////////////////////////////
-  class Thunk : public Expression {
-    ADD_PROPERTY(Expression*, expression)
-    ADD_PROPERTY(Env*, environment)
-  public:
-    Thunk(ParserState pstate, Expression* exp, Env* env = 0)
-    : Expression(pstate), expression_(exp), environment_(env)
-    { }
-  };
-
-  /////////////////////////////////////////////////////////
-  // Individual parameter objects for mixins and functions.
-  /////////////////////////////////////////////////////////
-  class Parameter : public AST_Node {
-    ADD_PROPERTY(std::string, name)
-    ADD_PROPERTY(Expression*, default_value)
-    ADD_PROPERTY(bool, is_rest_parameter)
-  public:
-    Parameter(ParserState pstate,
-              std::string n, Expression* 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);
-      }
-    }
-    ATTACH_OPERATIONS()
-  };
-
-  /////////////////////////////////////////////////////////////////////////
-  // Parameter lists -- in their own class to facilitate context-sensitive
-  // error checking (e.g., ensuring that all optional parameters follow all
-  // required parameters).
-  /////////////////////////////////////////////////////////////////////////
-  class Parameters : public AST_Node, public Vectorized<Parameter*> {
-    ADD_PROPERTY(bool, has_optional_parameters)
-    ADD_PROPERTY(bool, has_rest_parameter)
-  protected:
-    void adjust_after_pushing(Parameter* p)
-    {
-      if (p->default_value()) {
-        if (has_rest_parameter_) {
-          error("optional parameters may not be combined with variable-length parameters", p->pstate());
-        }
-        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());
-        }
-        has_rest_parameter_ = true;
-      }
-      else {
-        if (has_rest_parameter_) {
-          error("required parameters must precede variable-length parameters", p->pstate());
-        }
-        if (has_optional_parameters_) {
-          error("required parameters must precede optional parameters", p->pstate());
-        }
-      }
-    }
-  public:
-    Parameters(ParserState pstate)
-    : AST_Node(pstate),
-      Vectorized<Parameter*>(),
-      has_optional_parameters_(false),
-      has_rest_parameter_(false)
-    { }
-    ATTACH_OPERATIONS()
-  };
-
-  /////////////////////////////////////////
-  // Abstract base class for CSS selectors.
-  /////////////////////////////////////////
-  class Selector : public Expression {
-    ADD_PROPERTY(bool, has_reference)
-    ADD_PROPERTY(bool, has_placeholder)
-    // line break before list separator
-    ADD_PROPERTY(bool, has_line_feed)
-    // line break after list separator
-    ADD_PROPERTY(bool, has_line_break)
-    // maybe we have optional flag
-    ADD_PROPERTY(bool, is_optional)
-    // parent block pointers
-    ADD_PROPERTY(Media_Block*, media_block)
-  public:
-    Selector(ParserState pstate, bool r = false, bool h = false)
-    : Expression(pstate),
-      has_reference_(r),
-      has_placeholder_(h),
-      has_line_feed_(false),
-      has_line_break_(false),
-      is_optional_(false),
-      media_block_(0)
-    { concrete_type(SELECTOR); }
-    virtual ~Selector() = 0;
-    virtual unsigned long specificity() {
-      return Constants::Specificity_Universal;
-    }
-    virtual std::string to_string(bool compressed = false, int precision = 5) const = 0;
-  };
-  inline Selector::~Selector() { }
-
-  /////////////////////////////////////////////////////////////////////////
-  // Interpolated selectors -- the interpolated String will be expanded and
-  // re-parsed into a normal selector class.
-  /////////////////////////////////////////////////////////////////////////
-  class Selector_Schema : public Selector {
-    ADD_PROPERTY(String*, contents)
-    ADD_PROPERTY(bool, at_root);
-  public:
-    Selector_Schema(ParserState pstate, String* c)
-    : Selector(pstate), contents_(c), at_root_(false)
-    { }
-    virtual std::string to_string(bool compressed = false, int precision = 5) const;
-    ATTACH_OPERATIONS()
-  };
-
-  ////////////////////////////////////////////
-  // Abstract base class for simple selectors.
-  ////////////////////////////////////////////
-  class Simple_Selector : public Selector {
-    ADD_PROPERTY(std::string, ns);
-    ADD_PROPERTY(std::string, name)
-    ADD_PROPERTY(bool, has_ns)
-  public:
-    Simple_Selector(ParserState pstate, std::string n = "")
-    : Selector(pstate), ns_(""), name_(n), has_ns_(false)
-    {
-      size_t pos = n.find('|');
-      // found some namespace
-      if (pos != std::string::npos) {
-        has_ns_ = true;
-        ns_ = n.substr(0, pos);
-        name_ = n.substr(pos + 1);
-      }
-    }
-    virtual std::string ns_name() const
-    {
-      std::string name("");
-      if (has_ns_)
-        name += ns_ + "|";
-      return name + name_;
-    }
-    // namespace query functions
-    bool is_universal_ns() const
-    {
-      return has_ns_ && ns_ == "*";
-    }
-    bool has_universal_ns() const
-    {
-      return !has_ns_ || ns_ == "*";
-    }
-    bool is_empty_ns() const
-    {
-      return !has_ns_ || ns_ == "";
-    }
-    bool has_empty_ns() const
-    {
-      return has_ns_ && ns_ == "";
-    }
-    bool has_qualified_ns() const
-    {
-      return has_ns_ && ns_ != "" && ns_ != "*";
-    }
-    // name query functions
-    bool is_universal() const
-    {
-      return name_ == "*";
-    }
-
-    virtual ~Simple_Selector() = 0;
-    virtual Compound_Selector* unify_with(Compound_Selector*, Context&);
-    virtual bool has_parent_ref() { return false; };
-    virtual bool is_pseudo_element() { return false; }
-    virtual bool is_pseudo_class() { return false; }
-
-    virtual bool is_superselector_of(Compound_Selector* sub) { return false; }
-
-    bool operator==(const Simple_Selector& rhs) const;
-    inline bool operator!=(const Simple_Selector& rhs) const { return !(*this == rhs); }
-
-    bool operator<(const Simple_Selector& rhs) const;
-    // default implementation should work for most of the simple selectors (otherwise overload)
-    virtual std::string to_string(bool compressed = false, int precision = 5) const { return this->ns_name(); };
-    ATTACH_OPERATIONS();
-  };
-  inline Simple_Selector::~Simple_Selector() { }
-
-
-  //////////////////////////////////
-  // The Parent Selector Expression.
-  //////////////////////////////////
-  // parent selectors can occur in selectors but also
-  // inside strings in declarations (Compound_Selector).
-  // only one simple parent selector means the first case.
-  class Parent_Selector : public Simple_Selector {
-  public:
-    Parent_Selector(ParserState pstate)
-    : Simple_Selector(pstate, "&")
-    { has_reference(true); }
-    virtual bool has_parent_ref() { return true; };
-    virtual unsigned long specificity()
-    {
-      return 0;
-    }
-    std::string type() { return "selector"; }
-    static std::string type_name() { return "selector"; }
-    virtual std::string to_string(bool compressed = false, int precision = 5) const;
-    ATTACH_OPERATIONS()
-  };
-
-  /////////////////////////////////////////////////////////////////////////
-  // Placeholder selectors (e.g., "%foo") for use in extend-only selectors.
-  /////////////////////////////////////////////////////////////////////////
-  class Selector_Placeholder : public Simple_Selector {
-  public:
-    Selector_Placeholder(ParserState pstate, std::string n)
-    : Simple_Selector(pstate, n)
-    { has_placeholder(true); }
-    // virtual Selector_Placeholder* find_placeholder();
-    virtual ~Selector_Placeholder() {};
-    ATTACH_OPERATIONS()
-  };
-
-  /////////////////////////////////////////////////////////////////////
-  // Type selectors (and the universal selector) -- e.g., div, span, *.
-  /////////////////////////////////////////////////////////////////////
-  class Type_Selector : public Simple_Selector {
-  public:
-    Type_Selector(ParserState pstate, std::string n)
-    : Simple_Selector(pstate, n)
-    { }
-    virtual unsigned long specificity()
-    {
-      // ToDo: What is the specificity of the star selector?
-      if (name() == "*") return Constants::Specificity_Universal;
-      else               return Constants::Specificity_Type;
-    }
-    virtual Simple_Selector* unify_with(Simple_Selector*, Context&);
-    virtual Compound_Selector* unify_with(Compound_Selector*, Context&);
-    ATTACH_OPERATIONS()
-  };
-
-  ////////////////////////////////////////////////
-  // Selector qualifiers -- i.e., classes and ids.
-  ////////////////////////////////////////////////
-  class Selector_Qualifier : public Simple_Selector {
-  public:
-    Selector_Qualifier(ParserState pstate, std::string n)
-    : Simple_Selector(pstate, n)
-    { }
-    virtual unsigned long specificity()
-    {
-      if (name()[0] == '#') return Constants::Specificity_ID;
-      if (name()[0] == '.') return Constants::Specificity_Class;
-      else                  return Constants::Specificity_Type;
-    }
-    virtual Compound_Selector* unify_with(Compound_Selector*, Context&);
-    ATTACH_OPERATIONS()
-  };
-
-  ///////////////////////////////////////////////////
-  // Attribute selectors -- e.g., [src*=".jpg"], etc.
-  ///////////////////////////////////////////////////
-  class Attribute_Selector : public Simple_Selector {
-    ADD_PROPERTY(std::string, matcher)
-    ADD_PROPERTY(String*, value) // might be interpolated
-  public:
-    Attribute_Selector(ParserState pstate, std::string n, std::string m, String* v)
-    : Simple_Selector(pstate, n), matcher_(m), value_(v)
-    { }
-    virtual unsigned long specificity()
-    {
-      return Constants::Specificity_Attr;
-    }
-    bool operator==(const Simple_Selector& rhs) const;
-    bool operator==(const Attribute_Selector& rhs) const;
-    bool operator<(const Simple_Selector& rhs) const;
-    bool operator<(const Attribute_Selector& rhs) const;
-    virtual std::string to_string(bool compressed = false, int precision = 5) const;
-    ATTACH_OPERATIONS()
-  };
-
-  //////////////////////////////////////////////////////////////////
-  // Pseudo selectors -- e.g., :first-child, :nth-of-type(...), etc.
-  //////////////////////////////////////////////////////////////////
-  /* '::' starts a pseudo-element, ':' a pseudo-class */
-  /* Except :first-line, :first-letter, :before and :after */
-  /* Note that pseudo-elements are restricted to one per selector */
-  /* and occur only in the last simple_selector_sequence. */
-  inline bool is_pseudo_class_element(const std::string& name)
-  {
-    return name == ":before"       ||
-           name == ":after"        ||
-           name == ":first-line"   ||
-           name == ":first-letter";
-  }
-
-  class Pseudo_Selector : public Simple_Selector {
-    ADD_PROPERTY(String*, expression)
-  public:
-    Pseudo_Selector(ParserState pstate, std::string n, String* expr = 0)
-    : Simple_Selector(pstate, n), expression_(expr)
-    { }
-
-    // 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.
-    // For compatibility with existing style sheets, user agents must also
-    // accept the previous one-colon notation for pseudo-elements introduced
-    // 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()
-    {
-      return (name_[0] == ':' && name_[1] == ':')
-             || is_pseudo_class_element(name_);
-    }
-    virtual unsigned long specificity()
-    {
-      if (is_pseudo_element())
-        return Constants::Specificity_Type;
-      return Constants::Specificity_Pseudo;
-    }
-    virtual Compound_Selector* unify_with(Compound_Selector*, Context&);
-    ATTACH_OPERATIONS()
-  };
-
-  /////////////////////////////////////////////////
-  // 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*, selector)
-  public:
-    Wrapped_Selector(ParserState pstate, std::string n, Selector* sel)
-    : Simple_Selector(pstate, n), selector_(sel)
-    { }
-    virtual bool is_superselector_of(Wrapped_Selector* sub);
-    // Selectors inside the negation pseudo-class are counted like any
-    // other, but the negation itself does not count as a pseudo-class.
-    virtual unsigned long specificity()
-    {
-      return selector_ ? selector_->specificity() : 0;
-    }
-    bool operator==(const Simple_Selector& rhs) const;
-    bool operator==(const Wrapped_Selector& rhs) const;
-    virtual std::string to_string(bool compressed = false, int precision = 5) const;
-    ATTACH_OPERATIONS()
-  };
-
-  struct Complex_Selector_Pointer_Compare {
-    bool operator() (const Complex_Selector* const pLeft, const Complex_Selector* const pRight) const;
-  };
-
-  ////////////////////////////////////////////////////////////////////////////
-  // Simple selector sequences. Maintains flags indicating whether it contains
-  // any parent references or placeholders, to simplify expansion.
-  ////////////////////////////////////////////////////////////////////////////
-  typedef std::set<Complex_Selector*, Complex_Selector_Pointer_Compare> SourcesSet;
-  class Compound_Selector : public Selector, public Vectorized<Simple_Selector*> {
-  private:
-    SourcesSet sources_;
-    ADD_PROPERTY(bool, has_parent_reference);
-  protected:
-    void adjust_after_pushing(Simple_Selector* s)
-    {
-      if (s->has_reference())   has_reference(true);
-      if (s->has_placeholder()) has_placeholder(true);
-    }
-  public:
-    Compound_Selector(ParserState pstate, size_t s = 0)
-    : Selector(pstate),
-      Vectorized<Simple_Selector*>(s),
-      has_parent_reference_(false)
-    { }
-    bool contains_placeholder() {
-      for (size_t i = 0, L = length(); i < L; ++i) {
-        if ((*this)[i]->has_placeholder()) return true;
-      }
-      return false;
-    };
-
-    bool is_universal() const
-    {
-      return length() == 1 && (*this)[0]->is_universal();
-    }
-
-    Complex_Selector* to_complex(Memory_Manager& mem);
-    Compound_Selector* unify_with(Compound_Selector* rhs, Context& ctx);
-    // virtual Selector_Placeholder* find_placeholder();
-    virtual bool has_parent_ref();
-    Simple_Selector* base()
-    {
-      // Implement non-const in terms of const. Safe to const_cast since this method is non-const
-      return const_cast<Simple_Selector*>(static_cast<const Compound_Selector*>(this)->base());
-    }
-    const Simple_Selector* base() const {
-      if (length() == 0) return 0;
-      if (typeid(*(*this)[0]) == typeid(Type_Selector))
-        return (*this)[0];
-//      else cerr << "SERIOUSELY " << "\n";
-      return 0;
-    }
-    virtual bool is_superselector_of(Compound_Selector* sub, std::string wrapped = "");
-    virtual bool is_superselector_of(Complex_Selector* sub, std::string wrapped = "");
-    virtual bool is_superselector_of(Selector_List* sub, std::string wrapped = "");
-    virtual unsigned long specificity()
-    {
-      int sum = 0;
-      for (size_t i = 0, L = length(); i < L; ++i)
-      { sum += (*this)[i]->specificity(); }
-      return sum;
-    }
-
-    bool is_empty_reference()
-    {
-      return length() == 1 &&
-             typeid(*(*this)[0]) == typeid(Parent_Selector);
-    }
-    std::vector<std::string> to_str_vec(); // sometimes need to convert to a flat "by-value" data structure
-
-    bool operator<(const Compound_Selector& rhs) const;
-
-    bool operator==(const Compound_Selector& rhs) const;
-    inline bool operator!=(const Compound_Selector& rhs) const { return !(*this == rhs); }
-
-    SourcesSet& sources() { return sources_; }
-    void clearSources() { sources_.clear(); }
-    void mergeSources(SourcesSet& sources, Context& ctx);
-
-    Compound_Selector* clone(Context&) const; // does not clone the Simple_Selector*s
-
-    Compound_Selector* minus(Compound_Selector* rhs, Context& ctx);
-    virtual std::string to_string(bool compressed = false, int precision = 5) const;
-    ATTACH_OPERATIONS()
-  };
-
-  ////////////////////////////////////////////////////////////////////////////
-  // General selectors -- i.e., simple sequences combined with one of the four
-  // CSS selector combinators (">", "+", "~", and whitespace). Essentially a
-  // linked list.
-  ////////////////////////////////////////////////////////////////////////////
-  class Complex_Selector : public Selector {
-  public:
-    enum Combinator { ANCESTOR_OF, PARENT_OF, PRECEDES, ADJACENT_TO, REFERENCE };
-  private:
-    ADD_PROPERTY(Combinator, combinator)
-    ADD_PROPERTY(Compound_Selector*, head)
-    ADD_PROPERTY(Complex_Selector*, tail)
-    ADD_PROPERTY(String*, reference);
-  public:
-    bool contains_placeholder() {
-      if (head() && head()->contains_placeholder()) return true;
-      if (tail() && tail()->contains_placeholder()) return true;
-      return false;
-    };
-    Complex_Selector(ParserState pstate,
-                     Combinator c = ANCESTOR_OF,
-                     Compound_Selector* h = 0,
-                     Complex_Selector* t = 0,
-                     String* r = 0)
-    : Selector(pstate),
-      combinator_(c),
-      head_(h), tail_(t),
-      reference_(r)
-    {
-      if ((h && h->has_reference())   || (t && t->has_reference()))   has_reference(true);
-      if ((h && h->has_placeholder()) || (t && t->has_placeholder())) has_placeholder(true);
-    }
-    virtual bool has_parent_ref();
-
-    Complex_Selector* skip_empty_reference()
-    {
-      if ((!head_ || !head_->length() || head_->is_empty_reference()) &&
-          combinator() == Combinator::ANCESTOR_OF)
-      {
-        if (!tail_) return 0;
-        tail_->has_line_feed_ = this->has_line_feed_;
-        // tail_->has_line_break_ = this->has_line_break_;
-        return tail_->skip_empty_reference();
-      }
-      return this;
-    }
-
-    // can still have a tail
-    bool is_empty_ancestor() const
-    {
-      return (!head() || head()->length() == 0) &&
-             combinator() == Combinator::ANCESTOR_OF;
-    }
-
-    Complex_Selector* context(Context&);
-
-
-    // front returns the first real tail
-    // skips over parent and empty ones
-    const Complex_Selector* first() const;
-
-    // last returns the last real tail
-    const Complex_Selector* last() const;
-
-    Selector_List* tails(Context& ctx, Selector_List* tails);
-
-    // unconstant accessors
-    Complex_Selector* first();
-    Complex_Selector* last();
-
-    // some shortcuts that should be removed
-    const Complex_Selector* innermost() const { return last(); };
-    Complex_Selector* innermost() { return last(); };
-
-    size_t length() const;
-    Selector_List* parentize(Selector_List* parents, Context& ctx);
-    virtual bool is_superselector_of(Compound_Selector* sub, std::string wrapping = "");
-    virtual bool is_superselector_of(Complex_Selector* sub, std::string wrapping = "");
-    virtual bool is_superselector_of(Selector_List* sub, std::string wrapping = "");
-    // virtual Selector_Placeholder* find_placeholder();
-    Selector_List* unify_with(Complex_Selector* rhs, Context& ctx);
-    Combinator clear_innermost();
-    void append(Context&, Complex_Selector*);
-    void set_innermost(Complex_Selector*, Combinator);
-    virtual unsigned long specificity() const
-    {
-      int sum = 0;
-      if (head()) sum += head()->specificity();
-      if (tail()) sum += tail()->specificity();
-      return sum;
-    }
-    bool operator<(const Complex_Selector& rhs) const;
-    bool operator==(const Complex_Selector& rhs) const;
-    inline bool operator!=(const Complex_Selector& rhs) const { return !(*this == rhs); }
-    SourcesSet 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;
-
-      Compound_Selector* pHead = head();
-      Complex_Selector*  pTail = tail();
-
-      if (pHead) {
-        SourcesSet& headSources = pHead->sources();
-        srcs.insert(headSources.begin(), headSources.end());
-      }
-
-      if (pTail) {
-        SourcesSet tailSources = pTail->sources();
-        srcs.insert(tailSources.begin(), tailSources.end());
-      }
-
-      return srcs;
-    }
-    void addSources(SourcesSet& sources, Context& ctx) {
-      // members.map! {|m| m.is_a?(SimpleSequence) ? m.with_more_sources(sources) : m}
-      Complex_Selector* pIter = this;
-      while (pIter) {
-        Compound_Selector* pHead = pIter->head();
-
-        if (pHead) {
-          pHead->mergeSources(sources, ctx);
-        }
-
-        pIter = pIter->tail();
-      }
-    }
-    void clearSources() {
-      Complex_Selector* pIter = this;
-      while (pIter) {
-        Compound_Selector* pHead = pIter->head();
-
-        if (pHead) {
-          pHead->clearSources();
-        }
-
-        pIter = pIter->tail();
-      }
-    }
-    Complex_Selector* clone(Context&) const;      // does not clone Compound_Selector*s
-    Complex_Selector* cloneFully(Context&) const; // clones Compound_Selector*s
-    // std::vector<Compound_Selector*> to_vector();
-    virtual std::string to_string(bool compressed = false, int precision = 5) const;
-    ATTACH_OPERATIONS()
-  };
-
-  typedef std::deque<Complex_Selector*> ComplexSelectorDeque;
-  typedef Subset_Map<std::string, std::pair<Complex_Selector*, Compound_Selector*> > ExtensionSubsetMap;
-
-  ///////////////////////////////////
-  // Comma-separated selector groups.
-  ///////////////////////////////////
-  class Selector_List : public Selector, public Vectorized<Complex_Selector*> {
-    ADD_PROPERTY(std::vector<std::string>, wspace)
-  protected:
-    void adjust_after_pushing(Complex_Selector* c);
-  public:
-    Selector_List(ParserState pstate, size_t s = 0)
-    : Selector(pstate), Vectorized<Complex_Selector*>(s), wspace_(0)
-    { }
-    std::string type() { return "list"; }
-    // remove parent selector references
-    // basically unwraps parsed selectors
-    void remove_parent_selectors();
-    // virtual Selector_Placeholder* find_placeholder();
-    Selector_List* parentize(Selector_List* parents, Context& ctx);
-    virtual bool is_superselector_of(Compound_Selector* sub, std::string wrapping = "");
-    virtual bool is_superselector_of(Complex_Selector* sub, std::string wrapping = "");
-    virtual bool is_superselector_of(Selector_List* sub, std::string wrapping = "");
-    Selector_List* unify_with(Selector_List*, Context&);
-    void populate_extends(Selector_List*, Context&, ExtensionSubsetMap&);
-    virtual unsigned long specificity()
-    {
-      unsigned long sum = 0;
-      unsigned long specificity = 0;
-      for (size_t i = 0, L = length(); i < L; ++i)
-      {
-        specificity = (*this)[i]->specificity();
-        if (sum < specificity) sum = specificity;
-      }
-      return sum;
-    }
-    Selector_List* clone(Context&) const;      // does not clone Compound_Selector*s
-    Selector_List* cloneFully(Context&) const; // clones Compound_Selector*s
-    virtual bool operator==(const Selector& rhs) const;
-    virtual bool operator==(const Selector_List& rhs) const;
-    // Selector Lists can be compared to comma lists
-    virtual bool operator==(const Expression& rhs) const;
-    virtual std::string to_string(bool compressed = false, int precision = 5) const;
-    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* l, const Complex_Selector* r) { return (*l < *r); } };
-  struct cmp_compound_selector { inline bool operator() (const Compound_Selector* l, const Compound_Selector* r) { return (*l < *r); } };
-  struct cmp_simple_selector { inline bool operator() (const Simple_Selector* l, const Simple_Selector* r) { return (*l < *r); } };
+#include "sass/base.h"
+#include "ast_fwd_decl.hpp"
+
+#ifdef DEBUG_SHARED_PTR
+
+#define ATTACH_VIRTUAL_AST_OPERATIONS(klass) \
+  virtual klass##_Ptr copy(std::string, size_t) const = 0; \
+  virtual klass##_Ptr clone(std::string, size_t) const = 0; \
+
+#define ATTACH_AST_OPERATIONS(klass) \
+  virtual klass##_Ptr copy(std::string, size_t) const; \
+  virtual klass##_Ptr clone(std::string, size_t) const; \
+
+#else
+
+#define ATTACH_VIRTUAL_AST_OPERATIONS(klass) \
+  virtual klass##_Ptr copy() const = 0; \
+  virtual klass##_Ptr clone() const = 0; \
+
+#define ATTACH_AST_OPERATIONS(klass) \
+  virtual klass##_Ptr copy() const; \
+  virtual klass##_Ptr clone() const; \
+
+#endif
+
+#ifdef __clang__
+
+/*
+ * There are some overloads used here that trigger the clang overload
+ * hiding warning. Specifically:
+ *
+ * Type type() which hides string type() from Expression
+ *
+ */
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Woverloaded-virtual"
+
+#endif
+
+#include "util.hpp"
+#include "units.hpp"
+#include "context.hpp"
+#include "position.hpp"
+#include "constants.hpp"
+#include "operation.hpp"
+#include "position.hpp"
+#include "inspect.hpp"
+#include "source_map.hpp"
+#include "environment.hpp"
+#include "error_handling.hpp"
+#include "ast_def_macros.hpp"
+#include "ast_fwd_decl.hpp"
+#include "source_map.hpp"
+
+#include "sass.h"
+
+namespace Sass {
+
+  // easier to search with name
+  const bool DELAYED = true;
+
+  // ToDo: should this really be hardcoded
+  // Note: most methods follow precision option
+  const double NUMBER_EPSILON = 0.00000000000001;
+
+  // ToDo: where does this fit best?
+  // We don't share this with C-API?
+  class Operand {
+    public:
+      Operand(Sass_OP operand, bool ws_before = false, bool ws_after = false)
+      : operand(operand), ws_before(ws_before), ws_after(ws_after)
+      { }
+    public:
+      enum Sass_OP operand;
+      bool ws_before;
+      bool ws_after;
+  };
+
+  //////////////////////////////////////////////////////////
+  // `hash_combine` comes from boost (functional/hash):
+  // http://www.boost.org/doc/libs/1_35_0/doc/html/hash/combine.html
+  // Boost Software License - Version 1.0
+  // http://www.boost.org/users/license.html
+  template <typename T>
+  void hash_combine (std::size_t& seed, const T& val)
+  {
+    seed ^= std::hash<T>()(val) + 0x9e3779b9
+             + (seed<<6) + (seed>>2);
+  }
+  //////////////////////////////////////////////////////////
+
+  //////////////////////////////////////////////////////////
+  // Abstract base class for all abstract syntax tree nodes.
+  //////////////////////////////////////////////////////////
+  class AST_Node : public SharedObj {
+    ADD_PROPERTY(ParserState, pstate)
+  public:
+    AST_Node(ParserState pstate)
+    : pstate_(pstate)
+    { }
+    AST_Node(const AST_Node* ptr)
+    : pstate_(ptr->pstate_)
+    { }
+
+    // AST_Node(AST_Node& ptr) = delete;
+
+    virtual ~AST_Node() = 0;
+    virtual size_t hash() { return 0; }
+    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 void cloneChildren() {};
+  public:
+    void update_pstate(const ParserState& pstate);
+    void set_pstate_offset(const Offset& offset);
+  public:
+    Offset off() { return pstate(); }
+    Position pos() { return pstate(); }
+    ATTACH_OPERATIONS()
+  };
+  inline AST_Node::~AST_Node() { }
+
+
+  //////////////////////////////////////////////////////////////////////
+  // Abstract base class for expressions. This side of the AST hierarchy
+  // represents elements in value contexts, which exist primarily to be
+  // evaluated and returned.
+  //////////////////////////////////////////////////////////////////////
+  class Expression : public AST_Node {
+  public:
+    enum Concrete_Type {
+      NONE,
+      BOOLEAN,
+      NUMBER,
+      COLOR,
+      STRING,
+      LIST,
+      MAP,
+      SELECTOR,
+      NULL_VAL,
+      C_WARNING,
+      C_ERROR,
+      FUNCTION,
+      NUM_TYPES
+    };
+    enum Simple_Type {
+      SIMPLE,
+      ATTR_SEL,
+      PSEUDO_SEL,
+      WRAPPED_SEL,
+    };
+  private:
+    // expressions in some contexts shouldn't be evaluated
+    ADD_PROPERTY(bool, is_delayed)
+    ADD_PROPERTY(bool, is_expanded)
+    ADD_PROPERTY(bool, is_interpolant)
+    ADD_PROPERTY(Concrete_Type, concrete_type)
+  public:
+    Expression(ParserState pstate,
+               bool d = false, bool e = false, bool i = false, Concrete_Type ct = NONE)
+    : AST_Node(pstate),
+      is_delayed_(d),
+      is_expanded_(e),
+      is_interpolant_(i),
+      concrete_type_(ct)
+    { }
+    Expression(const Expression* ptr)
+    : AST_Node(ptr),
+      is_delayed_(ptr->is_delayed_),
+      is_expanded_(ptr->is_expanded_),
+      is_interpolant_(ptr->is_interpolant_),
+      concrete_type_(ptr->concrete_type_)
+    { }
+    virtual operator bool() { return true; }
+    virtual ~Expression() { }
+    virtual std::string type() { return ""; /* TODO: raise an error? */ }
+    virtual bool is_invisible() const { return false; }
+    static std::string type_name() { return ""; }
+    virtual bool is_false() { return false; }
+    // virtual bool is_true() { return !is_false(); }
+    virtual bool operator== (const Expression& rhs) const { return false; }
+    virtual bool eq(const Expression& rhs) const { return *this == rhs; };
+    virtual void set_delayed(bool delayed) { is_delayed(delayed); }
+    virtual bool has_interpolant() const { return is_interpolant(); }
+    virtual bool is_left_interpolant() const { return is_interpolant(); }
+    virtual bool is_right_interpolant() const { return is_interpolant(); }
+    virtual std::string inspect() const { return to_string({ INSPECT, 5 }); }
+    virtual std::string to_sass() const { return to_string({ TO_SASS, 5 }); }
+    ATTACH_VIRTUAL_AST_OPERATIONS(Expression);
+    virtual size_t hash() { return 0; }
+  };
+
+  //////////////////////////////////////////////////////////////////////
+  // Still just an expression, but with a to_string method
+  //////////////////////////////////////////////////////////////////////
+  class PreValue : public Expression {
+  public:
+    PreValue(ParserState pstate,
+               bool d = false, bool e = false, bool i = false, Concrete_Type ct = NONE)
+    : Expression(pstate, d, e, i, ct)
+    { }
+    PreValue(const PreValue* ptr)
+    : Expression(ptr)
+    { }
+    ATTACH_VIRTUAL_AST_OPERATIONS(PreValue);
+    virtual ~PreValue() { }
+  };
+
+  //////////////////////////////////////////////////////////////////////
+  // base class for values that support operations
+  //////////////////////////////////////////////////////////////////////
+  class Value : public Expression {
+  public:
+    Value(ParserState pstate,
+          bool d = false, bool e = false, bool i = false, Concrete_Type ct = NONE)
+    : Expression(pstate, d, e, i, ct)
+    { }
+    Value(const Value* ptr)
+    : Expression(ptr)
+    { }
+    ATTACH_VIRTUAL_AST_OPERATIONS(Value);
+    virtual bool operator== (const Expression& rhs) const = 0;
+  };
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+// Hash method specializations for std::unordered_map to work with Sass::Expression
+/////////////////////////////////////////////////////////////////////////////////////
+
+namespace std {
+  template<>
+  struct hash<Sass::Expression_Obj>
+  {
+    size_t operator()(Sass::Expression_Obj s) const
+    {
+      return s->hash();
+    }
+  };
+  template<>
+  struct equal_to<Sass::Expression_Obj>
+  {
+    bool operator()( Sass::Expression_Obj lhs,  Sass::Expression_Obj rhs) const
+    {
+      return lhs->hash() == rhs->hash();
+    }
+  };
+}
+
+namespace Sass {
+
+  /////////////////////////////////////////////////////////////////////////////
+  // Mixin class for AST nodes that should behave like vectors. Uses the
+  // "Template Method" design pattern to allow subclasses to adjust their flags
+  // when certain objects are pushed.
+  /////////////////////////////////////////////////////////////////////////////
+  template <typename T>
+  class Vectorized {
+    std::vector<T> elements_;
+  protected:
+    size_t hash_;
+    void reset_hash() { hash_ = 0; }
+    virtual void adjust_after_pushing(T element) { }
+  public:
+    Vectorized(size_t s = 0) : elements_(std::vector<T>()), hash_(0)
+    { elements_.reserve(s); }
+    virtual ~Vectorized() = 0;
+    size_t length() const   { return elements_.size(); }
+    bool empty() const      { return elements_.empty(); }
+    void clear()            { return elements_.clear(); }
+    T last() const          { return elements_.back(); }
+    T first() const         { return elements_.front(); }
+    T& operator[](size_t i) { return elements_[i]; }
+    virtual const T& at(size_t i) const { return elements_.at(i); }
+    virtual T& at(size_t i) { return elements_.at(i); }
+    const T& operator[](size_t i) const { return elements_[i]; }
+    virtual void append(T element)
+    {
+      if (element) {
+        reset_hash();
+        elements_.push_back(element);
+        adjust_after_pushing(element);
+      }
+    }
+    virtual void concat(Vectorized* v)
+    {
+      for (size_t i = 0, L = v->length(); i < L; ++i) this->append((*v)[i]);
+    }
+    Vectorized& unshift(T element)
+    {
+      elements_.insert(elements_.begin(), element);
+      return *this;
+    }
+    std::vector<T>& elements() { return elements_; }
+    const std::vector<T>& elements() const { return elements_; }
+    std::vector<T>& elements(std::vector<T>& e) { elements_ = e; return elements_; }
+
+    virtual size_t hash()
+    {
+      if (hash_ == 0) {
+        for (T& el : elements_) {
+          hash_combine(hash_, el->hash());
+        }
+      }
+      return hash_;
+    }
+
+    typename std::vector<T>::iterator end() { return elements_.end(); }
+    typename std::vector<T>::iterator begin() { return elements_.begin(); }
+    typename std::vector<T>::const_iterator end() const { return elements_.end(); }
+    typename std::vector<T>::const_iterator begin() const { return elements_.begin(); }
+    typename std::vector<T>::iterator erase(typename std::vector<T>::iterator el) { return elements_.erase(el); }
+    typename std::vector<T>::const_iterator erase(typename std::vector<T>::const_iterator el) { return elements_.erase(el); }
+
+  };
+  template <typename T>
+  inline Vectorized<T>::~Vectorized() { }
+
+  /////////////////////////////////////////////////////////////////////////////
+  // Mixin class for AST nodes that should behave like a hash table. Uses an
+  // extra <std::vector> internally to maintain insertion order for interation.
+  /////////////////////////////////////////////////////////////////////////////
+  class Hashed {
+  private:
+    ExpressionMap elements_;
+    std::vector<Expression_Obj> list_;
+  protected:
+    size_t hash_;
+    Expression_Obj duplicate_key_;
+    void reset_hash() { hash_ = 0; }
+    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(); }
+    virtual ~Hashed();
+    size_t length() const                  { return list_.size(); }
+    bool empty() const                     { return list_.empty(); }
+    bool has(Expression_Obj k) const          { return elements_.count(k) == 1; }
+    Expression_Obj at(Expression_Obj k) const;
+    bool has_duplicate_key() const         { return duplicate_key_ != 0; }
+    Expression_Obj get_duplicate_key() const  { return duplicate_key_; }
+    const ExpressionMap elements() { return elements_; }
+    Hashed& operator<<(std::pair<Expression_Obj, Expression_Obj> p)
+    {
+      reset_hash();
+
+      if (!has(p.first)) list_.push_back(p.first);
+      else if (!duplicate_key_) duplicate_key_ = p.first;
+
+      elements_[p.first] = p.second;
+
+      adjust_after_pushing(p);
+      return *this;
+    }
+    Hashed& operator+=(Hashed* h)
+    {
+      if (length() == 0) {
+        this->elements_ = h->elements_;
+        this->list_ = h->list_;
+        return *this;
+      }
+
+      for (auto key : h->keys()) {
+        *this << std::make_pair(key, h->at(key));
+      }
+
+      reset_duplicate_key();
+      return *this;
+    }
+    const ExpressionMap& pairs() const { return elements_; }
+    const std::vector<Expression_Obj>& keys() const { return list_; }
+
+//    std::unordered_map<Expression_Obj, Expression_Obj>::iterator end() { return elements_.end(); }
+//    std::unordered_map<Expression_Obj, Expression_Obj>::iterator begin() { return elements_.begin(); }
+//    std::unordered_map<Expression_Obj, Expression_Obj>::const_iterator end() const { return elements_.end(); }
+//    std::unordered_map<Expression_Obj, Expression_Obj>::const_iterator begin() const { return elements_.begin(); }
+
+  };
+  inline Hashed::~Hashed() { }
+
+
+  /////////////////////////////////////////////////////////////////////////
+  // Abstract base class for statements. This side of the AST hierarchy
+  // represents elements in expansion contexts, which exist primarily to be
+  // rewritten and macro-expanded.
+  /////////////////////////////////////////////////////////////////////////
+  class Statement : public AST_Node {
+  public:
+    enum Statement_Type {
+      NONE,
+      RULESET,
+      MEDIA,
+      DIRECTIVE,
+      SUPPORTS,
+      ATROOT,
+      BUBBLE,
+      CONTENT,
+      KEYFRAMERULE,
+      DECLARATION,
+      ASSIGNMENT,
+      IMPORT_STUB,
+      IMPORT,
+      COMMENT,
+      WARNING,
+      RETURN,
+      EXTEND,
+      ERROR,
+      DEBUGSTMT,
+      WHILE,
+      EACH,
+      FOR,
+      IF
+    };
+  private:
+    ADD_PROPERTY(Statement_Type, statement_type)
+    ADD_PROPERTY(size_t, tabs)
+    ADD_PROPERTY(bool, group_end)
+  public:
+    Statement(ParserState pstate, Statement_Type st = NONE, size_t t = 0)
+    : AST_Node(pstate), statement_type_(st), tabs_(t), group_end_(false)
+     { }
+    Statement(const Statement* ptr)
+    : AST_Node(ptr),
+      statement_type_(ptr->statement_type_),
+      tabs_(ptr->tabs_),
+      group_end_(ptr->group_end_)
+     { }
+    virtual ~Statement() = 0;
+    // needed for rearranging nested rulesets during CSS emission
+    virtual bool   is_invisible() const { return false; }
+    virtual bool   bubbles() { return false; }
+    virtual bool has_content()
+    {
+      return statement_type_ == CONTENT;
+    }
+  };
+  inline Statement::~Statement() { }
+
+  ////////////////////////
+  // Blocks of statements.
+  ////////////////////////
+  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)
+    {
+    }
+  public:
+    Block(ParserState pstate, size_t s = 0, bool r = false)
+    : Statement(pstate),
+      Vectorized<Statement_Obj>(s),
+      is_root_(r),
+      is_at_root_(false)
+    { }
+    Block(const Block* ptr)
+    : Statement(ptr),
+      Vectorized<Statement_Obj>(*ptr),
+      is_root_(ptr->is_root_),
+      is_at_root_(ptr->is_at_root_)
+    { }
+    virtual bool has_content()
+    {
+      for (size_t i = 0, L = elements().size(); i < L; ++i) {
+        if (elements()[i]->has_content()) return true;
+      }
+      return Statement::has_content();
+    }
+    ATTACH_AST_OPERATIONS(Block)
+    ATTACH_OPERATIONS()
+  };
+
+  ////////////////////////////////////////////////////////////////////////
+  // Abstract base class for statements that contain blocks of statements.
+  ////////////////////////////////////////////////////////////////////////
+  class Has_Block : public Statement {
+    ADD_PROPERTY(Block_Obj, block)
+  public:
+    Has_Block(ParserState pstate, Block_Obj b)
+    : Statement(pstate), block_(b)
+    { }
+    Has_Block(const Has_Block* ptr)
+    : Statement(ptr), block_(ptr->block_)
+    { }
+    virtual bool has_content()
+    {
+      return (block_ && block_->has_content()) || Statement::has_content();
+    }
+    virtual ~Has_Block() = 0;
+  };
+  inline Has_Block::~Has_Block() { }
+
+  /////////////////////////////////////////////////////////////////////////////
+  // Rulesets (i.e., sets of styles headed by a selector and containing a block
+  // of style declarations.
+  /////////////////////////////////////////////////////////////////////////////
+  class Ruleset : public Has_Block {
+    ADD_PROPERTY(Selector_Obj, selector)
+    ADD_PROPERTY(bool, at_root);
+    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)
+    { 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;
+    ATTACH_AST_OPERATIONS(Ruleset)
+    ATTACH_OPERATIONS()
+  };
+
+  /////////////////
+  // Bubble.
+  /////////////////
+  class Bubble : public Statement {
+    ADD_PROPERTY(Statement_Obj, node)
+    ADD_PROPERTY(bool, group_end)
+  public:
+    Bubble(ParserState pstate, Statement_Obj n, Statement_Obj g = 0, size_t t = 0)
+    : Statement(pstate, Statement::BUBBLE, t), node_(n), group_end_(g == 0)
+    { }
+    Bubble(const Bubble* ptr)
+    : Statement(ptr),
+      node_(ptr->node_),
+      group_end_(ptr->group_end_)
+    { }
+    bool bubbles() { return true; }
+    ATTACH_AST_OPERATIONS(Bubble)
+    ATTACH_OPERATIONS()
+  };
+
+  /////////////////
+  // Trace.
+  /////////////////
+  class Trace : public Has_Block {
+    ADD_PROPERTY(std::string, name)
+  public:
+    Trace(ParserState pstate, std::string n, Block_Obj b = 0)
+    : Has_Block(pstate, b), name_(n)
+    { }
+    Trace(const Trace* ptr)
+    : Has_Block(ptr),
+      name_(ptr->name_)
+    { }
+    ATTACH_AST_OPERATIONS(Trace)
+    ATTACH_OPERATIONS()
+  };
+
+  /////////////////
+  // Media queries.
+  /////////////////
+  class Media_Block : public Has_Block {
+    ADD_PROPERTY(List_Obj, media_queries)
+  public:
+    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); }
+    bool bubbles() { return true; }
+    bool is_invisible() const;
+    ATTACH_AST_OPERATIONS(Media_Block)
+    ATTACH_OPERATIONS()
+  };
+
+  ///////////////////////////////////////////////////////////////////////
+  // At-rules -- arbitrary directives beginning with "@" that may have an
+  // optional statement block.
+  ///////////////////////////////////////////////////////////////////////
+  class Directive : public Has_Block {
+    ADD_PROPERTY(std::string, keyword)
+    ADD_PROPERTY(Selector_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)
+    : Has_Block(pstate, b), keyword_(kwd), selector_(sel), value_(val) // set value manually if needed
+    { statement_type(DIRECTIVE); }
+    Directive(const Directive* ptr)
+    : Has_Block(ptr),
+      keyword_(ptr->keyword_),
+      selector_(ptr->selector_),
+      value_(ptr->value_) // set value manually if needed
+    { statement_type(DIRECTIVE); }
+    bool bubbles() { return is_keyframes() || is_media(); }
+    bool is_media() {
+      return keyword_.compare("@-webkit-media") == 0 ||
+             keyword_.compare("@-moz-media") == 0 ||
+             keyword_.compare("@-o-media") == 0 ||
+             keyword_.compare("@media") == 0;
+    }
+    bool is_keyframes() {
+      return keyword_.compare("@-webkit-keyframes") == 0 ||
+             keyword_.compare("@-moz-keyframes") == 0 ||
+             keyword_.compare("@-o-keyframes") == 0 ||
+             keyword_.compare("@keyframes") == 0;
+    }
+    ATTACH_AST_OPERATIONS(Directive)
+    ATTACH_OPERATIONS()
+  };
+
+  ///////////////////////////////////////////////////////////////////////
+  // Keyframe-rules -- the child blocks of "@keyframes" nodes.
+  ///////////////////////////////////////////////////////////////////////
+  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)
+  public:
+    Keyframe_Rule(ParserState pstate, Block_Obj b)
+    : Has_Block(pstate, b), name_()
+    { statement_type(KEYFRAMERULE); }
+    Keyframe_Rule(const Keyframe_Rule* ptr)
+    : Has_Block(ptr), name_(ptr->name_)
+    { statement_type(KEYFRAMERULE); }
+    ATTACH_AST_OPERATIONS(Keyframe_Rule)
+    ATTACH_OPERATIONS()
+  };
+
+  ////////////////////////////////////////////////////////////////////////
+  // Declarations -- style rules consisting of a property name and values.
+  ////////////////////////////////////////////////////////////////////////
+  class Declaration : public Has_Block {
+    ADD_PROPERTY(String_Obj, property)
+    ADD_PROPERTY(Expression_Obj, value)
+    ADD_PROPERTY(bool, is_important)
+    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)
+    { statement_type(DECLARATION); }
+    Declaration(const Declaration* ptr)
+    : Has_Block(ptr),
+      property_(ptr->property_),
+      value_(ptr->value_),
+      is_important_(ptr->is_important_),
+      is_indented_(ptr->is_indented_)
+    { statement_type(DECLARATION); }
+    ATTACH_AST_OPERATIONS(Declaration)
+    ATTACH_OPERATIONS()
+  };
+
+  /////////////////////////////////////
+  // Assignments -- variable and value.
+  /////////////////////////////////////
+  class Assignment : public Statement {
+    ADD_PROPERTY(std::string, variable)
+    ADD_PROPERTY(Expression_Obj, value)
+    ADD_PROPERTY(bool, is_default)
+    ADD_PROPERTY(bool, is_global)
+  public:
+    Assignment(ParserState pstate,
+               std::string var, Expression_Obj val,
+               bool is_default = false,
+               bool is_global = false)
+    : Statement(pstate), variable_(var), value_(val), is_default_(is_default), is_global_(is_global)
+    { statement_type(ASSIGNMENT); }
+    Assignment(const Assignment* ptr)
+    : Statement(ptr),
+      variable_(ptr->variable_),
+      value_(ptr->value_),
+      is_default_(ptr->is_default_),
+      is_global_(ptr->is_global_)
+    { statement_type(ASSIGNMENT); }
+    ATTACH_AST_OPERATIONS(Assignment)
+    ATTACH_OPERATIONS()
+  };
+
+  ////////////////////////////////////////////////////////////////////////////
+  // Import directives. CSS and Sass import lists can be intermingled, so it's
+  // necessary to store a list of each in an Import node.
+  ////////////////////////////////////////////////////////////////////////////
+  class Import : public Statement {
+    std::vector<Expression_Obj> urls_;
+    std::vector<Include>     incs_;
+    ADD_PROPERTY(List_Obj,      import_queries);
+  public:
+    Import(ParserState pstate)
+    : Statement(pstate),
+      urls_(std::vector<Expression_Obj>()),
+      incs_(std::vector<Include>()),
+      import_queries_()
+    { statement_type(IMPORT); }
+    Import(const Import* ptr)
+    : Statement(ptr),
+      urls_(ptr->urls_),
+      incs_(ptr->incs_),
+      import_queries_(ptr->import_queries_)
+    { statement_type(IMPORT); }
+    std::vector<Expression_Obj>& urls() { return urls_; }
+    std::vector<Include>& incs() { return incs_; }
+    ATTACH_AST_OPERATIONS(Import)
+    ATTACH_OPERATIONS()
+  };
+
+  // not yet resolved single import
+  // so far we only know requested name
+  class Import_Stub : public Statement {
+    Include resource_;
+  public:
+    std::string abs_path() { return resource_.abs_path; };
+    std::string imp_path() { return resource_.imp_path; };
+    Include resource() { return resource_; };
+
+    Import_Stub(ParserState pstate, Include res)
+    : Statement(pstate), resource_(res)
+    { statement_type(IMPORT_STUB); }
+    Import_Stub(const Import_Stub* ptr)
+    : Statement(ptr), resource_(ptr->resource_)
+    { statement_type(IMPORT_STUB); }
+    ATTACH_AST_OPERATIONS(Import_Stub)
+    ATTACH_OPERATIONS()
+  };
+
+  //////////////////////////////
+  // The Sass `@warn` directive.
+  //////////////////////////////
+  class Warning : public Statement {
+    ADD_PROPERTY(Expression_Obj, message)
+  public:
+    Warning(ParserState pstate, Expression_Obj msg)
+    : Statement(pstate), message_(msg)
+    { statement_type(WARNING); }
+    Warning(const Warning* ptr)
+    : Statement(ptr), message_(ptr->message_)
+    { statement_type(WARNING); }
+    ATTACH_AST_OPERATIONS(Warning)
+    ATTACH_OPERATIONS()
+  };
+
+  ///////////////////////////////
+  // The Sass `@error` directive.
+  ///////////////////////////////
+  class Error : public Statement {
+    ADD_PROPERTY(Expression_Obj, message)
+  public:
+    Error(ParserState pstate, Expression_Obj msg)
+    : Statement(pstate), message_(msg)
+    { statement_type(ERROR); }
+    Error(const Error* ptr)
+    : Statement(ptr), message_(ptr->message_)
+    { statement_type(ERROR); }
+    ATTACH_AST_OPERATIONS(Error)
+    ATTACH_OPERATIONS()
+  };
+
+  ///////////////////////////////
+  // The Sass `@debug` directive.
+  ///////////////////////////////
+  class Debug : public Statement {
+    ADD_PROPERTY(Expression_Obj, value)
+  public:
+    Debug(ParserState pstate, Expression_Obj val)
+    : Statement(pstate), value_(val)
+    { statement_type(DEBUGSTMT); }
+    Debug(const Debug* ptr)
+    : Statement(ptr), value_(ptr->value_)
+    { statement_type(DEBUGSTMT); }
+    ATTACH_AST_OPERATIONS(Debug)
+    ATTACH_OPERATIONS()
+  };
+
+  ///////////////////////////////////////////
+  // CSS comments. These may be interpolated.
+  ///////////////////////////////////////////
+  class Comment : public Statement {
+    ADD_PROPERTY(String_Obj, text)
+    ADD_PROPERTY(bool, is_important)
+  public:
+    Comment(ParserState pstate, String_Obj txt, bool is_important)
+    : Statement(pstate), text_(txt), is_important_(is_important)
+    { statement_type(COMMENT); }
+    Comment(const Comment* ptr)
+    : Statement(ptr),
+      text_(ptr->text_),
+      is_important_(ptr->is_important_)
+    { statement_type(COMMENT); }
+    virtual bool is_invisible() const
+    { return /* is_important() == */ false; }
+    ATTACH_AST_OPERATIONS(Comment)
+    ATTACH_OPERATIONS()
+  };
+
+  ////////////////////////////////////
+  // The Sass `@if` control directive.
+  ////////////////////////////////////
+  class If : public Has_Block {
+    ADD_PROPERTY(Expression_Obj, predicate)
+    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)
+    { statement_type(IF); }
+    If(const If* ptr)
+    : Has_Block(ptr),
+      predicate_(ptr->predicate_),
+      alternative_(ptr->alternative_)
+    { statement_type(IF); }
+    virtual bool has_content()
+    {
+      return Has_Block::has_content() || (alternative_ && alternative_->has_content());
+    }
+    ATTACH_AST_OPERATIONS(If)
+    ATTACH_OPERATIONS()
+  };
+
+  /////////////////////////////////////
+  // The Sass `@for` control directive.
+  /////////////////////////////////////
+  class For : public Has_Block {
+    ADD_PROPERTY(std::string, variable)
+    ADD_PROPERTY(Expression_Obj, lower_bound)
+    ADD_PROPERTY(Expression_Obj, upper_bound)
+    ADD_PROPERTY(bool, is_inclusive)
+  public:
+    For(ParserState pstate,
+        std::string var, Expression_Obj lo, Expression_Obj hi, Block_Obj b, bool inc)
+    : Has_Block(pstate, b),
+      variable_(var), lower_bound_(lo), upper_bound_(hi), is_inclusive_(inc)
+    { statement_type(FOR); }
+    For(const For* ptr)
+    : Has_Block(ptr),
+      variable_(ptr->variable_),
+      lower_bound_(ptr->lower_bound_),
+      upper_bound_(ptr->upper_bound_),
+      is_inclusive_(ptr->is_inclusive_)
+    { statement_type(FOR); }
+    ATTACH_AST_OPERATIONS(For)
+    ATTACH_OPERATIONS()
+  };
+
+  //////////////////////////////////////
+  // The Sass `@each` control directive.
+  //////////////////////////////////////
+  class Each : public Has_Block {
+    ADD_PROPERTY(std::vector<std::string>, variables)
+    ADD_PROPERTY(Expression_Obj, list)
+  public:
+    Each(ParserState pstate, std::vector<std::string> vars, Expression_Obj lst, Block_Obj b)
+    : Has_Block(pstate, b), variables_(vars), list_(lst)
+    { statement_type(EACH); }
+    Each(const Each* ptr)
+    : Has_Block(ptr), variables_(ptr->variables_), list_(ptr->list_)
+    { statement_type(EACH); }
+    ATTACH_AST_OPERATIONS(Each)
+    ATTACH_OPERATIONS()
+  };
+
+  ///////////////////////////////////////
+  // The Sass `@while` control directive.
+  ///////////////////////////////////////
+  class While : public Has_Block {
+    ADD_PROPERTY(Expression_Obj, predicate)
+  public:
+    While(ParserState pstate, Expression_Obj pred, Block_Obj b)
+    : Has_Block(pstate, b), predicate_(pred)
+    { statement_type(WHILE); }
+    While(const While* ptr)
+    : Has_Block(ptr), predicate_(ptr->predicate_)
+    { statement_type(WHILE); }
+    ATTACH_AST_OPERATIONS(While)
+    ATTACH_OPERATIONS()
+  };
+
+  /////////////////////////////////////////////////////////////
+  // The @return directive for use inside SassScript functions.
+  /////////////////////////////////////////////////////////////
+  class Return : public Statement {
+    ADD_PROPERTY(Expression_Obj, value)
+  public:
+    Return(ParserState pstate, Expression_Obj val)
+    : Statement(pstate), value_(val)
+    { statement_type(RETURN); }
+    Return(const Return* ptr)
+    : Statement(ptr), value_(ptr->value_)
+    { statement_type(RETURN); }
+    ATTACH_AST_OPERATIONS(Return)
+    ATTACH_OPERATIONS()
+  };
+
+  ////////////////////////////////
+  // The Sass `@extend` directive.
+  ////////////////////////////////
+  class Extension : public Statement {
+    ADD_PROPERTY(Selector_Obj, selector)
+  public:
+    Extension(ParserState pstate, Selector_Obj s)
+    : Statement(pstate), selector_(s)
+    { statement_type(EXTEND); }
+    Extension(const Extension* ptr)
+    : Statement(ptr), selector_(ptr->selector_)
+    { statement_type(EXTEND); }
+    ATTACH_AST_OPERATIONS(Extension)
+    ATTACH_OPERATIONS()
+  };
+
+  /////////////////////////////////////////////////////////////////////////////
+  // Definitions for both mixins and functions. The two cases are distinguished
+  // 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>);
+  class Definition : public Has_Block {
+  public:
+    enum Type { MIXIN, FUNCTION };
+    ADD_PROPERTY(std::string, name)
+    ADD_PROPERTY(Parameters_Obj, parameters)
+    ADD_PROPERTY(Env*, environment)
+    ADD_PROPERTY(Type, type)
+    ADD_PROPERTY(Native_Function, native_function)
+    ADD_PROPERTY(Sass_Function_Entry, c_function)
+    ADD_PROPERTY(void*, cookie)
+    ADD_PROPERTY(bool, is_overload_stub)
+    ADD_PROPERTY(Signature, signature)
+  public:
+    Definition(const Definition* ptr)
+    : Has_Block(ptr),
+      name_(ptr->name_),
+      parameters_(ptr->parameters_),
+      environment_(ptr->environment_),
+      type_(ptr->type_),
+      native_function_(ptr->native_function_),
+      c_function_(ptr->c_function_),
+      cookie_(ptr->cookie_),
+      is_overload_stub_(ptr->is_overload_stub_),
+      signature_(ptr->signature_)
+    { }
+
+    Definition(ParserState pstate,
+               std::string n,
+               Parameters_Obj params,
+               Block_Obj b,
+               Type t)
+    : Has_Block(pstate, b),
+      name_(n),
+      parameters_(params),
+      environment_(0),
+      type_(t),
+      native_function_(0),
+      c_function_(0),
+      cookie_(0),
+      is_overload_stub_(false),
+      signature_(0)
+    { }
+    Definition(ParserState pstate,
+               Signature sig,
+               std::string n,
+               Parameters_Obj params,
+               Native_Function func_ptr,
+               bool overload_stub = false)
+    : Has_Block(pstate, 0),
+      name_(n),
+      parameters_(params),
+      environment_(0),
+      type_(FUNCTION),
+      native_function_(func_ptr),
+      c_function_(0),
+      cookie_(0),
+      is_overload_stub_(overload_stub),
+      signature_(sig)
+    { }
+    Definition(ParserState pstate,
+               Signature sig,
+               std::string n,
+               Parameters_Obj params,
+               Sass_Function_Entry c_func,
+               bool whatever,
+               bool whatever2)
+    : Has_Block(pstate, 0),
+      name_(n),
+      parameters_(params),
+      environment_(0),
+      type_(FUNCTION),
+      native_function_(0),
+      c_function_(c_func),
+      cookie_(sass_function_get_cookie(c_func)),
+      is_overload_stub_(false),
+      signature_(sig)
+    { }
+    ATTACH_AST_OPERATIONS(Definition)
+    ATTACH_OPERATIONS()
+  };
+
+  //////////////////////////////////////
+  // Mixin calls (i.e., `@include ...`).
+  //////////////////////////////////////
+  class Mixin_Call : public Has_Block {
+    ADD_PROPERTY(std::string, name)
+    ADD_PROPERTY(Arguments_Obj, arguments)
+  public:
+    Mixin_Call(ParserState pstate, std::string n, Arguments_Obj args, Block_Obj b = 0)
+    : Has_Block(pstate, b), name_(n), arguments_(args)
+    { }
+    Mixin_Call(const Mixin_Call* ptr)
+    : Has_Block(ptr),
+      name_(ptr->name_),
+      arguments_(ptr->arguments_)
+    { }
+    ATTACH_AST_OPERATIONS(Mixin_Call)
+    ATTACH_OPERATIONS()
+  };
+
+  ///////////////////////////////////////////////////
+  // The @content directive for mixin content blocks.
+  ///////////////////////////////////////////////////
+  class Content : public Statement {
+    ADD_PROPERTY(Media_Block_Obj, media_block)
+  public:
+    Content(ParserState pstate) : Statement(pstate)
+    { statement_type(CONTENT); }
+    Content(const Content* ptr) : Statement(ptr)
+    { statement_type(CONTENT); }
+    ATTACH_AST_OPERATIONS(Content)
+    ATTACH_OPERATIONS()
+  };
+
+  ///////////////////////////////////////////////////////////////////////
+  // Lists of values, both comma- and space-separated (distinguished by a
+  // type-tag.) Also used to represent variable-length argument lists.
+  ///////////////////////////////////////////////////////////////////////
+  class List : public Value, public Vectorized<Expression_Obj> {
+    void adjust_after_pushing(Expression_Obj e) { is_expanded(false); }
+  private:
+    ADD_PROPERTY(enum Sass_Separator, separator)
+    ADD_PROPERTY(bool, is_arglist)
+    ADD_PROPERTY(bool, from_selector)
+  public:
+    List(ParserState pstate,
+         size_t size = 0, enum Sass_Separator sep = SASS_SPACE, bool argl = false)
+    : Value(pstate),
+      Vectorized<Expression_Obj>(size),
+      separator_(sep),
+      is_arglist_(argl),
+      from_selector_(false)
+    { concrete_type(LIST); }
+    List(const List* ptr)
+    : Value(ptr),
+      Vectorized<Expression_Obj>(*ptr),
+      separator_(ptr->separator_),
+      is_arglist_(ptr->is_arglist_),
+      from_selector_(ptr->from_selector_)
+    { concrete_type(LIST); }
+    std::string type() { 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(); }
+    Expression_Obj value_at_index(size_t i);
+
+    virtual size_t size() const;
+
+    virtual size_t hash()
+    {
+      if (hash_ == 0) {
+        hash_ = std::hash<std::string>()(sep_string());
+        for (size_t i = 0, L = length(); i < L; ++i)
+          hash_combine(hash_, (elements()[i])->hash());
+      }
+      return hash_;
+    }
+
+    virtual void set_delayed(bool delayed)
+    {
+      is_delayed(delayed);
+      // don't set children
+    }
+
+    virtual bool operator== (const Expression& rhs) const;
+
+    ATTACH_AST_OPERATIONS(List)
+    ATTACH_OPERATIONS()
+  };
+
+  ///////////////////////////////////////////////////////////////////////
+  // Key value paris.
+  ///////////////////////////////////////////////////////////////////////
+  class Map : public Value, public Hashed {
+    void adjust_after_pushing(std::pair<Expression_Obj, Expression_Obj> p) { is_expanded(false); }
+  public:
+    Map(ParserState pstate,
+         size_t size = 0)
+    : Value(pstate),
+      Hashed(size)
+    { concrete_type(MAP); }
+    Map(const Map* ptr)
+    : Value(ptr),
+      Hashed(*ptr)
+    { concrete_type(MAP); }
+    std::string type() { return "map"; }
+    static std::string type_name() { return "map"; }
+    bool is_invisible() const { return empty(); }
+    List_Obj to_list(Context& ctx, ParserState& pstate);
+
+    virtual size_t hash()
+    {
+      if (hash_ == 0) {
+        for (auto key : keys()) {
+          hash_combine(hash_, key->hash());
+          hash_combine(hash_, at(key)->hash());
+        }
+      }
+
+      return hash_;
+    }
+
+    virtual bool operator== (const Expression& rhs) const;
+
+    ATTACH_AST_OPERATIONS(Map)
+    ATTACH_OPERATIONS()
+  };
+
+  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;
+      // this is only used internally!
+      case NUM_OPS: return "[OPS]"; break;
+      default: return "invalid"; break;
+    }
+  }
+
+  //////////////////////////////////////////////////////////////////////////
+  // Binary expressions. Represents logical, relational, and arithmetic
+  // operations. Templatized to avoid large switch statements and repetitive
+  // subclassing.
+  //////////////////////////////////////////////////////////////////////////
+  class Binary_Expression : public PreValue {
+  private:
+    ADD_HASHED(Operand, op)
+    ADD_HASHED(Expression_Obj, left)
+    ADD_HASHED(Expression_Obj, right)
+    size_t hash_;
+  public:
+    Binary_Expression(ParserState pstate,
+                      Operand op, Expression_Obj lhs, Expression_Obj rhs)
+    : PreValue(pstate), op_(op), left_(lhs), right_(rhs), hash_(0)
+    { }
+    Binary_Expression(const Binary_Expression* ptr)
+    : PreValue(ptr),
+      op_(ptr->op_),
+      left_(ptr->left_),
+      right_(ptr->right_),
+      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;
+      }
+    }
+    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;
+      }
+    }
+    bool is_left_interpolant(void) const;
+    bool is_right_interpolant(void) const;
+    bool has_interpolant() const
+    {
+      return is_left_interpolant() ||
+             is_right_interpolant();
+    }
+    virtual void set_delayed(bool delayed)
+    {
+      right()->set_delayed(delayed);
+      left()->set_delayed(delayed);
+      is_delayed(delayed);
+    }
+    virtual bool operator==(const Expression& rhs) const
+    {
+      try
+      {
+        Binary_Expression_Ptr_Const m = dynamic_cast<Binary_Expression_Ptr_Const>(&rhs);
+        if (m == 0) return false;
+        return type() == m->type() &&
+               left() == m->left() &&
+               right() == m->right();
+      }
+      catch (std::bad_cast&)
+      {
+        return false;
+      }
+      catch (...) { throw; }
+    }
+    virtual size_t hash()
+    {
+      if (hash_ == 0) {
+        hash_ = std::hash<size_t>()(type());
+        hash_combine(hash_, left()->hash());
+        hash_combine(hash_, right()->hash());
+      }
+      return hash_;
+    }
+    enum Sass_OP type() const { return op_.operand; }
+    ATTACH_AST_OPERATIONS(Binary_Expression)
+    ATTACH_OPERATIONS()
+  };
+
+  ////////////////////////////////////////////////////////////////////////////
+  // Arithmetic negation (logical negation is just an ordinary function call).
+  ////////////////////////////////////////////////////////////////////////////
+  class Unary_Expression : public Expression {
+  public:
+    enum Type { PLUS, MINUS, NOT };
+  private:
+    ADD_HASHED(Type, type)
+    ADD_HASHED(Expression_Obj, operand)
+    size_t hash_;
+  public:
+    Unary_Expression(ParserState pstate, Type t, Expression_Obj o)
+    : Expression(pstate), type_(t), operand_(o), hash_(0)
+    { }
+    Unary_Expression(const Unary_Expression* ptr)
+    : Expression(ptr),
+      type_(ptr->type_),
+      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;
+      }
+    }
+    virtual bool operator==(const Expression& rhs) const
+    {
+      try
+      {
+        Unary_Expression_Ptr_Const m = dynamic_cast<Unary_Expression_Ptr_Const>(&rhs);
+        if (m == 0) return false;
+        return type() == m->type() &&
+               operand() == m->operand();
+      }
+      catch (std::bad_cast&)
+      {
+        return false;
+      }
+      catch (...) { throw; }
+    }
+    virtual size_t hash()
+    {
+      if (hash_ == 0) {
+        hash_ = std::hash<size_t>()(type_);
+        hash_combine(hash_, operand()->hash());
+      };
+      return hash_;
+    }
+    ATTACH_AST_OPERATIONS(Unary_Expression)
+    ATTACH_OPERATIONS()
+  };
+
+  ////////////////////////////////////////////////////////////
+  // Individual argument objects for mixin and function calls.
+  ////////////////////////////////////////////////////////////
+  class Argument : public Expression {
+    ADD_HASHED(Expression_Obj, value)
+    ADD_HASHED(std::string, name)
+    ADD_PROPERTY(bool, is_rest_argument)
+    ADD_PROPERTY(bool, is_keyword_argument)
+    size_t hash_;
+  public:
+    Argument(ParserState pstate, Expression_Obj val, std::string n = "", bool rest = false, bool keyword = false)
+    : 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_);
+      }
+    }
+    Argument(const Argument* ptr)
+    : Expression(ptr),
+      value_(ptr->value_),
+      name_(ptr->name_),
+      is_rest_argument_(ptr->is_rest_argument_),
+      is_keyword_argument_(ptr->is_keyword_argument_),
+      hash_(ptr->hash_)
+    {
+      if (!name_.empty() && is_rest_argument_) {
+        error("variable-length argument may not be passed by name", pstate_);
+      }
+    }
+
+    virtual void set_delayed(bool delayed);
+    virtual bool operator==(const Expression& rhs) const
+    {
+      try
+      {
+        Argument_Ptr_Const m = dynamic_cast<Argument_Ptr_Const>(&rhs);
+        if (!(m && name() == m->name())) return false;
+        return *value() == *m->value();
+      }
+      catch (std::bad_cast&)
+      {
+        return false;
+      }
+      catch (...) { throw; }
+    }
+
+    virtual size_t hash()
+    {
+      if (hash_ == 0) {
+        hash_ = std::hash<std::string>()(name());
+        hash_combine(hash_, value()->hash());
+      }
+      return hash_;
+    }
+
+    ATTACH_AST_OPERATIONS(Argument)
+    ATTACH_OPERATIONS()
+  };
+
+  ////////////////////////////////////////////////////////////////////////
+  // Argument lists -- in their own class to facilitate context-sensitive
+  // error checking (e.g., ensuring that all ordinal arguments precede all
+  // named arguments).
+  ////////////////////////////////////////////////////////////////////////
+  class Arguments : public Expression, public Vectorized<Argument_Obj> {
+    ADD_PROPERTY(bool, has_named_arguments)
+    ADD_PROPERTY(bool, has_rest_argument)
+    ADD_PROPERTY(bool, has_keyword_argument)
+  protected:
+    void adjust_after_pushing(Argument_Obj a);
+  public:
+    Arguments(ParserState pstate)
+    : Expression(pstate),
+      Vectorized<Argument_Obj>(),
+      has_named_arguments_(false),
+      has_rest_argument_(false),
+      has_keyword_argument_(false)
+    { }
+    Arguments(const Arguments* ptr)
+    : Expression(ptr),
+      Vectorized<Argument_Obj>(*ptr),
+      has_named_arguments_(ptr->has_named_arguments_),
+      has_rest_argument_(ptr->has_rest_argument_),
+      has_keyword_argument_(ptr->has_keyword_argument_)
+    { }
+
+    virtual void set_delayed(bool delayed);
+
+    Argument_Obj get_rest_argument();
+    Argument_Obj get_keyword_argument();
+
+    ATTACH_AST_OPERATIONS(Arguments)
+    ATTACH_OPERATIONS()
+  };
+
+  //////////////////
+  // Function calls.
+  //////////////////
+  class Function_Call : public PreValue {
+    ADD_HASHED(std::string, name)
+    ADD_HASHED(Arguments_Obj, arguments)
+    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)
+    { 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); }
+    Function_Call(const Function_Call* ptr)
+    : PreValue(ptr),
+      name_(ptr->name_),
+      arguments_(ptr->arguments_),
+      via_call_(ptr->via_call_),
+      cookie_(ptr->cookie_),
+      hash_(ptr->hash_)
+    { concrete_type(FUNCTION); }
+
+    virtual bool operator==(const Expression& rhs) const
+    {
+      try
+      {
+        Function_Call_Ptr_Const m = dynamic_cast<Function_Call_Ptr_Const>(&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;
+        return true;
+      }
+      catch (std::bad_cast&)
+      {
+        return false;
+      }
+      catch (...) { throw; }
+    }
+
+    virtual size_t hash()
+    {
+      if (hash_ == 0) {
+        hash_ = std::hash<std::string>()(name());
+        for (auto argument : arguments()->elements())
+          hash_combine(hash_, argument->hash());
+      }
+      return hash_;
+    }
+    ATTACH_AST_OPERATIONS(Function_Call)
+    ATTACH_OPERATIONS()
+  };
+
+  /////////////////////////
+  // Function call schemas.
+  /////////////////////////
+  class Function_Call_Schema : public Expression {
+    ADD_PROPERTY(String_Obj, name)
+    ADD_PROPERTY(Arguments_Obj, arguments)
+  public:
+    Function_Call_Schema(ParserState pstate, String_Obj n, Arguments_Obj args)
+    : Expression(pstate), name_(n), arguments_(args)
+    { concrete_type(STRING); }
+    Function_Call_Schema(const Function_Call_Schema* ptr)
+    : Expression(ptr),
+      name_(ptr->name_),
+      arguments_(ptr->arguments_)
+    { concrete_type(STRING); }
+    ATTACH_AST_OPERATIONS(Function_Call_Schema)
+    ATTACH_OPERATIONS()
+  };
+
+  ///////////////////////
+  // Variable references.
+  ///////////////////////
+  class Variable : public PreValue {
+    ADD_PROPERTY(std::string, name)
+  public:
+    Variable(ParserState pstate, std::string n)
+    : PreValue(pstate), name_(n)
+    { }
+    Variable(const Variable* ptr)
+    : PreValue(ptr), name_(ptr->name_)
+    { }
+
+    virtual bool operator==(const Expression& rhs) const
+    {
+      try
+      {
+        Variable_Ptr_Const e = dynamic_cast<Variable_Ptr_Const>(&rhs);
+        return e && name() == e->name();
+      }
+      catch (std::bad_cast&)
+      {
+        return false;
+      }
+      catch (...) { throw; }
+    }
+
+    virtual size_t hash()
+    {
+      return std::hash<std::string>()(name());
+    }
+
+    ATTACH_AST_OPERATIONS(Variable)
+    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)
+    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),
+      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"; }
+    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;
+
+    virtual size_t hash()
+    {
+      if (hash_ == 0) {
+        hash_ = std::hash<double>()(value_);
+        for (const auto numerator : numerator_units())
+          hash_combine(hash_, std::hash<std::string>()(numerator));
+        for (const auto denominator : denominator_units())
+          hash_combine(hash_, std::hash<std::string>()(denominator));
+      }
+      return hash_;
+    }
+
+    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()
+  };
+
+  //////////
+  // 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)
+    size_t hash_;
+  public:
+    Color(ParserState pstate, double r, double g, double b, double a = 1, const std::string disp = "")
+    : Value(pstate), r_(r), g_(g), b_(b), a_(a), disp_(disp),
+      hash_(0)
+    { concrete_type(COLOR); }
+    Color(const Color* ptr)
+    : Value(ptr),
+      r_(ptr->r_),
+      g_(ptr->g_),
+      b_(ptr->b_),
+      a_(ptr->a_),
+      disp_(ptr->disp_),
+      hash_(ptr->hash_)
+    { concrete_type(COLOR); }
+    std::string type() { return "color"; }
+    static std::string type_name() { return "color"; }
+
+    virtual size_t hash()
+    {
+      if (hash_ == 0) {
+        hash_ = std::hash<double>()(a_);
+        hash_combine(hash_, std::hash<double>()(r_));
+        hash_combine(hash_, std::hash<double>()(g_));
+        hash_combine(hash_, std::hash<double>()(b_));
+      }
+      return hash_;
+    }
+
+    virtual bool operator== (const Expression& rhs) const;
+
+    ATTACH_AST_OPERATIONS(Color)
+    ATTACH_OPERATIONS()
+  };
+
+  //////////////////////////////
+  // Errors from Sass_Values.
+  //////////////////////////////
+  class Custom_Error : public Value {
+    ADD_PROPERTY(std::string, message)
+  public:
+    Custom_Error(ParserState pstate, std::string msg)
+    : Value(pstate), message_(msg)
+    { concrete_type(C_ERROR); }
+    Custom_Error(const Custom_Error* ptr)
+    : Value(ptr), message_(ptr->message_)
+    { concrete_type(C_ERROR); }
+    virtual bool operator== (const Expression& rhs) const;
+    ATTACH_AST_OPERATIONS(Custom_Error)
+    ATTACH_OPERATIONS()
+  };
+
+  //////////////////////////////
+  // Warnings from Sass_Values.
+  //////////////////////////////
+  class Custom_Warning : public Value {
+    ADD_PROPERTY(std::string, message)
+  public:
+    Custom_Warning(ParserState pstate, std::string msg)
+    : Value(pstate), message_(msg)
+    { concrete_type(C_WARNING); }
+    Custom_Warning(const Custom_Warning* ptr)
+    : Value(ptr), message_(ptr->message_)
+    { concrete_type(C_WARNING); }
+    virtual bool operator== (const Expression& rhs) const;
+    ATTACH_AST_OPERATIONS(Custom_Warning)
+    ATTACH_OPERATIONS()
+  };
+
+  ////////////
+  // Booleans.
+  ////////////
+  class Boolean : public Value {
+    ADD_HASHED(bool, value)
+    size_t hash_;
+  public:
+    Boolean(ParserState pstate, bool val)
+    : Value(pstate), value_(val),
+      hash_(0)
+    { concrete_type(BOOLEAN); }
+    Boolean(const Boolean* ptr)
+    : Value(ptr),
+      value_(ptr->value_),
+      hash_(ptr->hash_)
+    { concrete_type(BOOLEAN); }
+    virtual operator bool() { return value_; }
+    std::string type() { return "bool"; }
+    static std::string type_name() { return "bool"; }
+    virtual bool is_false() { return !value_; }
+
+    virtual size_t hash()
+    {
+      if (hash_ == 0) {
+        hash_ = std::hash<bool>()(value_);
+      }
+      return hash_;
+    }
+
+    virtual bool operator== (const Expression& rhs) const;
+
+    ATTACH_AST_OPERATIONS(Boolean)
+    ATTACH_OPERATIONS()
+  };
+
+  ////////////////////////////////////////////////////////////////////////
+  // Abstract base class for Sass string values. Includes interpolated and
+  // "flat" strings.
+  ////////////////////////////////////////////////////////////////////////
+  class String : public Value {
+  public:
+    String(ParserState pstate, bool delayed = false)
+    : Value(pstate, delayed)
+    { concrete_type(STRING); }
+    String(const String* ptr)
+    : Value(ptr)
+    { concrete_type(STRING); }
+    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();
+    };
+    ATTACH_VIRTUAL_AST_OPERATIONS(String);
+    ATTACH_OPERATIONS()
+  };
+  inline String::~String() { };
+
+  ///////////////////////////////////////////////////////////////////////
+  // Interpolated strings. Meant to be reduced to flat strings during the
+  // evaluation phase.
+  ///////////////////////////////////////////////////////////////////////
+  class String_Schema : public String, public Vectorized<Expression_Obj> {
+    // ADD_PROPERTY(bool, has_interpolants)
+    size_t hash_;
+  public:
+    String_Schema(ParserState pstate, size_t size = 0, bool has_interpolants = false)
+    : String(pstate), Vectorized<Expression_Obj>(size), hash_(0)
+    { concrete_type(STRING); }
+    String_Schema(const String_Schema* ptr)
+    : String(ptr),
+      Vectorized<Expression_Obj>(*ptr),
+      hash_(ptr->hash_)
+    { concrete_type(STRING); }
+
+    std::string type() { return "string"; }
+    static std::string type_name() { return "string"; }
+
+    bool is_left_interpolant(void) const;
+    bool is_right_interpolant(void) const;
+    // void has_interpolants(bool tc) { }
+    bool has_interpolants() {
+      for (auto el : elements()) {
+        if (el->is_interpolant()) return true;
+      }
+      return false;
+    }
+    virtual void rtrim();
+    virtual void ltrim();
+    virtual void trim();
+
+    virtual size_t hash()
+    {
+      if (hash_ == 0) {
+        for (auto string : elements())
+          hash_combine(hash_, string->hash());
+      }
+      return hash_;
+    }
+
+    virtual void set_delayed(bool delayed) {
+      is_delayed(delayed);
+    }
+
+    virtual bool operator==(const Expression& rhs) const;
+    ATTACH_AST_OPERATIONS(String_Schema)
+    ATTACH_OPERATIONS()
+  };
+
+  ////////////////////////////////////////////////////////
+  // Flat strings -- the lowest level of raw textual data.
+  ////////////////////////////////////////////////////////
+  class String_Constant : public String {
+    ADD_PROPERTY(char, quote_mark)
+    ADD_PROPERTY(bool, can_compress_whitespace)
+    ADD_HASHED(std::string, value)
+  protected:
+    size_t hash_;
+  public:
+    String_Constant(const String_Constant* ptr)
+    : String(ptr),
+      quote_mark_(ptr->quote_mark_),
+      can_compress_whitespace_(ptr->can_compress_whitespace_),
+      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, 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, 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 Token& tok)
+    : String(pstate), quote_mark_(0), can_compress_whitespace_(false), value_(read_css_string(std::string(tok.begin, tok.end))), hash_(0)
+    { }
+    std::string type() { 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()
+    {
+      if (hash_ == 0) {
+        hash_ = std::hash<std::string>()(value_);
+      }
+      return hash_;
+    }
+
+    virtual bool operator==(const Expression& rhs) const;
+    virtual std::string inspect() const; // quotes are forced on inspection
+
+    // static char auto_quote() { return '*'; }
+    static char double_quote() { return '"'; }
+    static char single_quote() { return '\''; }
+
+    ATTACH_AST_OPERATIONS(String_Constant)
+    ATTACH_OPERATIONS()
+  };
+
+  ////////////////////////////////////////////////////////
+  // Possibly quoted string (unquote on instantiation)
+  ////////////////////////////////////////////////////////
+  class String_Quoted : public String_Constant {
+  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)
+    {
+      if (skip_unquoting == false) {
+        value_ = unquote(value_, &quote_mark_, keep_utf8_escapes, strict_unquoting);
+      }
+      if (q && quote_mark_) quote_mark_ = q;
+    }
+    String_Quoted(const String_Quoted* ptr)
+    : String_Constant(ptr)
+    { }
+    virtual bool operator==(const Expression& rhs) const;
+    virtual std::string inspect() const; // quotes are forced on inspection
+    ATTACH_AST_OPERATIONS(String_Quoted)
+    ATTACH_OPERATIONS()
+  };
+
+  /////////////////
+  // Media queries.
+  /////////////////
+  class Media_Query : public Expression,
+                      public Vectorized<Media_Query_Expression_Obj> {
+    ADD_PROPERTY(String_Obj, media_type)
+    ADD_PROPERTY(bool, is_negated)
+    ADD_PROPERTY(bool, is_restricted)
+  public:
+    Media_Query(ParserState pstate,
+                String_Obj t = 0, size_t s = 0, bool n = false, bool r = false)
+    : Expression(pstate), Vectorized<Media_Query_Expression_Obj>(s),
+      media_type_(t), is_negated_(n), is_restricted_(r)
+    { }
+    Media_Query(const Media_Query* ptr)
+    : Expression(ptr),
+      Vectorized<Media_Query_Expression_Obj>(*ptr),
+      media_type_(ptr->media_type_),
+      is_negated_(ptr->is_negated_),
+      is_restricted_(ptr->is_restricted_)
+    { }
+    ATTACH_AST_OPERATIONS(Media_Query)
+    ATTACH_OPERATIONS()
+  };
+
+  ////////////////////////////////////////////////////
+  // Media expressions (for use inside media queries).
+  ////////////////////////////////////////////////////
+  class Media_Query_Expression : public Expression {
+    ADD_PROPERTY(Expression_Obj, feature)
+    ADD_PROPERTY(Expression_Obj, value)
+    ADD_PROPERTY(bool, is_interpolated)
+  public:
+    Media_Query_Expression(ParserState pstate,
+                           Expression_Obj f, Expression_Obj v, bool i = false)
+    : Expression(pstate), feature_(f), value_(v), is_interpolated_(i)
+    { }
+    Media_Query_Expression(const Media_Query_Expression* ptr)
+    : Expression(ptr),
+      feature_(ptr->feature_),
+      value_(ptr->value_),
+      is_interpolated_(ptr->is_interpolated_)
+    { }
+    ATTACH_AST_OPERATIONS(Media_Query_Expression)
+    ATTACH_OPERATIONS()
+  };
+
+  ////////////////////
+  // `@supports` rule.
+  ////////////////////
+  class Supports_Block : public Has_Block {
+    ADD_PROPERTY(Supports_Condition_Obj, condition)
+  public:
+    Supports_Block(ParserState pstate, Supports_Condition_Obj condition, Block_Obj block = 0)
+    : Has_Block(pstate, block), condition_(condition)
+    { statement_type(SUPPORTS); }
+    Supports_Block(const Supports_Block* ptr)
+    : Has_Block(ptr), condition_(ptr->condition_)
+    { statement_type(SUPPORTS); }
+    bool bubbles() { return true; }
+    ATTACH_AST_OPERATIONS(Supports_Block)
+    ATTACH_OPERATIONS()
+  };
+
+  //////////////////////////////////////////////////////
+  // The abstract superclass of all Supports conditions.
+  //////////////////////////////////////////////////////
+  class Supports_Condition : public Expression {
+  public:
+    Supports_Condition(ParserState pstate)
+    : Expression(pstate)
+    { }
+    Supports_Condition(const Supports_Condition* ptr)
+    : Expression(ptr)
+    { }
+    virtual bool needs_parens(Supports_Condition_Obj cond) const { return false; }
+    ATTACH_AST_OPERATIONS(Supports_Condition)
+    ATTACH_OPERATIONS()
+  };
+
+  ////////////////////////////////////////////////////////////
+  // An operator condition (e.g. `CONDITION1 and CONDITION2`).
+  ////////////////////////////////////////////////////////////
+  class Supports_Operator : public Supports_Condition {
+  public:
+    enum Operand { AND, OR };
+  private:
+    ADD_PROPERTY(Supports_Condition_Obj, left);
+    ADD_PROPERTY(Supports_Condition_Obj, right);
+    ADD_PROPERTY(Operand, operand);
+  public:
+    Supports_Operator(ParserState pstate, Supports_Condition_Obj l, Supports_Condition_Obj r, Operand o)
+    : Supports_Condition(pstate), left_(l), right_(r), operand_(o)
+    { }
+    Supports_Operator(const Supports_Operator* ptr)
+    : Supports_Condition(ptr),
+      left_(ptr->left_),
+      right_(ptr->right_),
+      operand_(ptr->operand_)
+    { }
+    virtual bool needs_parens(Supports_Condition_Obj cond) const;
+    ATTACH_AST_OPERATIONS(Supports_Operator)
+    ATTACH_OPERATIONS()
+  };
+
+  //////////////////////////////////////////
+  // A negation condition (`not CONDITION`).
+  //////////////////////////////////////////
+  class Supports_Negation : public Supports_Condition {
+  private:
+    ADD_PROPERTY(Supports_Condition_Obj, condition);
+  public:
+    Supports_Negation(ParserState pstate, Supports_Condition_Obj c)
+    : Supports_Condition(pstate), condition_(c)
+    { }
+    Supports_Negation(const Supports_Negation* ptr)
+    : Supports_Condition(ptr), condition_(ptr->condition_)
+    { }
+    virtual bool needs_parens(Supports_Condition_Obj cond) const;
+    ATTACH_AST_OPERATIONS(Supports_Negation)
+    ATTACH_OPERATIONS()
+  };
+
+  /////////////////////////////////////////////////////
+  // A declaration condition (e.g. `(feature: value)`).
+  /////////////////////////////////////////////////////
+  class Supports_Declaration : public Supports_Condition {
+  private:
+    ADD_PROPERTY(Expression_Obj, feature);
+    ADD_PROPERTY(Expression_Obj, value);
+  public:
+    Supports_Declaration(ParserState pstate, Expression_Obj f, Expression_Obj v)
+    : Supports_Condition(pstate), feature_(f), value_(v)
+    { }
+    Supports_Declaration(const Supports_Declaration* ptr)
+    : Supports_Condition(ptr),
+      feature_(ptr->feature_),
+      value_(ptr->value_)
+    { }
+    virtual bool needs_parens(Supports_Condition_Obj cond) const { return false; }
+    ATTACH_AST_OPERATIONS(Supports_Declaration)
+    ATTACH_OPERATIONS()
+  };
+
+  ///////////////////////////////////////////////
+  // An interpolation condition (e.g. `#{$var}`).
+  ///////////////////////////////////////////////
+  class Supports_Interpolation : public Supports_Condition {
+  private:
+    ADD_PROPERTY(Expression_Obj, value);
+  public:
+    Supports_Interpolation(ParserState pstate, Expression_Obj v)
+    : Supports_Condition(pstate), value_(v)
+    { }
+    Supports_Interpolation(const Supports_Interpolation* ptr)
+    : Supports_Condition(ptr),
+      value_(ptr->value_)
+    { }
+    virtual bool needs_parens(Supports_Condition_Obj cond) const { return false; }
+    ATTACH_AST_OPERATIONS(Supports_Interpolation)
+    ATTACH_OPERATIONS()
+  };
+
+  /////////////////////////////////////////////////
+  // At root expressions (for use inside @at-root).
+  /////////////////////////////////////////////////
+  class At_Root_Query : public Expression {
+  private:
+    ADD_PROPERTY(Expression_Obj, feature)
+    ADD_PROPERTY(Expression_Obj, value)
+  public:
+    At_Root_Query(ParserState pstate, Expression_Obj f = 0, Expression_Obj v = 0, bool i = false)
+    : Expression(pstate), feature_(f), value_(v)
+    { }
+    At_Root_Query(const At_Root_Query* ptr)
+    : Expression(ptr),
+      feature_(ptr->feature_),
+      value_(ptr->value_)
+    { }
+    bool exclude(std::string str);
+    ATTACH_AST_OPERATIONS(At_Root_Query)
+    ATTACH_OPERATIONS()
+  };
+
+  ///////////
+  // At-root.
+  ///////////
+  class At_Root_Block : public Has_Block {
+    ADD_PROPERTY(At_Root_Query_Obj, expression)
+  public:
+    At_Root_Block(ParserState pstate, Block_Obj b = 0, At_Root_Query_Obj e = 0)
+    : Has_Block(pstate, b), expression_(e)
+    { statement_type(ATROOT); }
+    At_Root_Block(const At_Root_Block* ptr)
+    : Has_Block(ptr), expression_(ptr->expression_)
+    { statement_type(ATROOT); }
+    bool bubbles() { return true; }
+    bool exclude_node(Statement_Obj s) {
+      if (expression() == 0)
+      {
+        return s->statement_type() == Statement::RULESET;
+      }
+
+      if (s->statement_type() == Statement::DIRECTIVE)
+      {
+        if (Directive_Obj dir = SASS_MEMORY_CAST(Directive, s))
+        {
+          std::string keyword(dir->keyword());
+          if (keyword.length() > 0) keyword.erase(0, 1);
+          return expression()->exclude(keyword);
+        }
+      }
+      if (s->statement_type() == Statement::MEDIA)
+      {
+        return expression()->exclude("media");
+      }
+      if (s->statement_type() == Statement::RULESET)
+      {
+        return expression()->exclude("rule");
+      }
+      if (s->statement_type() == Statement::SUPPORTS)
+      {
+        return expression()->exclude("supports");
+      }
+      if (Directive_Obj dir = SASS_MEMORY_CAST(Directive, s))
+      {
+        if (dir->is_keyframes()) return expression()->exclude("keyframes");
+      }
+      return false;
+    }
+    ATTACH_AST_OPERATIONS(At_Root_Block)
+    ATTACH_OPERATIONS()
+  };
+
+  //////////////////
+  // The null value.
+  //////////////////
+  class Null : public Value {
+  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"; }
+    static std::string type_name() { return "null"; }
+    bool is_invisible() const { return true; }
+    operator bool() { return false; }
+    bool is_false() { return true; }
+
+    virtual size_t hash()
+    {
+      return -1;
+    }
+
+    virtual bool operator== (const Expression& rhs) const;
+
+    ATTACH_AST_OPERATIONS(Null)
+    ATTACH_OPERATIONS()
+  };
+
+  /////////////////////////////////
+  // Thunks for delayed evaluation.
+  /////////////////////////////////
+  class Thunk : public Expression {
+    ADD_PROPERTY(Expression_Obj, expression)
+    ADD_PROPERTY(Env*, environment)
+  public:
+    Thunk(ParserState pstate, Expression_Obj exp, Env* env = 0)
+    : Expression(pstate), expression_(exp), environment_(env)
+    { }
+  };
+
+  /////////////////////////////////////////////////////////
+  // Individual parameter objects for mixins and functions.
+  /////////////////////////////////////////////////////////
+  class Parameter : public AST_Node {
+    ADD_PROPERTY(std::string, name)
+    ADD_PROPERTY(Expression_Obj, default_value)
+    ADD_PROPERTY(bool, is_rest_parameter)
+  public:
+    Parameter(ParserState pstate,
+              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_);
+      }
+    }
+    Parameter(const Parameter* ptr)
+    : AST_Node(ptr),
+      name_(ptr->name_),
+      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_);
+      }
+    }
+    ATTACH_AST_OPERATIONS(Parameter)
+    ATTACH_OPERATIONS()
+  };
+
+  /////////////////////////////////////////////////////////////////////////
+  // Parameter lists -- in their own class to facilitate context-sensitive
+  // error checking (e.g., ensuring that all optional parameters follow all
+  // required parameters).
+  /////////////////////////////////////////////////////////////////////////
+  class Parameters : public AST_Node, public Vectorized<Parameter_Obj> {
+    ADD_PROPERTY(bool, has_optional_parameters)
+    ADD_PROPERTY(bool, has_rest_parameter)
+  protected:
+    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());
+        }
+        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());
+        }
+        has_rest_parameter_ = true;
+      }
+      else {
+        if (has_rest_parameter_) {
+          error("required parameters must precede variable-length parameters", p->pstate());
+        }
+        if (has_optional_parameters_) {
+          error("required parameters must precede optional parameters", p->pstate());
+        }
+      }
+    }
+  public:
+    Parameters(ParserState pstate)
+    : AST_Node(pstate),
+      Vectorized<Parameter_Obj>(),
+      has_optional_parameters_(false),
+      has_rest_parameter_(false)
+    { }
+    Parameters(const Parameters* ptr)
+    : AST_Node(ptr),
+      Vectorized<Parameter_Obj>(*ptr),
+      has_optional_parameters_(ptr->has_optional_parameters_),
+      has_rest_parameter_(ptr->has_rest_parameter_)
+    { }
+    ATTACH_AST_OPERATIONS(Parameters)
+    ATTACH_OPERATIONS()
+  };
+
+  /////////////////////////////////////////
+  // Abstract base class for CSS selectors.
+  /////////////////////////////////////////
+  class Selector : public Expression {
+    // ADD_PROPERTY(bool, has_reference)
+    // line break before list separator
+    ADD_PROPERTY(bool, has_line_feed)
+    // line break after list separator
+    ADD_PROPERTY(bool, has_line_break)
+    // maybe we have optional flag
+    ADD_PROPERTY(bool, is_optional)
+    // parent block pointers
+
+    // must not be a reference counted object
+    // otherwise we create circular references
+    ADD_PROPERTY(Media_Block_Ptr, media_block)
+  protected:
+    size_t hash_;
+  public:
+    Selector(ParserState pstate, bool r = false, bool h = false)
+    : Expression(pstate),
+      // has_reference_(r),
+      has_line_feed_(false),
+      has_line_break_(false),
+      is_optional_(false),
+      media_block_(0),
+      hash_(0)
+    { concrete_type(SELECTOR); }
+    Selector(const Selector* ptr)
+    : Expression(ptr),
+      // has_reference_(ptr->has_reference_),
+      has_line_feed_(ptr->has_line_feed_),
+      has_line_break_(ptr->has_line_break_),
+      is_optional_(ptr->is_optional_),
+      media_block_(ptr->media_block_),
+      hash_(ptr->hash_)
+    { concrete_type(SELECTOR); }
+    virtual ~Selector() = 0;
+    virtual size_t hash() = 0;
+    virtual unsigned long specificity() {
+      return 0;
+    }
+    virtual void set_media_block(Media_Block_Ptr mb) {
+      media_block(mb);
+    }
+    virtual bool has_parent_ref() {
+      return false;
+    }
+    virtual bool has_real_parent_ref() {
+      return false;
+    }
+    // dispatch to correct handlers
+    virtual bool operator<(const Selector& rhs) const;
+    virtual bool operator==(const Selector& rhs) const;
+    ATTACH_VIRTUAL_AST_OPERATIONS(Selector);
+  };
+  inline Selector::~Selector() { }
+
+  /////////////////////////////////////////////////////////////////////////
+  // Interpolated selectors -- the interpolated String will be expanded and
+  // re-parsed into a normal selector class.
+  /////////////////////////////////////////////////////////////////////////
+  class Selector_Schema : public Selector {
+    ADD_PROPERTY(String_Obj, contents)
+    ADD_PROPERTY(bool, at_root);
+  public:
+    Selector_Schema(ParserState pstate, String_Obj c)
+    : Selector(pstate), contents_(c), at_root_(false)
+    { }
+    Selector_Schema(const Selector_Schema* ptr)
+    : Selector(ptr),
+      contents_(ptr->contents_),
+      at_root_(ptr->at_root_)
+    { }
+    virtual bool has_parent_ref();
+    virtual bool has_real_parent_ref();
+    virtual size_t hash() {
+      if (hash_ == 0) {
+        hash_combine(hash_, contents_->hash());
+      }
+      return hash_;
+    }
+    ATTACH_AST_OPERATIONS(Selector_Schema)
+    ATTACH_OPERATIONS()
+  };
+
+  ////////////////////////////////////////////
+  // Abstract base class for simple selectors.
+  ////////////////////////////////////////////
+  class Simple_Selector : public Selector {
+    ADD_PROPERTY(std::string, ns)
+    ADD_PROPERTY(std::string, name)
+    ADD_PROPERTY(Simple_Type, simple_type)
+    ADD_PROPERTY(bool, has_ns)
+  public:
+    Simple_Selector(ParserState pstate, std::string n = "")
+    : Selector(pstate), ns_(""), name_(n), has_ns_(false)
+    {
+      simple_type(SIMPLE);
+      size_t pos = n.find('|');
+      // found some namespace
+      if (pos != std::string::npos) {
+        has_ns_ = true;
+        ns_ = n.substr(0, pos);
+        name_ = n.substr(pos + 1);
+      }
+    }
+    Simple_Selector(const Simple_Selector* ptr)
+    : Selector(ptr),
+      ns_(ptr->ns_),
+      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("");
+      if (has_ns_)
+        name += ns_ + "|";
+      return name + name_;
+    }
+    virtual size_t hash()
+    {
+      if (hash_ == 0) {
+        hash_combine(hash_, std::hash<int>()(SELECTOR));
+        hash_combine(hash_, std::hash<std::string>()(ns()));
+        hash_combine(hash_, std::hash<std::string>()(name()));
+      }
+      return hash_;
+    }
+    // namespace query functions
+    bool is_universal_ns() const
+    {
+      return has_ns_ && ns_ == "*";
+    }
+    bool has_universal_ns() const
+    {
+      return !has_ns_ || ns_ == "*";
+    }
+    bool is_empty_ns() const
+    {
+      return !has_ns_ || ns_ == "";
+    }
+    bool has_empty_ns() const
+    {
+      return has_ns_ && ns_ == "";
+    }
+    bool has_qualified_ns() const
+    {
+      return has_ns_ && ns_ != "" && ns_ != "*";
+    }
+    // name query functions
+    bool is_universal() const
+    {
+      return name_ == "*";
+    }
+
+    virtual bool has_placeholder() {
+      return false;
+    }
+
+    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 bool is_superselector_of(Compound_Selector_Obj sub) { return false; }
+
+    virtual bool operator==(const Selector& rhs) const;
+    virtual bool operator==(const Simple_Selector& rhs) const;
+    inline bool operator!=(const Simple_Selector& rhs) const { return !(*this == rhs); }
+
+    bool operator<(const Selector& rhs) const;
+    bool operator<(const Simple_Selector& rhs) const;
+    // default implementation should work for most of the simple selectors (otherwise overload)
+    ATTACH_VIRTUAL_AST_OPERATIONS(Simple_Selector);
+    ATTACH_OPERATIONS();
+  };
+  inline Simple_Selector::~Simple_Selector() { }
+
+
+  //////////////////////////////////
+  // The Parent Selector Expression.
+  //////////////////////////////////
+  // parent selectors can occur in selectors but also
+  // inside strings in declarations (Compound_Selector).
+  // only one simple parent selector means the first case.
+  class Parent_Selector : public Simple_Selector {
+    ADD_PROPERTY(bool, real)
+  public:
+    Parent_Selector(ParserState pstate, bool r = true)
+    : Simple_Selector(pstate, "&"), real_(r)
+    { /* has_reference(true); */ }
+    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()
+    {
+      return 0;
+    }
+    std::string type() { return "selector"; }
+    static std::string type_name() { return "selector"; }
+    ATTACH_AST_OPERATIONS(Parent_Selector)
+    ATTACH_OPERATIONS()
+  };
+
+  /////////////////////////////////////////////////////////////////////////
+  // Placeholder selectors (e.g., "%foo") for use in extend-only selectors.
+  /////////////////////////////////////////////////////////////////////////
+  class Placeholder_Selector : public Simple_Selector {
+  public:
+    Placeholder_Selector(ParserState pstate, std::string n)
+    : Simple_Selector(pstate, n)
+    { }
+    Placeholder_Selector(const Placeholder_Selector* ptr)
+    : Simple_Selector(ptr)
+    { }
+    virtual unsigned long specificity()
+    {
+      return Constants::Specificity_Base;
+    }
+    virtual bool has_placeholder() {
+      return true;
+    }
+    virtual ~Placeholder_Selector() {};
+    ATTACH_AST_OPERATIONS(Placeholder_Selector)
+    ATTACH_OPERATIONS()
+  };
+
+  /////////////////////////////////////////////////////////////////////
+  // Element selectors (and the universal selector) -- e.g., div, span, *.
+  /////////////////////////////////////////////////////////////////////
+  class Element_Selector : public Simple_Selector {
+  public:
+    Element_Selector(ParserState pstate, std::string n)
+    : Simple_Selector(pstate, n)
+    { }
+    Element_Selector(const Element_Selector* ptr)
+    : Simple_Selector(ptr)
+    { }
+    virtual unsigned long specificity()
+    {
+      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&);
+    ATTACH_AST_OPERATIONS(Element_Selector)
+    ATTACH_OPERATIONS()
+  };
+
+  ////////////////////////////////////////////////
+  // Class selectors  -- i.e., .foo.
+  ////////////////////////////////////////////////
+  class Class_Selector : public Simple_Selector {
+  public:
+    Class_Selector(ParserState pstate, std::string n)
+    : Simple_Selector(pstate, n)
+    { }
+    Class_Selector(const Class_Selector* ptr)
+    : Simple_Selector(ptr)
+    { }
+    virtual bool unique() const
+    {
+      return false;
+    }
+    virtual unsigned long specificity()
+    {
+      return Constants::Specificity_Class;
+    }
+    virtual Compound_Selector_Ptr unify_with(Compound_Selector_Ptr, Context&);
+    ATTACH_AST_OPERATIONS(Class_Selector)
+    ATTACH_OPERATIONS()
+  };
+
+  ////////////////////////////////////////////////
+  // ID selectors -- i.e., #foo.
+  ////////////////////////////////////////////////
+  class Id_Selector : public Simple_Selector {
+  public:
+    Id_Selector(ParserState pstate, std::string n)
+    : Simple_Selector(pstate, n)
+    { }
+    Id_Selector(const Id_Selector* ptr)
+    : Simple_Selector(ptr)
+    { }
+    virtual bool unique() const
+    {
+      return true;
+    }
+    virtual unsigned long specificity()
+    {
+      return Constants::Specificity_ID;
+    }
+    virtual Compound_Selector_Ptr unify_with(Compound_Selector_Ptr, Context&);
+    ATTACH_AST_OPERATIONS(Id_Selector)
+    ATTACH_OPERATIONS()
+  };
+
+  ///////////////////////////////////////////////////
+  // Attribute selectors -- e.g., [src*=".jpg"], etc.
+  ///////////////////////////////////////////////////
+  class Attribute_Selector : public Simple_Selector {
+    ADD_PROPERTY(std::string, matcher)
+    // this cannot be changed to obj atm!!!!!!????!!!!!!!
+    ADD_PROPERTY(String_Obj, value) // might be interpolated
+  public:
+    Attribute_Selector(ParserState pstate, std::string n, std::string m, String_Obj v)
+    : Simple_Selector(pstate, n), matcher_(m), value_(v)
+    { simple_type(ATTR_SEL); }
+    Attribute_Selector(const Attribute_Selector* ptr)
+    : Simple_Selector(ptr),
+      matcher_(ptr->matcher_),
+      value_(ptr->value_)
+    { simple_type(ATTR_SEL); }
+    virtual size_t hash()
+    {
+      if (hash_ == 0) {
+        hash_combine(hash_, Simple_Selector::hash());
+        hash_combine(hash_, std::hash<std::string>()(matcher()));
+        if (value_) hash_combine(hash_, value_->hash());
+      }
+      return hash_;
+    }
+    virtual unsigned long specificity()
+    {
+      return Constants::Specificity_Attr;
+    }
+    virtual bool operator==(const Simple_Selector& rhs) const;
+    virtual bool operator==(const Attribute_Selector& rhs) const;
+    virtual bool operator<(const Simple_Selector& rhs) const;
+    virtual bool operator<(const Attribute_Selector& rhs) const;
+    ATTACH_AST_OPERATIONS(Attribute_Selector)
+    ATTACH_OPERATIONS()
+  };
+
+  //////////////////////////////////////////////////////////////////
+  // Pseudo selectors -- e.g., :first-child, :nth-of-type(...), etc.
+  //////////////////////////////////////////////////////////////////
+  /* '::' starts a pseudo-element, ':' a pseudo-class */
+  /* Except :first-line, :first-letter, :before and :after */
+  /* Note that pseudo-elements are restricted to one per selector */
+  /* and occur only in the last simple_selector_sequence. */
+  inline bool is_pseudo_class_element(const std::string& name)
+  {
+    return name == ":before"       ||
+           name == ":after"        ||
+           name == ":first-line"   ||
+           name == ":first-letter";
+  }
+
+  // Pseudo Selector cannot have any namespace?
+  class Pseudo_Selector : public Simple_Selector {
+    ADD_PROPERTY(String_Obj, expression)
+  public:
+    Pseudo_Selector(ParserState pstate, std::string n, String_Obj expr = 0)
+    : Simple_Selector(pstate, n), expression_(expr)
+    { simple_type(PSEUDO_SEL); }
+    Pseudo_Selector(const Pseudo_Selector* ptr)
+    : 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.
+    // For compatibility with existing style sheets, user agents must also
+    // accept the previous one-colon notation for pseudo-elements introduced
+    // 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()
+    {
+      return (name_[0] == ':' && name_[1] == ':')
+             || is_pseudo_class_element(name_);
+    }
+    virtual size_t hash()
+    {
+      if (hash_ == 0) {
+        hash_combine(hash_, Simple_Selector::hash());
+        if (expression_) hash_combine(hash_, expression_->hash());
+      }
+      return hash_;
+    }
+    virtual unsigned long specificity()
+    {
+      if (is_pseudo_element())
+        return Constants::Specificity_Element;
+      return Constants::Specificity_Pseudo;
+    }
+    virtual bool operator==(const Simple_Selector& rhs) const;
+    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&);
+    ATTACH_AST_OPERATIONS(Pseudo_Selector)
+    ATTACH_OPERATIONS()
+  };
+
+  /////////////////////////////////////////////////
+  // 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)
+  public:
+    Wrapped_Selector(ParserState pstate, std::string n, Selector_Obj sel)
+    : Simple_Selector(pstate, n), selector_(sel)
+    { simple_type(WRAPPED_SEL); }
+    Wrapped_Selector(const Wrapped_Selector* ptr)
+    : Simple_Selector(ptr), selector_(ptr->selector_)
+    { simple_type(WRAPPED_SEL); }
+    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 bool operator==(const Simple_Selector& rhs) const;
+    virtual bool operator==(const Wrapped_Selector& rhs) const;
+    virtual bool operator<(const Simple_Selector& rhs) const;
+    virtual bool operator<(const Wrapped_Selector& rhs) const;
+    virtual void cloneChildren();
+    ATTACH_AST_OPERATIONS(Wrapped_Selector)
+    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_;
+    ADD_PROPERTY(bool, extended);
+    ADD_PROPERTY(bool, has_parent_reference);
+  protected:
+    void adjust_after_pushing(Simple_Selector_Obj s)
+    {
+      // if (s->has_reference())   has_reference(true);
+      // if (s->has_placeholder()) has_placeholder(true);
+    }
+  public:
+    Compound_Selector(ParserState pstate, size_t s = 0)
+    : Selector(pstate),
+      Vectorized<Simple_Selector_Obj>(s),
+      extended_(false),
+      has_parent_reference_(false)
+    { }
+    Compound_Selector(const Compound_Selector* ptr)
+    : Selector(ptr),
+      Vectorized<Simple_Selector_Obj>(*ptr),
+      extended_(ptr->extended_),
+      has_parent_reference_(ptr->has_parent_reference_)
+    { }
+    bool contains_placeholder() {
+      for (size_t i = 0, L = length(); i < L; ++i) {
+        if ((*this)[i]->has_placeholder()) return true;
+      }
+      return false;
+    };
+
+    void append(Simple_Selector_Ptr element);
+
+    bool is_universal() const
+    {
+      return length() == 1 && (*this)[0]->is_universal();
+    }
+
+    Complex_Selector_Obj to_complex();
+    Compound_Selector_Ptr unify_with(Compound_Selector_Ptr rhs, Context& ctx);
+    // 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 {
+      if (length() == 0) return 0;
+      // ToDo: why is this needed?
+      if (SASS_MEMORY_CAST(Element_Selector, (*this)[0]))
+        return &(*this)[0];
+      return 0;
+    }
+    virtual bool is_superselector_of(Compound_Selector_Obj sub, std::string wrapped = "");
+    virtual bool is_superselector_of(Complex_Selector_Obj sub, std::string wrapped = "");
+    virtual bool is_superselector_of(Selector_List_Obj sub, std::string wrapped = "");
+    virtual size_t hash()
+    {
+      if (Selector::hash_ == 0) {
+        hash_combine(Selector::hash_, std::hash<int>()(SELECTOR));
+        if (length()) hash_combine(Selector::hash_, Vectorized::hash());
+      }
+      return Selector::hash_;
+    }
+    virtual unsigned long specificity()
+    {
+      int sum = 0;
+      for (size_t i = 0, L = length(); i < L; ++i)
+      { sum += (*this)[i]->specificity(); }
+      return sum;
+    }
+
+    virtual bool has_placeholder()
+    {
+      if (length() == 0) return false;
+      if (Simple_Selector_Obj ss = elements().front()) {
+        if (ss->has_placeholder()) return true;
+      }
+      return false;
+    }
+
+    bool is_empty_reference()
+    {
+      return length() == 1 &&
+             SASS_MEMORY_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 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_; }
+    void clearSources() { sources_.clear(); }
+    void mergeSources(SourcesSet& sources, Context& ctx);
+
+    Compound_Selector_Ptr minus(Compound_Selector_Ptr rhs, Context& ctx);
+    virtual void cloneChildren();
+    ATTACH_AST_OPERATIONS(Compound_Selector)
+    ATTACH_OPERATIONS()
+  };
+
+  ////////////////////////////////////////////////////////////////////////////
+  // General selectors -- i.e., simple sequences combined with one of the four
+  // CSS selector combinators (">", "+", "~", and whitespace). Essentially a
+  // linked list.
+  ////////////////////////////////////////////////////////////////////////////
+  class Complex_Selector : public Selector {
+  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);
+  public:
+    bool contains_placeholder() {
+      if (head() && head()->contains_placeholder()) return true;
+      if (tail() && tail()->contains_placeholder()) return true;
+      return false;
+    };
+    Complex_Selector(ParserState pstate,
+                     Combinator c = ANCESTOR_OF,
+                     Compound_Selector_Obj h = 0,
+                     Complex_Selector_Obj t = 0,
+                     String_Obj r = 0)
+    : Selector(pstate),
+      combinator_(c),
+      head_(h), tail_(t),
+      reference_(r)
+    {}
+    Complex_Selector(const Complex_Selector* ptr)
+    : Selector(ptr),
+      combinator_(ptr->combinator_),
+      head_(ptr->head_), tail_(ptr->tail_),
+      reference_(ptr->reference_)
+    {};
+    virtual bool has_parent_ref();
+    virtual bool has_real_parent_ref();
+
+    Complex_Selector_Obj skip_empty_reference()
+    {
+      if ((!head_ || !head_->length() || head_->is_empty_reference()) &&
+          combinator() == Combinator::ANCESTOR_OF)
+      {
+        if (!tail_) return 0;
+        tail_->has_line_feed_ = this->has_line_feed_;
+        // tail_->has_line_break_ = this->has_line_break_;
+        return tail_->skip_empty_reference();
+      }
+      return this;
+    }
+
+    // can still have a tail
+    bool is_empty_ancestor() const
+    {
+      return (!head() || head()->length() == 0) &&
+             combinator() == Combinator::ANCESTOR_OF;
+    }
+
+    Complex_Selector_Obj context(Context&);
+
+
+    Selector_List_Ptr tails(Context& ctx, Selector_List_Ptr tails);
+
+    // front returns the first real tail
+    // skips over parent and empty ones
+    Complex_Selector_Obj first();
+    // last returns the last real tail
+    Complex_Selector_Obj last();
+
+    // some shortcuts that should be removed
+    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);
+    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);
+    Combinator clear_innermost();
+    void append(Context&, Complex_Selector_Obj);
+    void set_innermost(Complex_Selector_Obj, Combinator);
+    virtual size_t hash()
+    {
+      if (hash_ == 0) {
+        hash_combine(hash_, std::hash<int>()(SELECTOR));
+        hash_combine(hash_, std::hash<int>()(combinator_));
+        if (head_) hash_combine(hash_, head_->hash());
+        if (tail_) hash_combine(hash_, tail_->hash());
+      }
+      return hash_;
+    }
+    virtual unsigned long specificity() const
+    {
+      int sum = 0;
+      if (head()) sum += head()->specificity();
+      if (tail()) sum += tail()->specificity();
+      return sum;
+    }
+    virtual void set_media_block(Media_Block_Ptr mb) {
+      media_block(mb);
+      if (tail_) tail_->set_media_block(mb);
+      if (head_) head_->set_media_block(mb);
+    }
+    virtual bool has_placeholder() {
+      if (head_ && head_->has_placeholder()) return true;
+      if (tail_ && tail_->has_placeholder()) return true;
+      return false;
+    }
+    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()
+    {
+      //s = Set.new
+      //seq.map {|sseq_or_op| s.merge sseq_or_op.sources if sseq_or_op.is_a?(SimpleSequence)}
+      //s
+
+      SourcesSet srcs;
+
+      Compound_Selector_Obj pHead = head();
+      Complex_Selector_Obj  pTail = tail();
+
+      if (pHead) {
+        SourcesSet& headSources = pHead->sources();
+        srcs.insert(headSources.begin(), headSources.end());
+      }
+
+      if (pTail) {
+        SourcesSet tailSources = pTail->sources();
+        srcs.insert(tailSources.begin(), tailSources.end());
+      }
+
+      return srcs;
+    }
+    void addSources(SourcesSet& sources, Context& ctx) {
+      // 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();
+
+        if (pHead) {
+          pHead->mergeSources(sources, ctx);
+        }
+
+        pIter = &pIter->tail();
+      }
+    }
+    void clearSources() {
+      Complex_Selector_Ptr pIter = this;
+      while (pIter) {
+        Compound_Selector_Ptr pHead = &pIter->head();
+
+        if (pHead) {
+          pHead->clearSources();
+        }
+
+        pIter = &pIter->tail();
+      }
+    }
+
+    virtual void cloneChildren();
+    ATTACH_AST_OPERATIONS(Complex_Selector)
+    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)
+  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_List(const Selector_List* ptr)
+    : Selector(ptr),
+      Vectorized<Complex_Selector_Obj>(*ptr),
+      wspace_(ptr->wspace_)
+    { }
+    std::string type() { return "list"; }
+    // remove parent selector references
+    // basically unwraps parsed selectors
+    virtual bool has_parent_ref();
+    virtual bool has_real_parent_ref();
+    void remove_parent_selectors();
+    Selector_List_Ptr resolve_parent_refs(Context& ctx, std::vector<Selector_List_Obj>& pstack, 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&);
+    virtual size_t hash()
+    {
+      if (Selector::hash_ == 0) {
+        hash_combine(Selector::hash_, std::hash<int>()(SELECTOR));
+        hash_combine(Selector::hash_, Vectorized::hash());
+      }
+      return Selector::hash_;
+    }
+    virtual unsigned long specificity()
+    {
+      unsigned long sum = 0;
+      unsigned long specificity = 0;
+      for (size_t i = 0, L = length(); i < L; ++i)
+      {
+        specificity = (*this)[i]->specificity();
+        if (sum < specificity) sum = specificity;
+      }
+      return sum;
+    }
+    virtual void set_media_block(Media_Block_Ptr mb) {
+      media_block(mb);
+      for (Complex_Selector_Obj cs : elements()) {
+        cs->set_media_block(mb);
+      }
+    }
+    virtual bool has_placeholder() {
+      for (Complex_Selector_Obj cs : elements()) {
+        if (cs->has_placeholder()) return true;
+      }
+      return false;
+    }
+    virtual bool operator<(const Selector& rhs) const;
+    virtual bool operator==(const Selector& rhs) const;
+    virtual bool operator<(const Selector_List& rhs) const;
+    virtual bool operator==(const Selector_List& rhs) const;
+    // Selector Lists can be compared to comma lists
+    virtual bool operator==(const Expression& rhs) const;
+    virtual void cloneChildren();
+    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); } };
+  struct cmp_compound_selector { inline bool operator() (const Compound_Selector_Obj l, const Compound_Selector_Obj r) { return (*l < *r); } };
+  struct cmp_simple_selector { inline bool operator() (const Simple_Selector_Obj l, const Simple_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
@@ -28,13 +28,13 @@
 
 #define ATTACH_OPERATIONS()\
 virtual void perform(Operation<void>* op) { (*op)(this); }\
-virtual AST_Node* perform(Operation<AST_Node*>* op) { return (*op)(this); }\
-virtual Statement* perform(Operation<Statement*>* op) { return (*op)(this); }\
-virtual Expression* perform(Operation<Expression*>* op) { return (*op)(this); }\
-virtual Selector* perform(Operation<Selector*>* op) { return (*op)(this); }\
+virtual AST_Node_Ptr perform(Operation<AST_Node_Ptr>* op) { return (*op)(this); }\
+virtual Statement_Ptr perform(Operation<Statement_Ptr>* op) { return (*op)(this); }\
+virtual Expression_Ptr perform(Operation<Expression_Ptr>* op) { return (*op)(this); }\
+virtual Selector_Ptr perform(Operation<Selector_Ptr>* op) { return (*op)(this); }\
 virtual std::string perform(Operation<std::string>* op) { return (*op)(this); }\
 virtual union Sass_Value* perform(Operation<union Sass_Value*>* op) { return (*op)(this); }\
-virtual Value* perform(Operation<Value*>* op) { return (*op)(this); }
+virtual Value_Ptr perform(Operation<Value_Ptr>* op) { return (*op)(this); }
 
 #define ADD_PROPERTY(type, name)\
 protected:\
diff --git a/libsass/src/ast_factory.hpp b/libsass/src/ast_factory.hpp
deleted file mode 100644
--- a/libsass/src/ast_factory.hpp
+++ /dev/null
@@ -1,93 +0,0 @@
-#ifndef SASS_AST_FACTORY_H
-#define SASS_AST_FACTORY_H
-
-#include <vector>
-
-#include "ast.hpp"
-
-namespace Sass {
-
-  class AST_Factory {
-    std::vector<AST_Node*> nodes;
-  public:
-    // statements
-    Block* new_Block(std::string p, size_t l, size_t s = 0, bool r = false);
-    Ruleset* new_Ruleset(std::string p, size_t l, Selector* s, Block* b);
-    Propset* new_Propset(std::string p, size_t l, String* pf, Block* b);
-    Supports_Query* new_Supports_Query(std::string p, size_t l, Supports_Query* f, Block* b);
-    Media_Query* new_Media_Query(std::string p, size_t l, List* q, Block* b);
-    At_Root_Block* new_At_Root_Block(std::string p, size_t l, Selector* sel, Block* b);
-    At_Rule* new_At_Rule(std::string p, size_t l, std::string kwd, Selector* sel, Block* b);
-    Keyframe_Rule* new_Keyframe_Rule(std::string p, size_t l, Block* b);
-    Declaration* new_Declaration(std::string p, size_t l, String* prop, List* vals);
-    Assignment* new_Assignment(std::string p, size_t l, std::string var, Expression* val, bool guarded = false);
-    Import<Function_Call*>* new_CSS_Import(std::string p, size_t l, Function_Call* loc);
-    Import<String*>* new_SASS_Import(std::string p, size_t l, String* loc);
-    Custom_Warning* new_Custom_Warning(std::string msg, size_t l, std::string msg);
-    Custom_Error* new_Custom_Error(std::string p, size_t l, std::string msg);
-    Warning* new_Warning(std::string p, size_t l, Expression* msg);
-    Error* new_Error(std::string p, size_t l, Expression* msg);
-    Debug* new_Debug(std::string p, size_t l, Expression* val);
-    Comment* new_Comment(std::string p, size_t l, String* txt);
-    If* new_If(std::string p, size_t l, Expression* pred, Block* con, Block* alt = 0);
-    For* new_For(std::string p, size_t l, std::string var, Expression* lo, Expression* hi, Block* b, bool inc);
-    Each* new_Each(std::string p, size_t l, std::vector<std::string> vars, Expression* lst, Block* b);
-    While* new_While(std::string p, size_t l, Expression* pred, Block* b);
-    Extension* new_Extension(std::string p, size_t l, Selector* s);
-    Definition<MIXIN>* new_Mixin_Definition(std::string p, size_t l, std::string n, Parameters* params, Block* b);
-    Definition<FUNCTION>* new_Function_Definition(std::string p, size_t l, std::string n, Parameters* params, Block* b);
-    Mixin_Call* new_Mixin_Call(std::string p, size_t l, std::string n, Arguments* args, Block* b = 0);
-    // expressions
-    List* new_List(std::string p, size_t l, size_t size = 0, enum Sass_Separator sep = List::space, bool argl = false);
-    Map* new_Map(std::string p, size_t l, size_t size = 0);
-    Binary_Expression<AND>* new_And(std::string p, size_t l, Expression* lhs, Expression* rhs);
-    Binary_Expression<OR>* new_Or(std::string p, size_t l, Expression* lhs, Expression* rhs);
-    Binary_Expression<EQ>* new_Eq(std::string p, size_t l, Expression* lhs, Expression* rhs);
-    Binary_Expression<NEQ>* new_Neq(std::string p, size_t l, Expression* lhs, Expression* rhs);
-    Binary_Expression<GT>* new_Gt(std::string p, size_t l, Expression* lhs, Expression* rhs);
-    Binary_Expression<GTE>* new_Gte(std::string p, size_t l, Expression* lhs, Expression* rhs);
-    Binary_Expression<LT>* new_Lt(std::string p, size_t l, Expression* lhs, Expression* rhs);
-    Binary_Expression<LTE>* new_Lte(std::string p, size_t l, Expression* lhs, Expression* rhs);
-    Binary_Expression<ADD>* new_Add(std::string p, size_t l, Expression* lhs, Expression* rhs);
-    Binary_Expression<SUB>* new_Sub(std::string p, size_t l, Expression* lhs, Expression* rhs);
-    Binary_Expression<MUL>* new_Mul(std::string p, size_t l, Expression* lhs, Expression* rhs);
-    Binary_Expression<DIV>* new_Div(std::string p, size_t l, Expression* lhs, Expression* rhs);
-    Negation* new_Negation(std::string p, size_t l, Expression* o);
-    Function_Call* new_Function_Call(std::string p, size_t l, String* n, Arguments* args);
-    Variable* new_Variable(std::string p, size_t l, std::string n);
-    Textual<NUMBER>* new_Textual_Number(std::string p, size_t l, std::string val);
-    Textual<PERCENTAGE>* new_Textual_Percentage(std::string p, size_t l, std::string val);
-    Textual<DIMENSION>* new_Textual_Dimension(std::string p, size_t l, std::string val);
-    Textual<HEX>* new_Textual_Hex(std::string p, size_t l, std::string val);
-    Number* new_Number(std::string p, size_t l, double val);
-    Percentage* new_Percentage(std::string p, size_t l, double val);
-    Dimension* new_Dimension(std::string p, size_t l, double val, std::string unit);
-    Color* new_Color(std::string p, size_t l, double r, double g, double b, double a = 1, std::string disp = "");
-    Boolean* new_Boolean(std::string p, size_t l, bool val);
-    String_Schema* new_String_Schema(std::string p, size_t l, size_t size = 0);
-    String_Constant* new_String_Constant(std::string p, size_t l, std::string val);
-    String_Constant* new_String_Constant(std::string p, size_t l, const char* beg);
-    String_Constant* new_String_Constant(std::string p, size_t l, const char* beg, const char* end);
-    Supports_Condition* new_Supports_Condition(std::string p, size_t l, String* f, Expression* v);
-    Media_Expression* new_Media_Expression(std::string p, size_t l, String* f, Expression* v);
-    Parent_Selector* new_Parent_Selector(std::string p, size_t l, Selector* s);
-    // parameters and arguments
-    Parameter* new_Parameter(std::string p, size_t l, std::string n, Expression* def = 0, bool rest = false);
-    Parameters* new_Parameters(std::string p, size_t l);
-    Argument* new_Argument(std::string p, size_t l, Expression* val, std::string n = "", bool rest = false);
-    Arguments* new_Arguments(std::string p, size_t l);
-    // selectors
-    Selector_Schema* new_Selector_Schema(std::string p, size_t l, String* c);
-    Attribute_Selector* new_Attribute_Selector(std::string p, size_t l, std::string n, std::string m, String* v);
-    Simple_Selector* new_Simple_Selector(std::string p, size_t l, std::string c);
-    Reference_Selector* new_Reference_Selector(std::string p, size_t l);
-    Placeholder_Selector* new_Placeholder_Selector(std::string p, size_t l, std::string n);
-    Pseudo_Selector* new_Pseudo_Selector(std::string p, size_t l, std::string n, Expression* expr = 0);
-    Wrapped_Selector* new_Wrapped_Selector(std::string p, size_t l, std::string n, Simple_Base* sel);
-    Compound_Selector* new_Compound_Selector(std::string p, size_t l, size_t s = 0);
-    Complex_Selector* new_Complex_Selector(std::string p, size_t l, Complex_Selector::Combinator c, Complex_Selector* ctx, Compound_Selector* sel);
-    Selector_List* new_Selector_List(std::string p, size_t l, size_t s = 0);
-  };
-}
-
-#endif
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,90 +1,389 @@
 #ifndef SASS_AST_FWD_DECL_H
 #define SASS_AST_FWD_DECL_H
 
+#include <vector>
+#include <iostream>
+#include <algorithm>
+#include <unordered_map>
+#include <unordered_set>
+#include "memory/SharedPtr.hpp"
+
 /////////////////////////////////////////////
 // Forward declarations for the AST visitors.
 /////////////////////////////////////////////
 namespace Sass {
 
   class AST_Node;
-  // statements
-  class Statement;
+  typedef AST_Node* AST_Node_Ptr;
+  typedef AST_Node const* AST_Node_Ptr_Const;
+
+  class Has_Block;
+  typedef Has_Block* Has_Block_Ptr;
+  typedef Has_Block const* Has_Block_Ptr_Const;
+
+  class Simple_Selector;
+  typedef Simple_Selector* Simple_Selector_Ptr;
+  typedef Simple_Selector const* Simple_Selector_Ptr_Const;
+
+  class PreValue;
+  typedef PreValue* PreValue_Ptr;
+  typedef PreValue const* PreValue_Ptr_Const;
+  class Thunk;
+  typedef Thunk* Thunk_Ptr;
+  typedef Thunk const* Thunk_Ptr_Const;
   class Block;
+  typedef Block* Block_Ptr;
+  typedef Block const* Block_Ptr_Const;
+  class Expression;
+  typedef Expression* Expression_Ptr;
+  typedef Expression const* Expression_Ptr_Const;
+  class Statement;
+  typedef Statement* Statement_Ptr;
+  typedef Statement const* Statement_Ptr_Const;
+  class Value;
+  typedef Value* Value_Ptr;
+  typedef Value const* Value_Ptr_Const;
+  class Declaration;
+  typedef Declaration* Declaration_Ptr;
+  typedef Declaration const* Declaration_Ptr_Const;
   class Ruleset;
-  class Propset;
+  typedef Ruleset* Ruleset_Ptr;
+  typedef Ruleset const* Ruleset_Ptr_Const;
   class Bubble;
+  typedef Bubble* Bubble_Ptr;
+  typedef Bubble const* Bubble_Ptr_Const;
+  class Trace;
+  typedef Trace* Trace_Ptr;
+  typedef Trace const* Trace_Ptr_Const;
+
   class Media_Block;
+  typedef Media_Block* Media_Block_Ptr;
+  typedef Media_Block const* Media_Block_Ptr_Const;
   class Supports_Block;
-  class At_Rule;
+  typedef Supports_Block* Supports_Block_Ptr;
+  typedef Supports_Block const* Supports_Block_Ptr_Const;
+  class Directive;
+  typedef Directive* Directive_Ptr;
+  typedef Directive const* Directive_Ptr_Const;
+
+
   class Keyframe_Rule;
+  typedef Keyframe_Rule* Keyframe_Rule_Ptr;
+  typedef Keyframe_Rule const* Keyframe_Rule_Ptr_Const;
   class At_Root_Block;
-  class Declaration;
+  typedef At_Root_Block* At_Root_Block_Ptr;
+  typedef At_Root_Block const* At_Root_Block_Ptr_Const;
   class Assignment;
+  typedef Assignment* Assignment_Ptr;
+  typedef Assignment const* Assignment_Ptr_Const;
+
   class Import;
+  typedef Import* Import_Ptr;
+  typedef Import const* Import_Ptr_Const;
   class Import_Stub;
+  typedef Import_Stub* Import_Stub_Ptr;
+  typedef Import_Stub const* Import_Stub_Ptr_Const;
   class Warning;
+  typedef Warning* Warning_Ptr;
+  typedef Warning const* Warning_Ptr_Const;
+
   class Error;
+  typedef Error* Error_Ptr;
+  typedef Error const* Error_Ptr_Const;
   class Debug;
+  typedef Debug* Debug_Ptr;
+  typedef Debug const* Debug_Ptr_Const;
   class Comment;
+  typedef Comment* Comment_Ptr;
+  typedef Comment const* Comment_Ptr_Const;
+
   class If;
+  typedef If* If_Ptr;
+  typedef If const* If_Ptr_Const;
   class For;
+  typedef For* For_Ptr;
+  typedef For const* For_Ptr_Const;
   class Each;
+  typedef Each* Each_Ptr;
+  typedef Each const* Each_Ptr_Const;
   class While;
+  typedef While* While_Ptr;
+  typedef While const* While_Ptr_Const;
   class Return;
+  typedef Return* Return_Ptr;
+  typedef Return const* Return_Ptr_Const;
   class Content;
+  typedef Content* Content_Ptr;
+  typedef Content const* Content_Ptr_Const;
   class Extension;
+  typedef Extension* Extension_Ptr;
+  typedef Extension const* Extension_Ptr_Const;
   class Definition;
-  class Mixin_Call;
-  // expressions
-  class Value;
-  class Expression;
+  typedef Definition* Definition_Ptr;
+  typedef Definition const* Definition_Ptr_Const;
+
   class List;
+  typedef List* List_Ptr;
+  typedef List const* List_Ptr_Const;
   class Map;
+  typedef Map* Map_Ptr;
+  typedef Map const* Map_Ptr_Const;
+
+  class Mixin_Call;
+  typedef Mixin_Call* Mixin_Call_Ptr;
+  typedef Mixin_Call const* Mixin_Call_Ptr_Const;
   class Binary_Expression;
+  typedef Binary_Expression* Binary_Expression_Ptr;
+  typedef Binary_Expression const* Binary_Expression_Ptr_Const;
   class Unary_Expression;
+  typedef Unary_Expression* Unary_Expression_Ptr;
+  typedef Unary_Expression const* Unary_Expression_Ptr_Const;
   class Function_Call;
+  typedef Function_Call* Function_Call_Ptr;
+  typedef Function_Call const* Function_Call_Ptr_Const;
   class Function_Call_Schema;
+  typedef Function_Call_Schema* Function_Call_Schema_Ptr;
+  typedef Function_Call_Schema const* Function_Call_Schema_Ptr_Const;
   class Custom_Warning;
+  typedef Custom_Warning* Custom_Warning_Ptr;
+  typedef Custom_Warning const* Custom_Warning_Ptr_Const;
   class Custom_Error;
+  typedef Custom_Error* Custom_Error_Ptr;
+  typedef Custom_Error const* Custom_Error_Ptr_Const;
+
   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;
   class Color;
+  typedef Color* Color_Ptr;
+  typedef Color const* Color_Ptr_Const;
   class Boolean;
-  class String_Schema;
+  typedef Boolean* Boolean_Ptr;
+  typedef Boolean const* Boolean_Ptr_Const;
   class String;
+  typedef String* String_Ptr;
+  typedef String const* String_Ptr_Const;
+
+  class String_Schema;
+  typedef String_Schema* String_Schema_Ptr;
+  typedef String_Schema const* String_Schema_Ptr_Const;
   class String_Constant;
+  typedef String_Constant* String_Constant_Ptr;
+  typedef String_Constant const* String_Constant_Ptr_Const;
   class String_Quoted;
+  typedef String_Quoted* String_Quoted_Ptr;
+  typedef String_Quoted const* String_Quoted_Ptr_Const;
+
   class Media_Query;
+  typedef Media_Query* Media_Query_Ptr;
+  typedef Media_Query const* Media_Query_Ptr_Const;
   class Media_Query_Expression;
+  typedef Media_Query_Expression* Media_Query_Expression_Ptr;
+  typedef Media_Query_Expression const* Media_Query_Expression_Ptr_Const;
   class Supports_Condition;
+  typedef Supports_Condition* Supports_Condition_Ptr;
+  typedef Supports_Condition const* Supports_Condition_Ptr_Const;
   class Supports_Operator;
+  typedef Supports_Operator* Supports_Operator_Ptr;
+  typedef Supports_Operator const* Supports_Operator_Ptr_Const;
   class Supports_Negation;
+  typedef Supports_Negation* Supports_Negation_Ptr;
+  typedef Supports_Negation const* Supports_Negation_Ptr_Const;
   class Supports_Declaration;
+  typedef Supports_Declaration* Supports_Declaration_Ptr;
+  typedef Supports_Declaration const* Supports_Declaration_Ptr_Const;
   class Supports_Interpolation;
-  class At_Root_Expression;
+  typedef Supports_Interpolation* Supports_Interpolation_Ptr;
+  typedef Supports_Interpolation const* Supports_Interpolation_Ptr_Const;
+
+
   class Null;
+  typedef Null* Null_Ptr;
+  typedef Null const* Null_Ptr_Const;
+
+  class At_Root_Query;
+  typedef At_Root_Query* At_Root_Query_Ptr;
+  typedef At_Root_Query const* At_Root_Query_Ptr_Const;
   class Parent_Selector;
-  // parameters and arguments
+  typedef Parent_Selector* Parent_Selector_Ptr;
+  typedef Parent_Selector const* Parent_Selector_Ptr_Const;
   class Parameter;
+  typedef Parameter* Parameter_Ptr;
+  typedef Parameter const* Parameter_Ptr_Const;
   class Parameters;
+  typedef Parameters* Parameters_Ptr;
+  typedef Parameters const* Parameters_Ptr_Const;
   class Argument;
+  typedef Argument* Argument_Ptr;
+  typedef Argument const* Argument_Ptr_Const;
   class Arguments;
-  // selectors
+  typedef Arguments* Arguments_Ptr;
+  typedef Arguments const* Arguments_Ptr_Const;
   class Selector;
+  typedef Selector* Selector_Ptr;
+  typedef Selector const* Selector_Ptr_Const;
+
+
   class Selector_Schema;
-  class Selector_Placeholder;
-  class Type_Selector;
-  class Selector_Qualifier;
+  typedef Selector_Schema* Selector_Schema_Ptr;
+  typedef Selector_Schema const* Selector_Schema_Ptr_Const;
+  class Placeholder_Selector;
+  typedef Placeholder_Selector* Placeholder_Selector_Ptr;
+  typedef Placeholder_Selector const* Placeholder_Selector_Ptr_Const;
+  class Element_Selector;
+  typedef Element_Selector* Element_Selector_Ptr;
+  typedef Element_Selector const* Element_Selector_Ptr_Const;
+  class Class_Selector;
+  typedef Class_Selector* Class_Selector_Ptr;
+  typedef Class_Selector const* Class_Selector_Ptr_Const;
+  class Id_Selector;
+  typedef Id_Selector* Id_Selector_Ptr;
+  typedef Id_Selector const* Id_Selector_Ptr_Const;
   class Attribute_Selector;
+  typedef Attribute_Selector* Attribute_Selector_Ptr;
+  typedef Attribute_Selector const* Attribute_Selector_Ptr_Const;
+
   class Pseudo_Selector;
+  typedef Pseudo_Selector* Pseudo_Selector_Ptr;
+  typedef Pseudo_Selector const * Pseudo_Selector_Ptr_Const;
   class Wrapped_Selector;
+  typedef Wrapped_Selector* Wrapped_Selector_Ptr;
+  typedef Wrapped_Selector const * Wrapped_Selector_Ptr_Const;
   class Compound_Selector;
+  typedef Compound_Selector* Compound_Selector_Ptr;
+  typedef Compound_Selector const * Compound_Selector_Ptr_Const;
   class Complex_Selector;
+  typedef Complex_Selector* Complex_Selector_Ptr;
+  typedef Complex_Selector const * Complex_Selector_Ptr_Const;
   class Selector_List;
+  typedef Selector_List* Selector_List_Ptr;
+  typedef Selector_List const * Selector_List_Ptr_Const;
 
+
   // common classes
   class Context;
+  class Expand;
+  class Eval;
+
+  // declare classes that are instances of memory nodes
+  // #define IMPL_MEM_OBJ(type) using type##_Obj = SharedImpl<type>
+  #define IMPL_MEM_OBJ(type) typedef SharedImpl<type> type##_Obj
+
+  IMPL_MEM_OBJ(AST_Node);
+  IMPL_MEM_OBJ(Statement);
+  IMPL_MEM_OBJ(Block);
+  IMPL_MEM_OBJ(Ruleset);
+  IMPL_MEM_OBJ(Bubble);
+  IMPL_MEM_OBJ(Trace);
+  IMPL_MEM_OBJ(Media_Block);
+  IMPL_MEM_OBJ(Supports_Block);
+  IMPL_MEM_OBJ(Directive);
+  IMPL_MEM_OBJ(Keyframe_Rule);
+  IMPL_MEM_OBJ(At_Root_Block);
+  IMPL_MEM_OBJ(Declaration);
+  IMPL_MEM_OBJ(Assignment);
+  IMPL_MEM_OBJ(Import);
+  IMPL_MEM_OBJ(Import_Stub);
+  IMPL_MEM_OBJ(Warning);
+  IMPL_MEM_OBJ(Error);
+  IMPL_MEM_OBJ(Debug);
+  IMPL_MEM_OBJ(Comment);
+  IMPL_MEM_OBJ(PreValue);
+  IMPL_MEM_OBJ(Has_Block);
+  IMPL_MEM_OBJ(Thunk);
+  IMPL_MEM_OBJ(If);
+  IMPL_MEM_OBJ(For);
+  IMPL_MEM_OBJ(Each);
+  IMPL_MEM_OBJ(While);
+  IMPL_MEM_OBJ(Return);
+  IMPL_MEM_OBJ(Content);
+  IMPL_MEM_OBJ(Extension);
+  IMPL_MEM_OBJ(Definition);
+  IMPL_MEM_OBJ(Mixin_Call);
+  IMPL_MEM_OBJ(Value);
+  IMPL_MEM_OBJ(Expression);
+  IMPL_MEM_OBJ(List);
+  IMPL_MEM_OBJ(Map);
+  IMPL_MEM_OBJ(Binary_Expression);
+  IMPL_MEM_OBJ(Unary_Expression);
+  IMPL_MEM_OBJ(Function_Call);
+  IMPL_MEM_OBJ(Function_Call_Schema);
+  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);
+  IMPL_MEM_OBJ(String_Schema);
+  IMPL_MEM_OBJ(String);
+  IMPL_MEM_OBJ(String_Constant);
+  IMPL_MEM_OBJ(String_Quoted);
+  IMPL_MEM_OBJ(Media_Query);
+  IMPL_MEM_OBJ(Media_Query_Expression);
+  IMPL_MEM_OBJ(Supports_Condition);
+  IMPL_MEM_OBJ(Supports_Operator);
+  IMPL_MEM_OBJ(Supports_Negation);
+  IMPL_MEM_OBJ(Supports_Declaration);
+  IMPL_MEM_OBJ(Supports_Interpolation);
+  IMPL_MEM_OBJ(At_Root_Query);
+  IMPL_MEM_OBJ(Null);
+  IMPL_MEM_OBJ(Parent_Selector);
+  IMPL_MEM_OBJ(Parameter);
+  IMPL_MEM_OBJ(Parameters);
+  IMPL_MEM_OBJ(Argument);
+  IMPL_MEM_OBJ(Arguments);
+  IMPL_MEM_OBJ(Selector);
+  IMPL_MEM_OBJ(Selector_Schema);
+  IMPL_MEM_OBJ(Simple_Selector);
+  IMPL_MEM_OBJ(Placeholder_Selector);
+  IMPL_MEM_OBJ(Element_Selector);
+  IMPL_MEM_OBJ(Class_Selector);
+  IMPL_MEM_OBJ(Id_Selector);
+  IMPL_MEM_OBJ(Attribute_Selector);
+  IMPL_MEM_OBJ(Pseudo_Selector);
+  IMPL_MEM_OBJ(Wrapped_Selector);
+  IMPL_MEM_OBJ(Compound_Selector);
+  IMPL_MEM_OBJ(Complex_Selector);
+  IMPL_MEM_OBJ(Selector_List);
+
+
+  struct HashExpression {
+    size_t operator() (Expression_Obj ex) const;
+  };
+  struct CompareExpression {
+    bool operator()(const Expression_Obj& lhs, const Expression_Obj& rhs) const;
+  };
+
+  struct HashSimpleSelector {
+    size_t operator() (Simple_Selector_Obj ex) const;
+  };
+
+  struct CompareSimpleSelector {
+    bool operator()(Simple_Selector_Obj lhs, Simple_Selector_Obj rhs) const;
+  };
+
+  typedef std::unordered_map<
+    Expression_Obj, // key
+    Expression_Obj, // value
+    HashExpression, // hasher
+    CompareExpression // compare
+  > ExpressionMap;
+  typedef std::unordered_set<
+    Expression_Obj, // value
+    HashExpression, // hasher
+    CompareExpression // 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;
 
 }
 
diff --git a/libsass/src/base64vlq.cpp b/libsass/src/base64vlq.cpp
--- a/libsass/src/base64vlq.cpp
+++ b/libsass/src/base64vlq.cpp
@@ -1,3 +1,4 @@
+#include "sass.hpp"
 #include "base64vlq.hpp"
 
 namespace Sass {
diff --git a/libsass/src/bind.cpp b/libsass/src/bind.cpp
--- a/libsass/src/bind.cpp
+++ b/libsass/src/bind.cpp
@@ -1,3 +1,4 @@
+#include "sass.hpp"
 #include "bind.hpp"
 #include "ast.hpp"
 #include "context.hpp"
@@ -5,22 +6,20 @@
 #include <map>
 #include <iostream>
 #include <sstream>
-#include "to_string.hpp"
 
 namespace Sass {
 
-  void bind(std::string type, std::string name, Parameters* ps, Arguments* as, Context* ctx, Env* env, Eval* eval)
+  void bind(std::string type, std::string name, Parameters_Obj ps, Arguments_Obj as, Context* ctx, Env* env, Eval* eval)
   {
     std::string callee(type + " " + name);
-    Listize listize(*ctx);
-    std::map<std::string, Parameter*> param_map;
 
+    std::map<std::string, Parameter_Obj> param_map;
+
     for (size_t i = 0, L = as->length(); i < L; ++i) {
-      if (auto str = dynamic_cast<String_Quoted*>((*as)[i]->value())) {
+      if (auto str = SASS_MEMORY_CAST(String_Quoted, (*as)[i]->value())) {
         // force optional quotes (only if needed)
         if (str->quote_mark()) {
           str->quote_mark('*');
-          str->is_delayed(true);
         }
       }
     }
@@ -28,7 +27,7 @@
     // Set up a map to ensure named arguments refer to actual parameters. Also
     // eval each default value left-to-right, wrt env, populating env as we go.
     for (size_t i = 0, L = ps->length(); i < L; ++i) {
-      Parameter*  p = (*ps)[i];
+      Parameter_Obj  p = ps->at(i);
       param_map[p->name()] = p;
       // if (p->default_value()) {
       //   env->local_frame()[p->name()] = p->default_value()->perform(eval->with(env));
@@ -39,11 +38,11 @@
     size_t ip = 0, LP = ps->length();
     size_t ia = 0, LA = as->length();
     while (ia < LA) {
-      Argument* a = (*as)[ia];
+      Argument_Obj a = as->at(ia);
       if (ip >= LP) {
         // skip empty rest arguments
         if (a->is_rest_argument()) {
-          if (List* l = dynamic_cast<List*>(a->value())) {
+          if (List_Obj l = SASS_MEMORY_CAST(List, a->value())) {
             if (l->length() == 0) {
               ++ ia; continue;
             }
@@ -54,43 +53,37 @@
         msg << " for `" << name << "'";
         return error(msg.str(), as->pstate());
       }
-      Parameter* p = (*ps)[ip];
+      Parameter_Obj p = ps->at(ip);
 
       // If the current parameter is the rest parameter, process and break the loop
       if (p->is_rest_parameter()) {
         // The next argument by coincidence provides a rest argument
         if (a->is_rest_argument()) {
+
           // We should always get a list for rest arguments
-          if (List* rest = dynamic_cast<List*>(a->value())) {
-            // arg contains a list
-            List* args = rest;
-            // make sure it's an arglist
-            if (rest->is_arglist()) {
-              // can pass it through as it was
-              env->local_frame()[p->name()] = args;
-            }
-            // create a new list and wrap each item as an argument
-            // otherwise we will not be able to fetch it again
-            else {
+          if (List_Obj rest = SASS_MEMORY_CAST(List, a->value())) {
               // create a new list object for wrapped items
-              List* arglist = SASS_MEMORY_NEW(ctx->mem, List,
+              List_Ptr arglist = SASS_MEMORY_NEW(List,
                                               p->pstate(),
                                               0,
                                               rest->separator(),
                                               true);
               // wrap each item from list as an argument
-              for (Expression* item : rest->elements()) {
-                (*arglist) << SASS_MEMORY_NEW(ctx->mem, Argument,
-                                              item->pstate(),
-                                              item,
-                                              "",
-                                              false,
-                                              false);
+              for (Expression_Obj item : rest->elements()) {
+                if (Argument_Obj arg = SASS_MEMORY_CAST(Argument, item)) {
+                  arglist->append(SASS_MEMORY_COPY(arg)); // copy
+                } else {
+                  arglist->append(SASS_MEMORY_NEW(Argument,
+                                                  item->pstate(),
+                                                  &item,
+                                                  "",
+                                                  false,
+                                                  false));
+                }
               }
               // assign new arglist to environment
               env->local_frame()[p->name()] = arglist;
             }
-          }
           // invalid state
           else {
             throw std::runtime_error("invalid state");
@@ -98,23 +91,23 @@
         } else if (a->is_keyword_argument()) {
 
           // expand keyword arguments into their parameters
-          List* arglist = SASS_MEMORY_NEW(ctx->mem, List, p->pstate(), 0, SASS_COMMA, true);
+          List_Ptr arglist = SASS_MEMORY_NEW(List, p->pstate(), 0, SASS_COMMA, true);
           env->local_frame()[p->name()] = arglist;
-          Map* argmap = static_cast<Map*>(a->value());
+          Map_Obj argmap = SASS_MEMORY_CAST(Map, a->value());
           for (auto key : argmap->keys()) {
-            std::string name = unquote(static_cast<String_Constant*>(key)->value());
-            (*arglist) << SASS_MEMORY_NEW(ctx->mem, Argument,
-                                          key->pstate(),
-                                          argmap->at(key),
-                                          "$" + name,
-                                          false,
-                                          false);
+            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));
           }
 
         } else {
 
           // create a new list object for wrapped items
-          List* arglist = SASS_MEMORY_NEW(ctx->mem, List,
+          List_Obj arglist = SASS_MEMORY_NEW(List,
                                           p->pstate(),
                                           0,
                                           SASS_COMMA,
@@ -124,52 +117,45 @@
             // get and post inc
             a = (*as)[ia++];
             // maybe we have another list as argument
-            List* ls = dynamic_cast<List*>(a->value());
+            List_Obj ls = SASS_MEMORY_CAST(List, a->value());
             // skip any list completely if empty
             if (ls && ls->empty() && a->is_rest_argument()) continue;
-            // flatten all nested arglists
-            if (ls && ls->is_arglist()) {
-              for (size_t i = 0, L = ls->size(); i < L; ++i) {
-                // already have a wrapped argument
-                if (Argument* arg = dynamic_cast<Argument*>((*ls)[i])) {
-                  (*arglist) << SASS_MEMORY_NEW(ctx->mem, Argument, *arg);
-                }
-                // wrap all other value types into Argument
-                else {
-                  (*arglist) << SASS_MEMORY_NEW(ctx->mem, Argument,
-                                                (*ls)[i]->pstate(),
-                                                (*ls)[i],
+
+            Expression_Obj value = a->value();
+            if (Argument_Obj arg = SASS_MEMORY_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())) {
+                arglist->separator(rest->separator());
+
+                for (size_t i = 0, L = rest->size(); i < L; ++i) {
+                  Expression_Obj obj = rest->at(i);
+                  arglist->append(SASS_MEMORY_NEW(Argument,
+                                                obj->pstate(),
+                                                &obj,
                                                 "",
                                                 false,
-                                                false);
+                                                false));
                 }
               }
-            }
-            // already have a wrapped argument
-            else if (Argument* arg = dynamic_cast<Argument*>(a->value())) {
-              (*arglist) << SASS_MEMORY_NEW(ctx->mem, Argument, *arg);
+              // no more arguments
+              break;
             }
             // wrap all other value types into Argument
             else {
-              (*arglist) << SASS_MEMORY_NEW(ctx->mem, Argument,
+              arglist->append(SASS_MEMORY_NEW(Argument,
                                             a->pstate(),
                                             a->value(),
                                             a->name(),
                                             false,
-                                            false);
-            }
-            // check if we have rest argument
-            if (a->is_rest_argument()) {
-              // preserve the list separator from rest args
-              if (List* rest = dynamic_cast<List*>(a->value())) {
-                arglist->separator(rest->separator());
-              }
-              // no more arguments
-              break;
+                                            false));
             }
           }
           // assign new arglist to environment
-          env->local_frame()[p->name()] = arglist;
+          env->local_frame()[p->name()] = &arglist;
         }
         // consumed parameter
         ++ip;
@@ -180,25 +166,30 @@
       // 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* arglist = static_cast<List*>(a->value());
+        List_Obj arglist = SASS_MEMORY_CAST(List, a->value());
         // empty rest arg - treat all args as default values
         if (!arglist->length()) {
           break;
         } else {
-          if (arglist->length() + ia > LP && !ps->has_rest_parameter()) {
-            int arg_count = (arglist->length() + LA - 1);
+          if (arglist->length() > LP - ip && !ps->has_rest_parameter()) {
+            size_t arg_count = (arglist->length() + LA - 1);
             std::stringstream msg;
             msg << callee << " takes " << LP;
             msg << (LP == 1 ? " argument" : " arguments");
             msg << " but " << arg_count;
             msg << (arg_count == 1 ? " was passed" : " were passed.");
             deprecated_bind(msg.str(), as->pstate());
+
+            while (arglist->length() > LP - ip) {
+              arglist->elements().erase(arglist->elements().end() - 1);
+            }
           }
         }
         // otherwise move one of the rest args into the param, converting to argument if necessary
-        if (!(a = dynamic_cast<Argument*>((*arglist)[0]))) {
-          Expression* a_to_convert = (*arglist)[0];
-          a = SASS_MEMORY_NEW(ctx->mem, Argument,
+        Expression_Obj obj = arglist->at(0);
+        if (!(a = SASS_MEMORY_CAST(Argument, obj))) {
+          Expression_Ptr a_to_convert = &obj;
+          a = SASS_MEMORY_NEW(Argument,
                               a_to_convert->pstate(),
                               a_to_convert,
                               "",
@@ -209,18 +200,19 @@
         if (!arglist->length() || (!arglist->is_arglist() && ip + 1 == LP)) {
           ++ia;
         }
+
       } else if (a->is_keyword_argument()) {
-        Map* argmap = static_cast<Map*>(a->value());
+        Map_Obj argmap = SASS_MEMORY_CAST(Map, a->value());
 
         for (auto key : argmap->keys()) {
-          std::string name = "$" + unquote(static_cast<String_Constant*>(key)->value());
+          std::string name = "$" + unquote(SASS_MEMORY_CAST(String_Constant, key)->value());
 
           if (!param_map.count(name)) {
             std::stringstream msg;
             msg << callee << " has no parameter named " << name;
             error(msg.str(), a->pstate());
           }
-          env->local_frame()[name] = argmap->at(key);
+          env->local_frame()[name] = &argmap->at(&key);
         }
         ++ia;
         continue;
@@ -236,7 +228,7 @@
           error(msg.str(), a->pstate());
         }
         // ordinal arg -- bind it to the next param
-        env->local_frame()[p->name()] = a->value();
+        env->local_frame()[p->name()] = &a->value();
         ++ip;
       }
       else {
@@ -258,7 +250,7 @@
               << "provided more than once in call to " << callee;
           error(msg.str(), a->pstate());
         }
-        env->local_frame()[a->name()] = a->value();
+        env->local_frame()[a->name()] = &a->value();
       }
     }
     // EO while ia
@@ -267,29 +259,25 @@
     // That's only okay if they have default values, or were already bound by
     // named arguments, or if it's a single rest-param.
     for (size_t i = ip; i < LP; ++i) {
-      To_String to_string(ctx);
-      Parameter* leftover = (*ps)[i];
+      Parameter_Obj leftover = ps->at(i);
       // cerr << "env for default params:" << endl;
       // env->print();
       // cerr << "********" << endl;
       if (!env->has_local(leftover->name())) {
         if (leftover->is_rest_parameter()) {
-          env->local_frame()[leftover->name()] = SASS_MEMORY_NEW(ctx->mem, List,
+          env->local_frame()[leftover->name()] = SASS_MEMORY_NEW(List,
                                                                    leftover->pstate(),
                                                                    0,
                                                                    SASS_COMMA,
                                                                    true);
         }
         else if (leftover->default_value()) {
-          Expression* dv = leftover->default_value()->perform(eval);
+          Expression_Ptr dv = leftover->default_value()->perform(eval);
           env->local_frame()[leftover->name()] = dv;
         }
         else {
           // param is unbound and has no default value -- error
-          std::stringstream msg;
-          msg << "required parameter " << leftover->name()
-              << " is missing in call to " << callee;
-          error(msg.str(), as->pstate());
+          throw Exception::MissingArgument(as->pstate(), 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
@@ -3,16 +3,12 @@
 
 #include <string>
 #include "environment.hpp"
+#include "ast_fwd_decl.hpp"
 
 namespace Sass {
-  class   AST_Node;
-  class   Parameters;
-  class   Arguments;
-  class   Context;
-  class   Eval;
-  typedef Environment<AST_Node*> Env;
+  typedef Environment<AST_Node_Obj> Env;
 
-  void bind(std::string type, std::string name, Parameters*, Arguments*, Context*, Env*, Eval*);
+  void bind(std::string type, std::string name, Parameters_Obj, Arguments_Obj, Context*, Env*, Eval*);
 }
 
 #endif
diff --git a/libsass/src/check_nesting.cpp b/libsass/src/check_nesting.cpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/check_nesting.cpp
@@ -0,0 +1,376 @@
+#include "sass.hpp"
+#include <vector>
+
+#include "check_nesting.hpp"
+
+namespace Sass {
+
+  CheckNesting::CheckNesting()
+  : parents(std::vector<Statement_Ptr>()),
+    parent(0),
+    current_mixin_definition(0)
+  { }
+
+  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)) {
+      std::vector<Statement_Ptr> old_parents = this->parents;
+      std::vector<Statement_Ptr> new_parents;
+
+      for (size_t i = 0, L = this->parents.size(); i < L; i++) {
+        Statement_Ptr p = this->parents.at(i);
+        if (!root->exclude_node(p)) {
+          new_parents.push_back(p);
+        }
+      }
+      this->parents = new_parents;
+
+      for (size_t i = this->parents.size(); i > 0; i--) {
+        Statement_Ptr p = 0;
+        Statement_Ptr gp = 0;
+        if (i > 0) p = this->parents.at(i - 1);
+        if (i > 1) gp = this->parents.at(i - 2);
+
+        if (!this->is_transparent_parent(p, gp)) {
+          this->parent = p;
+          break;
+        }
+      }
+
+      At_Root_Block_Ptr ar = SASS_MEMORY_CAST_PTR(At_Root_Block, parent);
+      Statement_Ptr ret = this->visit_children(&ar->block());
+
+      this->parent = old_parent;
+      this->parents = old_parents;
+
+      return ret;
+    }
+
+    if (!this->is_transparent_parent(parent, old_parent)) {
+      this->parent = parent;
+    }
+
+    this->parents.push_back(parent);
+
+    Block_Ptr b = SASS_MEMORY_CAST_PTR(Block, parent);
+
+    if (!b) {
+      if (Has_Block_Ptr bb = SASS_MEMORY_CAST(Has_Block, *parent)) {
+        b = &bb->block();
+      }
+    }
+
+    if (b) {
+      for (auto n : b->elements()) {
+        n->perform(this);
+      }
+    }
+    this->parent = old_parent;
+    this->parents.pop_back();
+
+    return b;
+  }
+
+
+  Statement_Ptr CheckNesting::operator()(Block_Ptr b)
+  {
+    return this->visit_children(b);
+  }
+
+  Statement_Ptr CheckNesting::operator()(Definition_Ptr n)
+  {
+    if (!this->should_visit(n)) return NULL;
+    if (!is_mixin(n)) {
+      visit_children(n);
+      return n;
+    }
+
+    Definition_Ptr old_mixin_definition = this->current_mixin_definition;
+    this->current_mixin_definition = n;
+
+    visit_children(n);
+
+    this->current_mixin_definition = old_mixin_definition;
+
+    return n;
+  }
+
+  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);
+    return b1 || b2 ? visit_children(s) : s;
+  }
+
+  bool CheckNesting::should_visit(Statement_Ptr node)
+  {
+    if (!this->parent) return true;
+
+    if (SASS_MEMORY_CAST_PTR(Content, node))
+    { this->invalid_content_parent(this->parent); }
+
+    if (is_charset(node))
+    { this->invalid_charset_parent(this->parent); }
+
+    if (SASS_MEMORY_CAST_PTR(Extension, node))
+    { this->invalid_extend_parent(this->parent); }
+
+    // if (SASS_MEMORY_CAST(Import, node))
+    // { this->invalid_import_parent(this->parent); }
+
+    if (this->is_mixin(node))
+    { this->invalid_mixin_definition_parent(this->parent); }
+
+    if (this->is_function(node))
+    { this->invalid_function_parent(this->parent); }
+
+    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 (SASS_MEMORY_CAST_PTR(Declaration, this->parent))
+    { this->invalid_prop_child(node); }
+
+    if (SASS_MEMORY_CAST_PTR(Return, node))
+    { this->invalid_return_parent(this->parent); }
+
+    return true;
+  }
+
+  void CheckNesting::invalid_content_parent(Statement_Ptr parent)
+  {
+    if (!this->current_mixin_definition) {
+      throw Exception::InvalidSass(
+        parent->pstate(),
+        "@content may only be used within a mixin."
+      );
+    }
+  }
+
+  void CheckNesting::invalid_charset_parent(Statement_Ptr parent)
+  {
+    if (!(
+        is_root_node(parent)
+    )) {
+      throw Exception::InvalidSass(
+        parent->pstate(),
+        "@charset may only be used at the root of a document."
+      );
+    }
+  }
+
+  void CheckNesting::invalid_extend_parent(Statement_Ptr parent)
+  {
+    if (!(
+        SASS_MEMORY_CAST_PTR(Ruleset, parent) ||
+        SASS_MEMORY_CAST_PTR(Mixin_Call, parent) ||
+        is_mixin(parent)
+    )) {
+      throw Exception::InvalidSass(
+        parent->pstate(),
+        "Extend directives may only be used within rules."
+      );
+    }
+  }
+
+  // void CheckNesting::invalid_import_parent(Statement_Ptr parent)
+  // {
+  //   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) ||
+  //         is_mixin(pp)
+  //     ) {
+  //       throw Exception::InvalidSass(
+  //         parent->pstate(),
+  //         "Import directives may not be defined within control directives or other mixins."
+  //       );
+  //     }
+  //   }
+
+  //   if (this->is_root_node(parent)) {
+  //     return;
+  //   }
+
+  //   if (false/*n.css_import?*/) {
+  //     throw Exception::InvalidSass(
+  //       parent->pstate(),
+  //       "CSS import directives may only be used at the root of a document."
+  //     );
+  //   }
+  // }
+
+  void CheckNesting::invalid_mixin_definition_parent(Statement_Ptr parent)
+  {
+    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) ||
+          is_mixin(pp)
+      ) {
+        throw Exception::InvalidSass(
+          parent->pstate(),
+          "Mixins may not be defined within control directives or other mixins."
+        );
+      }
+    }
+  }
+
+  void CheckNesting::invalid_function_parent(Statement_Ptr parent)
+  {
+    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) ||
+          is_mixin(pp)
+      ) {
+        throw Exception::InvalidSass(
+          parent->pstate(),
+          "Functions may not be defined within control directives or other mixins."
+        );
+      }
+    }
+  }
+
+  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) ||
+        // 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)
+    )) {
+      throw Exception::InvalidSass(
+        child->pstate(),
+        "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)
+    )) {
+      throw Exception::InvalidSass(
+        child->pstate(),
+        "Illegal nesting: Only properties may be nested beneath properties."
+      );
+    }
+  }
+
+  void CheckNesting::invalid_prop_parent(Statement_Ptr parent)
+  {
+    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)
+    )) {
+      throw Exception::InvalidSass(
+        parent->pstate(),
+        "Properties are only allowed within rules, directives, mixin includes, or other properties."
+      );
+    }
+  }
+
+  void CheckNesting::invalid_return_parent(Statement_Ptr parent)
+  {
+    if (!this->is_function(parent)) {
+      throw Exception::InvalidSass(
+        parent->pstate(),
+        "@return may only be used within a function."
+      );
+    }
+  }
+
+  bool CheckNesting::is_transparent_parent(Statement_Ptr parent, Statement_Ptr grandparent)
+  {
+    bool parent_bubbles = parent && parent->bubbles();
+
+    bool valid_bubble_node = parent_bubbles &&
+                             !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) ||
+           valid_bubble_node;
+  }
+
+  bool CheckNesting::is_charset(Statement_Ptr n)
+  {
+    Directive_Ptr d = SASS_MEMORY_CAST_PTR(Directive, n);
+    return d && d->keyword() == "charset";
+  }
+
+  bool CheckNesting::is_mixin(Statement_Ptr n)
+  {
+    Definition_Ptr def = SASS_MEMORY_CAST_PTR(Definition, n);
+    return def && def->type() == Definition::MIXIN;
+  }
+
+  bool CheckNesting::is_function(Statement_Ptr n)
+  {
+    Definition_Ptr def = SASS_MEMORY_CAST_PTR(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;
+
+    Block_Ptr b = SASS_MEMORY_CAST_PTR(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;
+  }
+
+  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);
+  }
+}
diff --git a/libsass/src/check_nesting.hpp b/libsass/src/check_nesting.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/check_nesting.hpp
@@ -0,0 +1,64 @@
+#ifndef SASS_CHECK_NESTING_H
+#define SASS_CHECK_NESTING_H
+
+#include "ast.hpp"
+#include "operation.hpp"
+
+namespace Sass {
+
+  typedef Environment<AST_Node_Obj> Env;
+
+  class CheckNesting : public Operation_CRTP<Statement_Ptr, CheckNesting> {
+
+    std::vector<Statement_Ptr>  parents;
+    Statement_Ptr               parent;
+    Definition_Ptr              current_mixin_definition;
+
+    Statement_Ptr fallback_impl(Statement_Ptr);
+    Statement_Ptr before(Statement_Ptr);
+    Statement_Ptr visit_children(Statement_Ptr);
+
+  public:
+    CheckNesting();
+    ~CheckNesting() { }
+
+    Statement_Ptr operator()(Block_Ptr);
+    Statement_Ptr operator()(Definition_Ptr);
+
+    template <typename U>
+    Statement_Ptr fallback(U x) {
+      Statement_Ptr n = SASS_MEMORY_CAST_PTR(Statement, x);
+      if (this->should_visit(n)) {
+        return fallback_impl(n);
+      }
+      return NULL;
+    }
+
+  private:
+    void invalid_content_parent(Statement_Ptr);
+    void invalid_charset_parent(Statement_Ptr);
+    void invalid_extend_parent(Statement_Ptr);
+    // void invalid_import_parent(Statement_Ptr);
+    void invalid_mixin_definition_parent(Statement_Ptr);
+    void invalid_function_parent(Statement_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);
+
+    bool is_transparent_parent(Statement_Ptr, Statement_Ptr);
+
+    bool should_visit(Statement_Ptr);
+
+    bool is_charset(Statement_Ptr);
+    bool is_mixin(Statement_Ptr);
+    bool is_function(Statement_Ptr);
+    bool is_root_node(Statement_Ptr);
+    bool is_at_root_node(Statement_Ptr);
+    bool is_directive_node(Statement_Ptr);
+  };
+
+}
+
+#endif
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
@@ -1,3 +1,4 @@
+#include "sass.hpp"
 #include "ast.hpp"
 #include "color_maps.hpp"
 
@@ -451,7 +452,7 @@
     { 102 * 0x10000 +  51 * 0x100 + 153, ColorNames::rebeccapurple }
   };
 
-  const std::map<const char*, const Color*, map_cmp_str> names_to_colors
+  const std::map<const char*, Color_Ptr_Const, map_cmp_str> names_to_colors
   {
     { ColorNames::aliceblue, &Colors::aliceblue },
     { ColorNames::antiquewhite, &Colors::antiquewhite },
@@ -604,7 +605,7 @@
     { ColorNames::transparent, &Colors::transparent }
   };
 
-  const Color* name_to_color(const char* key)
+  Color_Ptr_Const name_to_color(const char* key)
   {
     auto p = names_to_colors.find(key);
     if (p != names_to_colors.end()) {
@@ -613,7 +614,7 @@
     return 0;
   }
 
-  const Color* name_to_color(const std::string& key)
+  Color_Ptr_Const name_to_color(const std::string& key)
   {
     return name_to_color(key.c_str());
   }
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
@@ -320,10 +320,10 @@
   }
 
   extern const std::map<const int, const char*> colors_to_names;
-  extern const std::map<const char*, const Color*, map_cmp_str> names_to_colors;
+  extern const std::map<const char*, Color_Ptr_Const, map_cmp_str> names_to_colors;
 
-  extern const Color* name_to_color(const char*);
-  extern const Color* name_to_color(const std::string&);
+  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);
diff --git a/libsass/src/constants.cpp b/libsass/src/constants.cpp
--- a/libsass/src/constants.cpp
+++ b/libsass/src/constants.cpp
@@ -1,3 +1,4 @@
+#include "sass.hpp"
 #include "constants.hpp"
 
 namespace Sass {
@@ -9,12 +10,13 @@
     // https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity
     // https://github.com/sass/sass/issues/1495#issuecomment-61189114
     extern const unsigned long Specificity_Star = 0;
-    extern const unsigned long Specificity_Universal = 1 << 0;
-    extern const unsigned long Specificity_Type = 1 << 8;
-    extern const unsigned long Specificity_Class = 1 << 16;
-    extern const unsigned long Specificity_Attr = 1 << 16;
-    extern const unsigned long Specificity_Pseudo = 1 << 16;
-    extern const unsigned long Specificity_ID = 1 << 24;
+    extern const unsigned long Specificity_Universal = 0;
+    extern const unsigned long Specificity_Element = 1;
+    extern const unsigned long Specificity_Base = 1000;
+    extern const unsigned long Specificity_Class = 1000;
+    extern const unsigned long Specificity_Attr = 1000;
+    extern const unsigned long Specificity_Pseudo = 1000;
+    extern const unsigned long Specificity_ID = 1000000;
 
     // sass keywords
     extern const char at_root_kwd[]       = "@at-root";
@@ -78,7 +80,7 @@
     extern const char keyframes_kwd[]    = "keyframes";
     extern const char only_kwd[]         = "only";
     extern const char rgb_kwd[]          = "rgb(";
-    extern const char url_kwd[]          = "url(";
+    extern const char url_kwd[]          = "url";
     // extern const char url_prefix_kwd[]   = "url-prefix(";
     extern const char important_kwd[]    = "important";
     extern const char pseudo_not_kwd[]   = ":not(";
@@ -86,11 +88,10 @@
     extern const char odd_kwd[]          = "odd";
     extern const char progid_kwd[]       = "progid";
     extern const char expression_kwd[]   = "expression";
-    extern const char calc_kwd[]         = "calc(";
-    extern const char moz_calc_kwd[]     = "-moz-calc(";
-    extern const char webkit_calc_kwd[]  = "-webkit-calc(";
-    extern const char ms_calc_kwd[]      = "-ms-calc(";
+    extern const char calc_fn_kwd[]      = "calc";
 
+    extern const char almost_any_value_class[] = "\"'#!;{}";
+
     // css selector keywords
     extern const char sel_deep_kwd[] = "/deep/";
 
@@ -124,6 +125,7 @@
     extern const char rbrace[]          = "}";
     extern const char rparen[]          = ")";
     extern const char sign_chars[]      = "-+";
+    extern const char op_chars[]        = "-+";
     extern const char hyphen[]          = "-";
     extern const char ellipsis[]        = "...";
     // extern const char url_space_chars[] = " \t\r\n\f";
diff --git a/libsass/src/constants.hpp b/libsass/src/constants.hpp
--- a/libsass/src/constants.hpp
+++ b/libsass/src/constants.hpp
@@ -11,7 +11,8 @@
     // The following list of selectors is by increasing specificity:
     extern const unsigned long Specificity_Star;
     extern const unsigned long Specificity_Universal;
-    extern const unsigned long Specificity_Type;
+    extern const unsigned long Specificity_Element;
+    extern const unsigned long Specificity_Base;
     extern const unsigned long Specificity_Class;
     extern const unsigned long Specificity_Attr;
     extern const unsigned long Specificity_Pseudo;
@@ -81,18 +82,17 @@
     extern const char rgb_kwd[];
     extern const char url_kwd[];
     // extern const char url_prefix_kwd[];
-    extern const char image_url_kwd[];
     extern const char important_kwd[];
     extern const char pseudo_not_kwd[];
     extern const char even_kwd[];
     extern const char odd_kwd[];
     extern const char progid_kwd[];
     extern const char expression_kwd[];
-    extern const char calc_kwd[];
-    extern const char moz_calc_kwd[];
-    extern const char webkit_calc_kwd[];
-    extern const char ms_calc_kwd[];
+    extern const char calc_fn_kwd[];
 
+    // char classes for "regular expressions"
+    extern const char almost_any_value_class[];
+
     // css selector keywords
     extern const char sel_deep_kwd[];
 
@@ -126,6 +126,7 @@
     extern const char rbrace[];
     extern const char rparen[];
     extern const char sign_chars[];
+    extern const char op_chars[];
     extern const char hyphen[];
     extern const char ellipsis[];
     // extern const char url_space_chars[];
diff --git a/libsass/src/context.cpp b/libsass/src/context.cpp
--- a/libsass/src/context.cpp
+++ b/libsass/src/context.cpp
@@ -1,9 +1,4 @@
-#ifdef _WIN32
-#define PATH_SEP ';'
-#else
-#define PATH_SEP ':'
-#endif
-
+#include "sass.hpp"
 #include <string>
 #include <cstdlib>
 #include <cstring>
@@ -23,11 +18,13 @@
 #include "output.hpp"
 #include "expand.hpp"
 #include "eval.hpp"
+#include "check_nesting.hpp"
 #include "cssize.hpp"
 #include "listize.hpp"
 #include "extend.hpp"
 #include "remove_placeholders.hpp"
 #include "functions.hpp"
+#include "sass_functions.hpp"
 #include "backtrace.hpp"
 #include "sass2scss.h"
 #include "prelexer.hpp"
@@ -62,13 +59,13 @@
     return safe_path == "" ? "stdout" : safe_path;
   }
 
-  Context::Context(struct Sass_Context* c_ctx)
+  Context::Context(struct Sass_Context& c_ctx)
   : CWD(File::get_cwd()),
+    c_options(c_ctx),
     entry_path(""),
     head_imports(0),
-    mem(Memory_Manager()),
     plugins(),
-    emitter(this),
+    emitter(c_options),
 
     strings(),
     resources(),
@@ -76,19 +73,17 @@
     subset_map(),
     import_stack(),
 
-    c_options               (c_ctx),
-
     c_headers               (std::vector<Sass_Importer_Entry>()),
     c_importers             (std::vector<Sass_Importer_Entry>()),
     c_functions             (std::vector<Sass_Function_Entry>()),
 
-    indent                  (safe_str(c_options->indent, "  ")),
-    linefeed                (safe_str(c_options->linefeed, "\n")),
+    indent                  (safe_str(c_options.indent, "  ")),
+    linefeed                (safe_str(c_options.linefeed, "\n")),
 
-    input_path              (make_canonical_path(safe_input(c_options->input_path))),
-    output_path             (make_canonical_path(safe_output(c_options->output_path, input_path))),
-    source_map_file         (make_canonical_path(safe_str(c_options->source_map_file, ""))),
-    source_map_root         (make_canonical_path(safe_str(c_options->source_map_root, "")))
+    input_path              (make_canonical_path(safe_input(c_options.input_path))),
+    output_path             (make_canonical_path(safe_output(c_options.output_path, input_path))),
+    source_map_file         (make_canonical_path(safe_str(c_options.source_map_file, ""))),
+    source_map_root         (make_canonical_path(safe_str(c_options.source_map_root, "")))
 
   {
 
@@ -96,10 +91,10 @@
     include_paths.push_back(CWD);
 
     // collect more paths from different options
-    collect_include_paths(sass_option_get_include_path(c_options));
-    // collect_include_paths(initializers.include_paths_array());
-    collect_plugin_paths(sass_option_get_plugin_path(c_options));
-    // collect_plugin_paths(initializers.plugin_paths_array());
+    collect_include_paths(c_options.include_path);
+    collect_include_paths(c_options.include_paths);
+    collect_plugin_paths(c_options.plugin_path);
+    collect_plugin_paths(c_options.plugin_paths);
 
     // load plugins and register custom behaviors
     for(auto plug : plugin_paths) plugins.load_plugins(plug);
@@ -150,6 +145,7 @@
     }
     // clear inner structures (vectors) and input source
     resources.clear(); import_stack.clear();
+    subset_map.clear(), sheets.clear();
   }
 
   Data_Context::~Data_Context()
@@ -167,7 +163,6 @@
 
   void Context::collect_include_paths(const char* paths_str)
   {
-
     if (paths_str) {
       const char* beg = paths_str;
       const char* end = Prelexer::find_first<PATH_SEP>(beg);
@@ -190,17 +185,17 @@
     }
   }
 
-  void Context::collect_include_paths(const char** paths_array)
+  void Context::collect_include_paths(string_list* paths_array)
   {
-    if (!paths_array) return;
-    for (size_t i = 0; paths_array[i]; i++) {
-      collect_include_paths(paths_array[i]);
+    while (paths_array)
+    {
+      collect_include_paths(paths_array->string);
+      paths_array = paths_array->next;
     }
   }
 
   void Context::collect_plugin_paths(const char* paths_str)
   {
-
     if (paths_str) {
       const char* beg = paths_str;
       const char* end = Prelexer::find_first<PATH_SEP>(beg);
@@ -223,15 +218,15 @@
     }
   }
 
-  void Context::collect_plugin_paths(const char** paths_array)
+  void Context::collect_plugin_paths(string_list* paths_array)
   {
-    if (!paths_array) return;
-    for (size_t i = 0; paths_array[i]; i++) {
-      collect_plugin_paths(paths_array[i]);
+    while (paths_array)
+    {
+      collect_plugin_paths(paths_array->string);
+      paths_array = paths_array->next;
     }
   }
 
-
   // resolve the imp_path in base_path or include_paths
   // looks for alternatives and returns a list from one directory
   std::vector<Include> Context::find_includes(const Importer& import)
@@ -254,7 +249,7 @@
 
   // 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)
+  void Context::register_resource(const Include& inc, const Resource& res, ParserState* prstate)
   {
 
     // do not parse same resource twice
@@ -294,22 +289,40 @@
     const char* contents = resources[idx].contents;
     // keep a copy of the path around (for parserstates)
     // ToDo: we clean it, but still not very elegant!?
-    strings.push_back(sass_strdup(inc.abs_path.c_str()));
+    strings.push_back(sass_copy_c_string(inc.abs_path.c_str()));
     // create the initial parser state from resource
     ParserState pstate(strings.back(), contents, idx);
+
+    // check existing import stack for possible recursion
+    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 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);
+        }
+        // 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);
+        // 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));
     // do not yet dispose these buffers
     sass_import_take_source(import);
     sass_import_take_srcmap(import);
     // then parse the root block
-    Block* root = p.parse();
+    Block_Obj root = p.parse();
     // delete memory of current stack frame
     sass_delete_import(import_stack.back());
     // remove current stack frame
     import_stack.pop_back();
     // create key/value pair for ast node
-    std::pair<const std::string, const StyleSheet>
+    std::pair<const std::string, StyleSheet>
       ast_pair(inc.abs_path, { res, root });
     // register resulting resource
     sheets.insert(ast_pair);
@@ -338,13 +351,14 @@
 
     // process the resolved entry
     else if (resolved.size() == 1) {
+      bool use_cache = c_importers.size() == 0;
       // use cache for the resource loading
-      if (sheets.count(resolved[0].abs_path)) return resolved[0];
+      if (use_cache && sheets.count(resolved[0].abs_path)) return resolved[0];
       // try to read the content of the resolved file entry
       // 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 });
+        register_resource(resolved[0], { contents, 0 }, &pstate);
         // return resolved entry
         return resolved[0];
       }
@@ -355,7 +369,7 @@
 
   }
 
-  void Context::import_url (Import* imp, std::string load_path, const std::string& ctx_path) {
+  void Context::import_url (Import_Ptr imp, std::string load_path, const std::string& ctx_path) {
 
     ParserState pstate(imp->pstate());
     std::string imp_path(unquote(load_path));
@@ -365,30 +379,27 @@
     if (const char* proto = sequence< identifier, exactly<':'>, exactly<'/'>, exactly<'/'> >(imp_path.c_str())) {
 
       protocol = std::string(imp_path.c_str(), proto - 3);
-      // std::cerr << "==================== " << protocol << "\n";
-      if (protocol.compare("file") && true) {
-
-      }
+      // if (protocol.compare("file") && true) { }
     }
 
     // add urls (protocol other than file) and urls without procotol to `urls` member
     // ToDo: if ctx_path is already a file resource, we should not add it here?
-    if (imp->media_queries() || protocol != "file" || imp_path.substr(0, 2) == "//") {
-      imp->urls().push_back(SASS_MEMORY_NEW(mem, String_Quoted, imp->pstate(), load_path));
+    if (imp->import_queries() || protocol != "file" || imp_path.substr(0, 2) == "//") {
+      imp->urls().push_back(SASS_MEMORY_NEW(String_Quoted, imp->pstate(), load_path));
     }
     else if (imp_path.length() > 4 && imp_path.substr(imp_path.length() - 4, 4) == ".css") {
-      String_Constant* loc = SASS_MEMORY_NEW(mem, String_Constant, pstate, unquote(load_path));
-      Argument* loc_arg = SASS_MEMORY_NEW(mem, Argument, pstate, loc);
-      Arguments* loc_args = SASS_MEMORY_NEW(mem, Arguments, pstate);
-      (*loc_args) << loc_arg;
-      Function_Call* new_url = SASS_MEMORY_NEW(mem, Function_Call, pstate, "url", loc_args);
+      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);
       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 + ".\nParent style sheet: " + ctx_path, pstate);
       }
       imp->incs().push_back(include);
     }
@@ -397,7 +408,7 @@
 
 
   // call custom importers on the given (unquoted) load_path and eventually parse the resulting style_sheet
-  bool Context::call_loader(const std::string& load_path, const char* ctx_path, ParserState& pstate, Import* imp, std::vector<Sass_Importer_Entry> importers, bool only_one)
+  bool Context::call_loader(const std::string& load_path, const char* ctx_path, ParserState& pstate, Import_Ptr imp, std::vector<Sass_Importer_Entry> importers, bool only_one)
   {
     // unique counter
     size_t count = 0;
@@ -426,14 +437,14 @@
           // query data from the current include
           Sass_Import_Entry include = *it_includes;
           char* source = sass_import_take_source(include);
-          char* srcmap = 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);
           // 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 });
+            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)));
           }
@@ -447,7 +458,7 @@
             // attach information to AST node
             imp->incs().push_back(include);
             // register the resource buffers
-            register_resource(include, { source, srcmap });
+            register_resource(include, { source, srcmap }, &pstate);
           }
           // only a path was retuned
           // try to load it like normal
@@ -483,7 +494,7 @@
   void register_c_functions(Context&, Env* env, Sass_Function_List);
   void register_c_function(Context&, Env* env, Sass_Function_Entry);
 
-  char* Context::render(Block* root)
+  char* Context::render(Block_Obj root)
   {
     // check for valid block
     if (!root) return 0;
@@ -494,9 +505,9 @@
     // get the resulting buffer from stream
     OutputBuffer emitted = emitter.get_buffer();
     // should we append a source map url?
-    if (!c_options->omit_source_map_url) {
+    if (!c_options.omit_source_map_url) {
       // generate an embeded source map
-      if (c_options->source_map_embed) {
+      if (c_options.source_map_embed) {
         emitted.buffer += linefeed;
         emitted.buffer += format_embedded_source_map();
       }
@@ -508,27 +519,27 @@
     }
     // create a copy of the resulting buffer string
     // this must be freed or taken over by implementor
-    return sass_strdup(emitted.buffer.c_str());
+    return sass_copy_c_string(emitted.buffer.c_str());
   }
 
-  void Context::apply_custom_headers(Block* root, const char* ctx_path, ParserState pstate)
+  void Context::apply_custom_headers(Block_Obj root, const char* ctx_path, ParserState pstate)
   {
     // create a custom import to resolve headers
-    Import* imp = SASS_MEMORY_NEW(mem, Import, pstate);
+    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) << 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) << SASS_MEMORY_NEW(mem, Import_Stub, pstate, imp->incs()[i]);
+      root->append(SASS_MEMORY_NEW(Import_Stub, pstate, imp->incs()[i]));
     }
   }
 
-  Block* File_Context::parse()
+  Block_Obj File_Context::parse()
   {
 
     // check if entry file is given
@@ -551,7 +562,7 @@
     }
 
     // abort early if no content could be loaded (various reasons)
-    if (!contents) throw "File to read not found or unreadable: " + input_path;
+    if (!contents) throw std::runtime_error("File to read not found or unreadable: " + input_path);
 
     // store entry path
     entry_path = abs_path;
@@ -574,14 +585,14 @@
 
   }
 
-  Block* Data_Context::parse()
+  Block_Obj Data_Context::parse()
   {
 
     // check if source string is given
     if (!source_c_str) return 0;
 
     // convert indented sass syntax
-    if(c_options->is_indented_syntax_src) {
+    if(c_options.is_indented_syntax_src) {
       // call sass2scss to convert the string
       char * converted = sass2scss(source_c_str,
         // preserve the structure as much as possible
@@ -595,7 +606,7 @@
 
     // ToDo: this may be resolved via custom importers
     std::string abs_path(rel2abs(entry_path));
-    char* abs_path_c_str = sass_strdup(abs_path.c_str());
+    char* abs_path_c_str = sass_copy_c_string(abs_path.c_str());
     strings.push_back(abs_path_c_str);
 
     // create entry only for the import stack
@@ -618,15 +629,14 @@
 
 
   // parse root block from includes
-  Block* Context::compile()
+  Block_Obj Context::compile()
   {
     // abort if there is no data
     if (resources.size() == 0) return 0;
     // get root block from the first style sheet
-    Block* root = sheets.at(entry_path).root;
+    Block_Obj root = sheets.at(entry_path).root;
     // abort on invalid root
-    if (root == 0) return 0;
-
+    if (root.isNull()) return 0;
     Env global; // create root environment
     // register built-in functions on env
     register_built_in_functions(*this, &global);
@@ -638,16 +648,21 @@
     // create crtp visitor objects
     Expand expand(*this, &global, &backtrace);
     Cssize cssize(*this, &backtrace);
+    CheckNesting check_nesting;
+    // check nesting
+    check_nesting(&root);
     // expand and eval the tree
-    root = root->perform(&expand)->block();
+    root = expand(&root);
+    // check nesting
+    check_nesting(&root);
     // merge and bubble certain rules
-    root = root->perform(&cssize)->block();
+    root = cssize(&root);
     // should we extend something?
     if (!subset_map.empty()) {
       // create crtp visitor object
       Extend extend(*this, subset_map);
       // extend tree nodes
-      root->perform(&extend);
+      extend(&root);
     }
 
     // clean up by removing empty placeholders
@@ -682,7 +697,7 @@
     if (source_map_file == "") return 0;
     char* result = 0;
     std::string map = emitter.render_srcmap(*this);
-    result = sass_strdup(map.c_str());
+    result = sass_copy_c_string(map.c_str());
     return result;
   }
 
@@ -703,14 +718,14 @@
 
   void register_function(Context& ctx, Signature sig, Native_Function f, Env* env)
   {
-    Definition* def = make_native_function(sig, f, ctx);
+    Definition_Ptr def = make_native_function(sig, f, ctx);
     def->environment(env);
     (*env)[def->name() + "[f]"] = def;
   }
 
   void register_function(Context& ctx, Signature sig, Native_Function f, size_t arity, Env* env)
   {
-    Definition* def = make_native_function(sig, f, ctx);
+    Definition_Ptr def = make_native_function(sig, f, ctx);
     std::stringstream ss;
     ss << def->name() << "[f]" << arity;
     def->environment(env);
@@ -719,7 +734,7 @@
 
   void register_overload_stub(Context& ctx, std::string name, Env* env)
   {
-    Definition* stub = SASS_MEMORY_NEW(ctx.mem, Definition,
+    Definition_Ptr stub = SASS_MEMORY_NEW(Definition,
                                        ParserState("[built-in function]"),
                                        0,
                                        name,
@@ -840,7 +855,7 @@
   }
   void register_c_function(Context& ctx, Env* env, Sass_Function_Entry descr)
   {
-    Definition* def = make_c_function(descr, ctx);
+    Definition_Ptr def = make_c_function(descr, ctx);
     def->environment(env);
     (*env)[def->name() + "[f]"] = def;
   }
diff --git a/libsass/src/context.hpp b/libsass/src/context.hpp
--- a/libsass/src/context.hpp
+++ b/libsass/src/context.hpp
@@ -10,7 +10,6 @@
 
 #include "ast_fwd_decl.hpp"
 #include "kwd_arg_macros.hpp"
-#include "memory_manager.hpp"
 #include "ast_fwd_decl.hpp"
 #include "sass_context.hpp"
 #include "environment.hpp"
@@ -27,20 +26,20 @@
 
   class Context {
   public:
-    void import_url (Import* imp, std::string load_path, const std::string& ctx_path);
-    bool call_headers(const std::string& load_path, const char* ctx_path, ParserState& pstate, Import* imp)
+    void import_url (Import_Ptr imp, std::string load_path, const std::string& ctx_path);
+    bool call_headers(const std::string& load_path, const char* ctx_path, ParserState& pstate, Import_Ptr imp)
     { return call_loader(load_path, ctx_path, pstate, imp, c_headers, false); };
-    bool call_importers(const std::string& load_path, const char* ctx_path, ParserState& pstate, Import* imp)
+    bool call_importers(const std::string& load_path, const char* ctx_path, ParserState& pstate, Import_Ptr imp)
     { return call_loader(load_path, ctx_path, pstate, imp, c_importers, true); };
 
   private:
-    bool call_loader(const std::string& load_path, const char* ctx_path, ParserState& pstate, Import* imp, std::vector<Sass_Importer_Entry> importers, bool only_one = true);
+    bool call_loader(const std::string& load_path, const char* ctx_path, ParserState& pstate, Import_Ptr imp, std::vector<Sass_Importer_Entry> importers, bool only_one = true);
 
   public:
     const std::string CWD;
+    struct Sass_Options& c_options;
     std::string entry_path;
     size_t head_imports;
-    Memory_Manager mem;
     Plugins plugins;
     Output emitter;
 
@@ -48,12 +47,11 @@
     // these are guaranteed to be freed
     std::vector<char*> strings;
     std::vector<Resource> resources;
-    std::map<const std::string, const StyleSheet> sheets;
-    Subset_Map<std::string, std::pair<Complex_Selector*, Compound_Selector*> > subset_map;
+    std::map<const std::string, StyleSheet> sheets;
+    Subset_Map subset_map;
     std::vector<Sass_Import_Entry> import_stack;
 
     struct Sass_Compiler* c_compiler;
-    struct Sass_Options* c_options;
 
     // absolute paths to includes
     std::vector<std::string> included_files;
@@ -68,7 +66,7 @@
 
 
 
-    void apply_custom_headers(Block* root, const char* path, ParserState pstate);
+    void apply_custom_headers(Block_Obj root, const char* path, ParserState pstate);
 
     std::vector<Sass_Importer_Entry> c_headers;
     std::vector<Sass_Importer_Entry> c_importers;
@@ -86,24 +84,24 @@
     const std::string source_map_root; // path for sourceRoot property (pass-through)
 
     virtual ~Context();
-    Context(struct Sass_Context*);
-    virtual Block* parse() = 0;
-    virtual Block* compile();
-    virtual char* render(Block* root);
+    Context(struct Sass_Context&);
+    virtual Block_Obj parse() = 0;
+    virtual Block_Obj compile();
+    virtual char* render(Block_Obj root);
     virtual char* render_srcmap();
 
-    void register_resource(const Include&, const Resource&);
+    void register_resource(const Include&, const Resource&, ParserState* = 0);
     std::vector<Include> find_includes(const Importer& import);
     Include load_import(const Importer&, ParserState pstate);
 
-    Sass_Output_Style output_style() { return c_options->output_style; };
+    Sass_Output_Style output_style() { return c_options.output_style; };
     std::vector<std::string> get_included_files(bool skip = false, size_t headers = 0);
 
   private:
     void collect_plugin_paths(const char* paths_str);
-    void collect_plugin_paths(const char** paths_array);
+    void collect_plugin_paths(string_list* paths_array);
     void collect_include_paths(const char* paths_str);
-    void collect_include_paths(const char** paths_array);
+    void collect_include_paths(string_list* paths_array);
     std::string format_embedded_source_map();
     std::string format_source_mapping_url(const std::string& out_path);
 
@@ -119,27 +117,27 @@
 
   class File_Context : public Context {
   public:
-    File_Context(struct Sass_File_Context* ctx)
+    File_Context(struct Sass_File_Context& ctx)
     : Context(ctx)
     { }
     virtual ~File_Context();
-    virtual Block* parse();
+    virtual Block_Obj parse();
   };
 
   class Data_Context : public Context {
   public:
     char* source_c_str;
     char* srcmap_c_str;
-    Data_Context(struct Sass_Data_Context* ctx)
+    Data_Context(struct Sass_Data_Context& ctx)
     : Context(ctx)
     {
-      source_c_str       = ctx->source_string;
-      srcmap_c_str       = ctx->srcmap_string;
-      ctx->source_string = 0; // passed away
-      ctx->srcmap_string = 0; // passed away
+      source_c_str       = ctx.source_string;
+      srcmap_c_str       = ctx.srcmap_string;
+      ctx.source_string = 0; // passed away
+      ctx.srcmap_string = 0; // passed away
     }
     virtual ~Data_Context();
-    virtual Block* parse();
+    virtual Block_Obj parse();
   };
 
 }
diff --git a/libsass/src/cssize.cpp b/libsass/src/cssize.cpp
--- a/libsass/src/cssize.cpp
+++ b/libsass/src/cssize.cpp
@@ -1,9 +1,9 @@
+#include "sass.hpp"
 #include <iostream>
 #include <typeinfo>
 #include <vector>
 
 #include "cssize.hpp"
-#include "to_string.hpp"
 #include "context.hpp"
 #include "backtrace.hpp"
 
@@ -11,157 +11,224 @@
 
   Cssize::Cssize(Context& ctx, Backtrace* bt)
   : ctx(ctx),
-    block_stack(std::vector<Block*>()),
-    p_stack(std::vector<Statement*>()),
+    block_stack(std::vector<Block_Ptr>()),
+    p_stack(std::vector<Statement_Ptr>()),
     backtrace(bt)
-  {  }
+  { }
 
-  Statement* Cssize::parent()
+  Statement_Ptr Cssize::parent()
   {
     return p_stack.size() ? p_stack.back() : block_stack.front();
   }
 
-  Statement* Cssize::operator()(Block* b)
+  Block_Ptr Cssize::operator()(Block_Ptr b)
   {
-    Block* bb = SASS_MEMORY_NEW(ctx.mem, Block, b->pstate(), b->length(), b->is_root());
+    Block_Ptr bb = SASS_MEMORY_NEW(Block, b->pstate(), b->length(), b->is_root());
     // bb->tabs(b->tabs());
     block_stack.push_back(bb);
-    append_block(b);
+    append_block(b, bb);
     block_stack.pop_back();
     return bb;
   }
 
-  Statement* Cssize::operator()(At_Rule* r)
+  Statement_Ptr Cssize::operator()(Trace_Ptr t)
   {
+    return t->block()->perform(this);
+  }
+
+  Statement_Ptr Cssize::operator()(Declaration_Ptr d)
+  {
+    String_Obj property = SASS_MEMORY_CAST(String, d->property());
+
+    if (Declaration_Ptr dd = dynamic_cast<Declaration_Ptr>(parent())) {
+      String_Obj parent_property = SASS_MEMORY_CAST(String, dd->property());
+      property = SASS_MEMORY_NEW(String_Constant,
+                                 d->property()->pstate(),
+                                 parent_property->to_string() + "-" + property->to_string());
+      if (!dd->value()) {
+        d->tabs(dd->tabs() + 1);
+      }
+    }
+
+    Declaration_Obj dd = SASS_MEMORY_NEW(Declaration,
+                                      d->pstate(),
+                                      property,
+                                      d->value(),
+                                      d->is_important());
+    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.pop_back();
+
+    if (bb && bb->length()) {
+      if (dd->value() && !dd->value()->is_invisible()) {
+        bb->unshift(&dd);
+      }
+      return bb.detach();
+    }
+    else if (dd->value() && !dd->value()->is_invisible()) {
+      return dd.detach();
+    }
+
+    return 0;
+  }
+
+  Statement_Ptr Cssize::operator()(Directive_Ptr r)
+  {
     if (!r->block() || !r->block()->length()) return r;
 
     if (parent()->statement_type() == Statement::RULESET)
     {
-      return (r->is_keyframes()) ? SASS_MEMORY_NEW(ctx.mem, Bubble, r->pstate(), r) : bubble(r);
+      return (r->is_keyframes()) ? SASS_MEMORY_NEW(Bubble, r->pstate(), r) : bubble(r);
     }
 
     p_stack.push_back(r);
-    At_Rule* rr = SASS_MEMORY_NEW(ctx.mem, At_Rule,
+    Directive_Obj rr = SASS_MEMORY_NEW(Directive,
                                   r->pstate(),
                                   r->keyword(),
                                   r->selector(),
-                                  r->block() ? r->block()->perform(this)->block() : 0);
+                                  r->block() ? operator()(&r->block()) : 0);
     if (r->value()) rr->value(r->value());
     p_stack.pop_back();
 
     bool directive_exists = false;
     size_t L = rr->block() ? rr->block()->length() : 0;
     for (size_t i = 0; i < L && !directive_exists; ++i) {
-      Statement* s = (*r->block())[i];
+      Statement_Obj s = r->block()->at(i);
       if (s->statement_type() != Statement::BUBBLE) directive_exists = true;
       else {
-        s = static_cast<Bubble*>(s)->node();
+        Bubble_Obj s_obj = SASS_MEMORY_CAST(Bubble, s);
+        s = s_obj->node();
         if (s->statement_type() != Statement::DIRECTIVE) directive_exists = false;
-        else directive_exists = (static_cast<At_Rule*>(s)->keyword() == rr->keyword());
+        else directive_exists = (static_cast<Directive_Ptr>(&s)->keyword() == rr->keyword());
       }
 
     }
 
-    Block* result = SASS_MEMORY_NEW(ctx.mem, Block, rr->pstate());
+    Block_Ptr result = SASS_MEMORY_NEW(Block, rr->pstate());
     if (!(directive_exists || rr->is_keyframes()))
     {
-      At_Rule* empty_node = static_cast<At_Rule*>(rr);
-      empty_node->block(SASS_MEMORY_NEW(ctx.mem, Block, rr->block() ? rr->block()->pstate() : rr->pstate()));
-      *result << empty_node;
+      Directive_Ptr empty_node = SASS_MEMORY_CAST(Directive, rr);
+      empty_node->block(SASS_MEMORY_NEW(Block, rr->block() ? rr->block()->pstate() : rr->pstate()));
+      result->append(empty_node);
     }
 
-    Statement* ss = debubble(rr->block() ? rr->block() : SASS_MEMORY_NEW(ctx.mem, Block, rr->pstate()), rr);
-    for (size_t i = 0, L = ss->block()->length(); i < L; ++i) {
-      *result << (*ss->block())[i];
+    Block_Obj ss = debubble(rr->block() ? &rr->block() : SASS_MEMORY_NEW(Block, rr->pstate()), &rr);
+    for (size_t i = 0, L = ss->length(); i < L; ++i) {
+      result->append(ss->at(i));
     }
 
     return result;
   }
 
-  Statement* Cssize::operator()(Keyframe_Rule* r)
+  Statement_Ptr Cssize::operator()(Keyframe_Rule_Ptr r)
   {
     if (!r->block() || !r->block()->length()) return r;
 
-    Keyframe_Rule* rr = SASS_MEMORY_NEW(ctx.mem, Keyframe_Rule,
+    Keyframe_Rule_Obj rr = SASS_MEMORY_NEW(Keyframe_Rule,
                                         r->pstate(),
-                                        r->block()->perform(this)->block());
-    if (r->selector()) rr->selector(r->selector());
+                                        operator()(&r->block()));
+    if (&r->name()) rr->name(r->name());
 
-    return debubble(rr->block(), rr)->block();
+    return debubble(&rr->block(), &rr);
   }
 
-  Statement* Cssize::operator()(Ruleset* r)
+  Statement_Ptr Cssize::operator()(Ruleset_Ptr r)
   {
     p_stack.push_back(r);
-    Ruleset* rr = SASS_MEMORY_NEW(ctx.mem, Ruleset,
+    // this can return a string schema
+    // 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());
+    // 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());
+    }
+    Ruleset_Obj rr = SASS_MEMORY_NEW(Ruleset,
                                   r->pstate(),
                                   r->selector(),
-                                  r->block()->perform(this)->block());
+                                  bb);
+
+    rr->is_root(r->is_root());
     // rr->tabs(r->block()->tabs());
     p_stack.pop_back();
 
-    Block* props = SASS_MEMORY_NEW(ctx.mem, Block, rr->block()->pstate());
-    Block* rules = SASS_MEMORY_NEW(ctx.mem, Block, rr->block()->pstate());
+    if (!rr->block()) {
+      error("Illegal nesting: Only properties may be nested beneath properties.", r->block()->pstate());
+    }
+
+    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* s = (*rr->block())[i];
-      if (bubblable(s)) *rules << s;
-      if (!bubblable(s)) *props << s;
+      Statement_Ptr s = &rr->block()->at(i);
+      if (bubblable(s)) rules->append(s);
+      if (!bubblable(s)) props->append(s);
     }
 
     if (props->length())
     {
-      Block* bb = SASS_MEMORY_NEW(ctx.mem, Block, rr->block()->pstate());
-      *bb += props;
+      Block_Obj bb = SASS_MEMORY_NEW(Block, rr->block()->pstate());
+      bb->concat(&props);
       rr->block(bb);
 
       for (size_t i = 0, L = rules->length(); i < L; i++)
       {
-        (*rules)[i]->tabs((*rules)[i]->tabs() + 1);
+        Statement_Ptr stm = &rules->at(i);
+        stm->tabs(stm->tabs() + 1);
       }
 
-      rules->unshift(rr);
+      rules->unshift(&rr);
     }
 
-    rules = debubble(rules)->block();
+    Block_Ptr ptr = rules;
+    rules = debubble(rules);
+    void* lp = ptr;
+    void* rp = rules;
+    if (lp != rp) {
+      Block_Obj obj = ptr;
+    }
 
     if (!(!rules->length() ||
-          !bubblable(rules->last()) ||
+          !bubblable(&rules->last()) ||
           parent()->statement_type() == Statement::RULESET))
     {
       rules->last()->group_end(true);
     }
-
     return rules;
   }
 
-  Statement* Cssize::operator()(Null* m)
+  Statement_Ptr Cssize::operator()(Null_Ptr m)
   {
     return 0;
   }
 
-  Statement* Cssize::operator()(Media_Block* m)
+  Statement_Ptr Cssize::operator()(Media_Block_Ptr m)
   {
     if (parent()->statement_type() == Statement::RULESET)
     { return bubble(m); }
 
     if (parent()->statement_type() == Statement::MEDIA)
-    { return SASS_MEMORY_NEW(ctx.mem, Bubble, m->pstate(), m); }
+    { return SASS_MEMORY_NEW(Bubble, m->pstate(), m); }
 
     p_stack.push_back(m);
 
-    Media_Block* mm = SASS_MEMORY_NEW(ctx.mem, Media_Block,
+    Media_Block_Obj mm = SASS_MEMORY_NEW(Media_Block,
                                       m->pstate(),
-                                      m->media_queries(),
-                                      m->block()->perform(this)->block());
+                                      &m->media_queries(),
+                                      operator()(&m->block()));
     mm->tabs(m->tabs());
 
     p_stack.pop_back();
 
-    return debubble(mm->block(), mm)->block();
+    return debubble(&mm->block(), &mm);
   }
 
-  Statement* Cssize::operator()(Supports_Block* m)
+  Statement_Ptr Cssize::operator()(Supports_Block_Ptr m)
   {
     if (!m->block()->length())
     { return m; }
@@ -171,339 +238,302 @@
 
     p_stack.push_back(m);
 
-    Supports_Block* mm = SASS_MEMORY_NEW(ctx.mem, Supports_Block,
+    Supports_Block_Obj mm = SASS_MEMORY_NEW(Supports_Block,
                                        m->pstate(),
-                                       m->condition(),
-                                       m->block()->perform(this)->block());
+                                       &m->condition(),
+                                       operator()(&m->block()));
     mm->tabs(m->tabs());
 
     p_stack.pop_back();
 
-    return debubble(mm->block(), mm)->block();
+    return debubble(&mm->block(), &mm);
   }
 
-  Statement* Cssize::operator()(At_Root_Block* m)
+  Statement_Ptr Cssize::operator()(At_Root_Block_Ptr m)
   {
     bool tmp = false;
     for (size_t i = 0, L = p_stack.size(); i < L; ++i) {
-      Statement* s = p_stack[i];
+      Statement_Ptr s = p_stack[i];
       tmp |= m->exclude_node(s);
     }
 
     if (!tmp)
     {
-      Block* bb = m->block()->perform(this)->block();
+      Block_Ptr bb = operator()(&m->block());
       for (size_t i = 0, L = bb->length(); i < L; ++i) {
         // (bb->elements())[i]->tabs(m->tabs());
-        if (bubblable((*bb)[i])) (*bb)[i]->tabs((*bb)[i]->tabs() + m->tabs());
+        Statement_Obj stm = bb->at(i);
+        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;
     }
 
     if (m->exclude_node(parent()))
     {
-      return SASS_MEMORY_NEW(ctx.mem, Bubble, m->pstate(), m);
+      return SASS_MEMORY_NEW(Bubble, m->pstate(), m);
     }
 
     return bubble(m);
   }
 
-  Statement* Cssize::bubble(At_Rule* m)
+  Statement_Ptr Cssize::bubble(Directive_Ptr m)
   {
-    Block* bb = SASS_MEMORY_NEW(ctx.mem, Block, this->parent()->pstate());
-    Has_Block* new_rule = static_cast<Has_Block*>(shallow_copy(this->parent()));
+    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());
-
-    size_t L = m->block() ? m->block()->length() : 0;
-    for (size_t i = 0; i < L; ++i) {
-      *new_rule->block() << (*m->block())[i];
-    }
+    new_rule->block()->concat(&m->block());
 
-    Block* wrapper_block = SASS_MEMORY_NEW(ctx.mem, Block, m->block() ? m->block()->pstate() : m->pstate());
-    *wrapper_block << new_rule;
-    At_Rule* mm = SASS_MEMORY_NEW(ctx.mem, At_Rule,
+    Block_Obj wrapper_block = SASS_MEMORY_NEW(Block, m->block() ? m->block()->pstate() : m->pstate());
+    wrapper_block->append(&new_rule);
+    Directive_Obj mm = SASS_MEMORY_NEW(Directive,
                                   m->pstate(),
                                   m->keyword(),
                                   m->selector(),
                                   wrapper_block);
     if (m->value()) mm->value(m->value());
 
-    Bubble* bubble = SASS_MEMORY_NEW(ctx.mem, Bubble, mm->pstate(), mm);
+    Bubble_Ptr bubble = SASS_MEMORY_NEW(Bubble, mm->pstate(), &mm);
     return bubble;
   }
 
-  Statement* Cssize::bubble(At_Root_Block* m)
+  Statement_Ptr Cssize::bubble(At_Root_Block_Ptr m)
   {
-    Block* bb = SASS_MEMORY_NEW(ctx.mem, Block, this->parent()->pstate());
-    Has_Block* new_rule = static_cast<Has_Block*>(shallow_copy(this->parent()));
+    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());
-
-    for (size_t i = 0, L = m->block()->length(); i < L; ++i) {
-      *new_rule->block() << (*m->block())[i];
-    }
+    new_rule->block()->concat(&m->block());
 
-    Block* wrapper_block = SASS_MEMORY_NEW(ctx.mem, Block, m->block()->pstate());
-    *wrapper_block << new_rule;
-    At_Root_Block* mm = SASS_MEMORY_NEW(ctx.mem, At_Root_Block,
+    Block_Ptr wrapper_block = SASS_MEMORY_NEW(Block, m->block()->pstate());
+    wrapper_block->append(&new_rule);
+    At_Root_Block_Ptr mm = SASS_MEMORY_NEW(At_Root_Block,
                                         m->pstate(),
                                         wrapper_block,
                                         m->expression());
-    Bubble* bubble = SASS_MEMORY_NEW(ctx.mem, Bubble, mm->pstate(), mm);
+    Bubble_Ptr bubble = SASS_MEMORY_NEW(Bubble, mm->pstate(), mm);
     return bubble;
   }
 
-  Statement* Cssize::bubble(Supports_Block* m)
+  Statement_Ptr Cssize::bubble(Supports_Block_Ptr m)
   {
-    Ruleset* parent = static_cast<Ruleset*>(shallow_copy(this->parent()));
+    Ruleset_Obj parent = static_cast<Ruleset_Ptr>(SASS_MEMORY_COPY(this->parent()));
 
-    Block* bb = SASS_MEMORY_NEW(ctx.mem, Block, parent->block()->pstate());
-    Ruleset* new_rule = SASS_MEMORY_NEW(ctx.mem, Ruleset,
+    Block_Ptr bb = SASS_MEMORY_NEW(Block, parent->block()->pstate());
+    Ruleset_Ptr new_rule = SASS_MEMORY_NEW(Ruleset,
                                         parent->pstate(),
                                         parent->selector(),
                                         bb);
     new_rule->tabs(parent->tabs());
-
-    for (size_t i = 0, L = m->block()->length(); i < L; ++i) {
-      *new_rule->block() << (*m->block())[i];
-    }
+    new_rule->block()->concat(&m->block());
 
-    Block* wrapper_block = SASS_MEMORY_NEW(ctx.mem, Block, m->block()->pstate());
-    *wrapper_block << new_rule;
-    Supports_Block* mm = SASS_MEMORY_NEW(ctx.mem, Supports_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());
 
-    Bubble* bubble = SASS_MEMORY_NEW(ctx.mem, Bubble, mm->pstate(), mm);
+    Bubble_Ptr bubble = SASS_MEMORY_NEW(Bubble, mm->pstate(), mm);
     return bubble;
   }
 
-  Statement* Cssize::bubble(Media_Block* m)
+  Statement_Ptr Cssize::bubble(Media_Block_Ptr m)
   {
-    Ruleset* parent = static_cast<Ruleset*>(shallow_copy(this->parent()));
+    Ruleset_Obj parent = static_cast<Ruleset_Ptr>(SASS_MEMORY_COPY(this->parent()));
 
-    Block* bb = SASS_MEMORY_NEW(ctx.mem, Block, parent->block()->pstate());
-    Ruleset* new_rule = SASS_MEMORY_NEW(ctx.mem, Ruleset,
+    Block_Ptr bb = SASS_MEMORY_NEW(Block, parent->block()->pstate());
+    Ruleset_Ptr new_rule = SASS_MEMORY_NEW(Ruleset,
                                         parent->pstate(),
                                         parent->selector(),
                                         bb);
     new_rule->tabs(parent->tabs());
-
-    for (size_t i = 0, L = m->block()->length(); i < L; ++i) {
-      *new_rule->block() << (*m->block())[i];
-    }
+    new_rule->block()->concat(&m->block());
 
-    Block* wrapper_block = SASS_MEMORY_NEW(ctx.mem, Block, m->block()->pstate());
-    *wrapper_block << new_rule;
-    Media_Block* mm = SASS_MEMORY_NEW(ctx.mem, Media_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(),
+                                      &m->media_queries(),
                                       wrapper_block,
                                       0);
 
     mm->tabs(m->tabs());
 
-    Bubble* bubble = SASS_MEMORY_NEW(ctx.mem, Bubble, mm->pstate(), mm);
-
-    return bubble;
+    return SASS_MEMORY_NEW(Bubble, mm->pstate(), &mm);
   }
 
-  bool Cssize::bubblable(Statement* s)
+  bool Cssize::bubblable(Statement_Ptr s)
   {
-    return s->statement_type() == Statement::RULESET || s->bubbles();
+    return dynamic_cast<Ruleset_Ptr>(s) || s->bubbles();
   }
 
-  Statement* Cssize::flatten(Statement* s)
+  Block_Ptr Cssize::flatten(Block_Ptr b)
   {
-    Block* bb = s->block();
-    Block* result = SASS_MEMORY_NEW(ctx.mem, Block, bb->pstate(), 0, bb->is_root());
-    for (size_t i = 0, L = bb->length(); i < L; ++i) {
-      Statement* ss = (*bb)[i];
-      if (ss->block()) {
-        ss = flatten(ss);
-        for (size_t j = 0, K = ss->block()->length(); j < K; ++j) {
-          *result << (*ss->block())[j];
+    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)) {
+        Block_Obj bs = flatten(bb);
+        for (size_t j = 0, K = bs->length(); j < K; ++j) {
+          result->append(bs->at(j));
         }
       }
       else {
-        *result << ss;
+        result->append(ss);
       }
     }
     return result;
   }
 
-  std::vector<std::pair<bool, Block*>> Cssize::slice_by_bubble(Statement* b)
+  std::vector<std::pair<bool, Block_Obj>> Cssize::slice_by_bubble(Block_Ptr b)
   {
-    std::vector<std::pair<bool, Block*>> results;
-    for (size_t i = 0, L = b->block()->length(); i < L; ++i) {
-      Statement* value = (*b->block())[i];
-      bool key = value->statement_type() == Statement::BUBBLE;
+    std::vector<std::pair<bool, Block_Obj>> results;
 
+    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;
+
       if (!results.empty() && results.back().first == key)
       {
-        Block* wrapper_block = results.back().second;
-        *wrapper_block << value;
+        Block_Obj wrapper_block = results.back().second;
+        wrapper_block->append(value);
       }
       else
       {
-        Block* wrapper_block = SASS_MEMORY_NEW(ctx.mem, Block, value->pstate());
-        *wrapper_block << value;
+        Block_Ptr wrapper_block = SASS_MEMORY_NEW(Block, value->pstate());
+        wrapper_block->append(value);
         results.push_back(std::make_pair(key, wrapper_block));
       }
     }
     return results;
   }
 
-  Statement* Cssize::shallow_copy(Statement* s)
-  {
-    switch (s->statement_type())
-    {
-      case Statement::RULESET:
-        return SASS_MEMORY_NEW(ctx.mem, Ruleset, *static_cast<Ruleset*>(s));
-      case Statement::MEDIA:
-        return SASS_MEMORY_NEW(ctx.mem, Media_Block, *static_cast<Media_Block*>(s));
-      case Statement::BUBBLE:
-        return SASS_MEMORY_NEW(ctx.mem, Bubble, *static_cast<Bubble*>(s));
-      case Statement::DIRECTIVE:
-        return SASS_MEMORY_NEW(ctx.mem, At_Rule, *static_cast<At_Rule*>(s));
-      case Statement::SUPPORTS:
-        return SASS_MEMORY_NEW(ctx.mem, Supports_Block, *static_cast<Supports_Block*>(s));
-      case Statement::ATROOT:
-        return SASS_MEMORY_NEW(ctx.mem, At_Root_Block, *static_cast<At_Root_Block*>(s));
-      case Statement::KEYFRAMERULE:
-        return SASS_MEMORY_NEW(ctx.mem, Keyframe_Rule, *static_cast<Keyframe_Rule*>(s));
-      case Statement::NONE:
-      default:
-        error("unknown internal error; please contact the LibSass maintainers", s->pstate(), backtrace);
-        String_Quoted* msg = SASS_MEMORY_NEW(ctx.mem, String_Quoted, ParserState("[WARN]"), std::string("`CSSize` can't clone ") + typeid(*s).name());
-        return SASS_MEMORY_NEW(ctx.mem, Warning, ParserState("[WARN]"), msg);
-    }
-  }
-
-  Statement* Cssize::debubble(Block* children, Statement* parent)
+  Block_Ptr Cssize::debubble(Block_Ptr children, Statement_Ptr parent)
   {
-    Has_Block* previous_parent = 0;
-    std::vector<std::pair<bool, Block*>> baz = slice_by_bubble(children);
-    Block* result = SASS_MEMORY_NEW(ctx.mem, Block, children->pstate());
+    Has_Block_Obj previous_parent = 0;
+    std::vector<std::pair<bool, Block_Obj>> baz = slice_by_bubble(children);
+    Block_Obj result = SASS_MEMORY_NEW(Block, children->pstate());
 
     for (size_t i = 0, L = baz.size(); i < L; ++i) {
       bool is_bubble = baz[i].first;
-      Block* slice = baz[i].second;
+      Block_Obj slice = baz[i].second;
 
       if (!is_bubble) {
         if (!parent) {
-          *result << slice;
+          result->append(&slice);
         }
         else if (previous_parent) {
-          *previous_parent->block() += slice;
+          previous_parent->block()->concat(&slice);
         }
         else {
-          previous_parent = static_cast<Has_Block*>(shallow_copy(parent));
+          previous_parent = static_cast<Has_Block_Ptr>(SASS_MEMORY_COPY(parent));
+          previous_parent->block(slice);
           previous_parent->tabs(parent->tabs());
 
-          Has_Block* new_parent = static_cast<Has_Block*>(shallow_copy(parent));
-          new_parent->block(slice);
-          new_parent->tabs(parent->tabs());
-
-          *result << new_parent;
+          result->append(&previous_parent);
         }
         continue;
       }
 
-      Block* wrapper_block = SASS_MEMORY_NEW(ctx.mem, Block,
-                                             children->block()->pstate(),
-                                             children->block()->length(),
-                                             children->block()->is_root());
-
       for (size_t j = 0, K = slice->length(); j < K; ++j)
       {
-        Statement* ss = 0;
-        Bubble* b = static_cast<Bubble*>((*slice)[j]);
-
+        Statement_Ptr ss = NULL;
+        Statement_Obj stm = slice->at(j);
+        // this has to go now here (too bad)
+        Bubble_Obj node = SASS_MEMORY_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 ||
             parent->statement_type() != Statement::MEDIA ||
-            b->node()->statement_type() != Statement::MEDIA ||
-            static_cast<Media_Block*>(b->node())->media_queries() == static_cast<Media_Block*>(parent)->media_queries())
+            node->node()->statement_type() != Statement::MEDIA ||
+            (m1 && m2 && &m1->media_queries() == &m2->media_queries())
+          )
         {
-          ss = b->node();
+          ss = &node->node();
         }
         else
         {
-          List* mq = merge_media_queries(static_cast<Media_Block*>(b->node()), static_cast<Media_Block*>(parent));
+          List_Obj mq = merge_media_queries(static_cast<Media_Block_Ptr>(&node->node()), static_cast<Media_Block_Ptr>(parent));
           if (!mq->length()) continue;
-          static_cast<Media_Block*>(b->node())->media_queries(mq);
-          ss = b->node();
+          static_cast<Media_Block_Ptr>(&node->node())->media_queries(mq);
+          ss = &node->node();
         }
 
         if (!ss) continue;
 
-        ss->tabs(ss->tabs() + b->tabs());
-        ss->group_end(b->group_end());
+        ss->tabs(ss->tabs() + node->tabs());
+        ss->group_end(node->group_end());
 
         if (!ss) continue;
 
-        Block* bb = SASS_MEMORY_NEW(ctx.mem, Block,
-                                    children->block()->pstate(),
-                                    children->block()->length(),
-                                    children->block()->is_root());
-        *bb << ss->perform(this);
-        Statement* wrapper = flatten(bb);
-        *wrapper_block << wrapper;
+        Block_Obj bb = SASS_MEMORY_NEW(Block,
+                                    children->pstate(),
+                                    children->length(),
+                                    children->is_root());
+        bb->append(ss->perform(this));
 
-        if (wrapper->block()->length()) {
-          previous_parent = 0;
+        Block_Obj wrapper_block = SASS_MEMORY_NEW(Block,
+                                              children->pstate(),
+                                              children->length(),
+                                              children->is_root());
+
+        Block_Ptr wrapper = flatten(&bb);
+        wrapper_block->append(wrapper);
+
+        if (wrapper->length()) {
+          previous_parent = NULL;
         }
-      }
 
-      if (wrapper_block) {
-        *result << flatten(wrapper_block);
+        if (wrapper_block) {
+          result->append(&wrapper_block);
+        }
       }
     }
 
-    return flatten(result);
+    return flatten(&result);
   }
 
-  Statement* Cssize::fallback_impl(AST_Node* n)
+  Statement_Ptr Cssize::fallback_impl(AST_Node_Ptr n)
   {
-    return static_cast<Statement*>(n);
+    return static_cast<Statement_Ptr>(n);
   }
 
-  void Cssize::append_block(Block* b)
+  void Cssize::append_block(Block_Ptr b, Block_Ptr cur)
   {
-    Block* current_block = block_stack.back();
-
     for (size_t i = 0, L = b->length(); i < L; ++i) {
-      Statement* ith = (*b)[i]->perform(this);
-      if (ith && ith->block()) {
-        for (size_t j = 0, K = ith->block()->length(); j < K; ++j) {
-          *current_block << (*ith->block())[j];
+      Statement_Obj ith = b->at(i)->perform(this);
+      if (Block_Ptr bb = SASS_MEMORY_CAST(Block, ith)) {
+        for (size_t j = 0, K = bb->length(); j < K; ++j) {
+          cur->append(bb->at(j));
         }
       }
       else if (ith) {
-        *current_block << ith;
+        cur->append(ith);
       }
     }
   }
 
-  List* Cssize::merge_media_queries(Media_Block* m1, Media_Block* m2)
+  List_Ptr Cssize::merge_media_queries(Media_Block_Ptr m1, Media_Block_Ptr m2)
   {
-    List* qq = SASS_MEMORY_NEW(ctx.mem, List,
+    List_Ptr qq = SASS_MEMORY_NEW(List,
                                m1->media_queries()->pstate(),
                                m1->media_queries()->length(),
                                SASS_COMMA);
 
     for (size_t i = 0, L = m1->media_queries()->length(); i < L; i++) {
       for (size_t j = 0, K = m2->media_queries()->length(); j < K; j++) {
-        Media_Query* mq1 = static_cast<Media_Query*>((*m1->media_queries())[i]);
-        Media_Query* mq2 = static_cast<Media_Query*>((*m2->media_queries())[j]);
-        Media_Query* mq = merge_media_query(mq1, mq2);
-
-        if (mq) *qq << mq;
+        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 mq = merge_media_query(mq1, mq2);
+        if (mq) qq->append(mq);
       }
     }
 
@@ -511,17 +541,16 @@
   }
 
 
-  Media_Query* Cssize::merge_media_query(Media_Query* mq1, Media_Query* mq2)
+  Media_Query_Ptr Cssize::merge_media_query(Media_Query_Ptr mq1, Media_Query_Ptr mq2)
   {
-    To_String to_string(&ctx);
 
     std::string type;
     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()->perform(&to_string) : "";
+    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()->perform(&to_string) : "";
+    std::string t2 = &mq2->media_type() ? mq2->media_type()->to_string(ctx.c_options) : "";
 
 
     if (t1.empty()) t1 = t2;
@@ -548,18 +577,19 @@
       mod = m1.empty() ? m2 : m1;
     }
 
-    Media_Query* mm = SASS_MEMORY_NEW(ctx.mem, Media_Query,
+    Media_Query_Ptr mm = SASS_MEMORY_NEW(Media_Query,
 
 mq1->pstate(), 0,
 mq1->length() + mq2->length(), mod == "not", mod == "only"
 );
 
     if (!type.empty()) {
-      mm->media_type(SASS_MEMORY_NEW(ctx.mem, String_Quoted, mq1->pstate(), type));
+      mm->media_type(SASS_MEMORY_NEW(String_Quoted, mq1->pstate(), type));
     }
 
-    *mm += mq2;
-    *mm += mq1;
+    mm->concat(mq2);
+    mm->concat(mq1);
+
     return mm;
   }
 }
diff --git a/libsass/src/cssize.hpp b/libsass/src/cssize.hpp
--- a/libsass/src/cssize.hpp
+++ b/libsass/src/cssize.hpp
@@ -8,69 +8,69 @@
 
 namespace Sass {
 
-  typedef Environment<AST_Node*> Env;
+  typedef Environment<AST_Node_Obj> Env;
   struct Backtrace;
 
-  class Cssize : public Operation_CRTP<Statement*, Cssize> {
+  class Cssize : public Operation_CRTP<Statement_Ptr, Cssize> {
 
-    Context&                 ctx;
-    std::vector<Block*>      block_stack;
-    std::vector<Statement*>  p_stack;
-    Backtrace*               backtrace;
+    Context&                    ctx;
+    std::vector<Block_Ptr>         block_stack;
+    std::vector<Statement_Ptr>     p_stack;
+    Backtrace*                  backtrace;
 
-    Statement* fallback_impl(AST_Node* n);
+    Statement_Ptr fallback_impl(AST_Node_Ptr n);
 
   public:
     Cssize(Context&, Backtrace*);
-    virtual ~Cssize() { }
+    ~Cssize() { }
 
-    using Operation<Statement*>::operator();
+    Selector_List_Ptr selector();
 
-    Statement* operator()(Block*);
-    Statement* operator()(Ruleset*);
-    // Statement* operator()(Propset*);
-    // Statement* operator()(Bubble*);
-    Statement* operator()(Media_Block*);
-    Statement* operator()(Supports_Block*);
-    Statement* operator()(At_Root_Block*);
-    Statement* operator()(At_Rule*);
-    Statement* operator()(Keyframe_Rule*);
-    // Statement* operator()(Declaration*);
-    // Statement* operator()(Assignment*);
-    // Statement* operator()(Import*);
-    // Statement* operator()(Import_Stub*);
-    // Statement* operator()(Warning*);
-    // Statement* operator()(Error*);
-    // Statement* operator()(Comment*);
-    // Statement* operator()(If*);
-    // Statement* operator()(For*);
-    // Statement* operator()(Each*);
-    // Statement* operator()(While*);
-    // Statement* operator()(Return*);
-    // Statement* operator()(Extension*);
-    // Statement* operator()(Definition*);
-    // Statement* operator()(Mixin_Call*);
-    // Statement* operator()(Content*);
-    Statement* operator()(Null*);
+    Block_Ptr operator()(Block_Ptr);
+    Statement_Ptr operator()(Ruleset_Ptr);
+    // Statement_Ptr operator()(Bubble_Ptr);
+    Statement_Ptr operator()(Media_Block_Ptr);
+    Statement_Ptr operator()(Supports_Block_Ptr);
+    Statement_Ptr operator()(At_Root_Block_Ptr);
+    Statement_Ptr operator()(Directive_Ptr);
+    Statement_Ptr operator()(Keyframe_Rule_Ptr);
+    Statement_Ptr operator()(Trace_Ptr);
+    Statement_Ptr operator()(Declaration_Ptr);
+    // Statement_Ptr operator()(Assignment_Ptr);
+    // Statement_Ptr operator()(Import_Ptr);
+    // Statement_Ptr operator()(Import_Stub_Ptr);
+    // Statement_Ptr operator()(Warning_Ptr);
+    // Statement_Ptr operator()(Error_Ptr);
+    // Statement_Ptr operator()(Comment_Ptr);
+    // Statement_Ptr operator()(If_Ptr);
+    // Statement_Ptr operator()(For_Ptr);
+    // Statement_Ptr operator()(Each_Ptr);
+    // Statement_Ptr operator()(While_Ptr);
+    // Statement_Ptr operator()(Return_Ptr);
+    // Statement_Ptr operator()(Extension_Ptr);
+    // Statement_Ptr operator()(Definition_Ptr);
+    // Statement_Ptr operator()(Mixin_Call_Ptr);
+    // Statement_Ptr operator()(Content_Ptr);
+    Statement_Ptr operator()(Null_Ptr);
 
-    Statement* parent();
-    std::vector<std::pair<bool, Block*>> slice_by_bubble(Statement*);
-    Statement* bubble(At_Rule*);
-    Statement* bubble(At_Root_Block*);
-    Statement* bubble(Media_Block*);
-    Statement* bubble(Supports_Block*);
-    Statement* shallow_copy(Statement*);
-    Statement* debubble(Block* children, Statement* parent = 0);
-    Statement* flatten(Statement*);
-    bool bubblable(Statement*);
+    Statement_Ptr parent();
+    std::vector<std::pair<bool, Block_Obj>> slice_by_bubble(Block_Ptr);
+    Statement_Ptr bubble(Directive_Ptr);
+    Statement_Ptr bubble(At_Root_Block_Ptr);
+    Statement_Ptr bubble(Media_Block_Ptr);
+    Statement_Ptr bubble(Supports_Block_Ptr);
 
-    List* merge_media_queries(Media_Block*, Media_Block*);
-    Media_Query* merge_media_query(Media_Query*, Media_Query*);
+    Block_Ptr debubble(Block_Ptr children, Statement_Ptr parent = 0);
+    Block_Ptr flatten(Block_Ptr);
+    bool bubblable(Statement_Ptr);
 
+    List_Ptr merge_media_queries(Media_Block_Ptr, Media_Block_Ptr);
+    Media_Query_Ptr merge_media_query(Media_Query_Ptr, Media_Query_Ptr);
+
     template <typename U>
-    Statement* fallback(U x) { return fallback_impl(x); }
+    Statement_Ptr fallback(U x) { return fallback_impl(x); }
 
-    void append_block(Block*);
+    void append_block(Block_Ptr, Block_Ptr);
   };
 
 }
diff --git a/libsass/src/debugger.hpp b/libsass/src/debugger.hpp
--- a/libsass/src/debugger.hpp
+++ b/libsass/src/debugger.hpp
@@ -8,13 +8,13 @@
 
 using namespace Sass;
 
-inline void debug_ast(AST_Node* node, std::string ind = "", Env* env = 0);
+inline void debug_ast(AST_Node_Ptr node, std::string ind = "", Env* env = 0);
 
 inline void debug_sources_set(SourcesSet& 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";
@@ -44,7 +44,7 @@
   return is.str();
 }
 
-inline std::string pstate_source_position(AST_Node* node)
+inline std::string pstate_source_position(AST_Node_Ptr node)
 {
   std::stringstream str;
   Position start(node->pstate());
@@ -52,58 +52,82 @@
   str << (start.file == std::string::npos ? -1 : start.file)
     << "@[" << start.line << ":" << start.column << "]"
     << "-[" << end.line << ":" << end.column << "]";
+#ifdef DEBUG_SHARED_PTR
+      str << "x" << node->getRefCount() << ""
+      << " " << node->getDbgFile()
+      << "@" << node->getDbgLine();
+#endif
   return str.str();
 }
 
-inline void debug_ast(AST_Node* node, std::string ind, Env* env)
+inline void debug_ast(AST_Node_Ptr node, std::string ind, Env* env)
 {
   if (node == 0) return;
   if (ind == "") std::cerr << "####################################################################\n";
-  if (dynamic_cast<Bubble*>(node)) {
-    Bubble* bubble = dynamic_cast<Bubble*>(node);
+  if (dynamic_cast<Bubble_Ptr>(node)) {
+    Bubble_Ptr bubble = dynamic_cast<Bubble_Ptr>(node);
     std::cerr << ind << "Bubble " << bubble;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " " << bubble->tabs();
     std::cerr << std::endl;
-  } else if (dynamic_cast<At_Root_Block*>(node)) {
-    At_Root_Block* root_block = dynamic_cast<At_Root_Block*>(node);
+    debug_ast(&bubble->node(), ind + " ", env);
+  } else if (dynamic_cast<Trace_Ptr>(node)) {
+    Trace_Ptr trace = dynamic_cast<Trace_Ptr>(node);
+    std::cerr << ind << "Trace " << trace;
+    std::cerr << " (" << pstate_source_position(node) << ")"
+    << " [name:" << trace->name() << "]"
+    << 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);
     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*>(node)) {
-    Selector_List* selector = dynamic_cast<Selector_List*>(node);
+    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);
     std::cerr << ind << "Selector_List " << selector;
     std::cerr << " (" << pstate_source_position(node) << ")";
+    std::cerr << " <" << selector->hash() << ">";
     std::cerr << " [@media:" << selector->media_block() << "]";
+    std::cerr << (selector->is_invisible() ? " [INVISIBLE]": " -");
+    std::cerr << (selector->has_placeholder() ? " [PLACEHOLDER]": " -");
     std::cerr << (selector->is_optional() ? " [is_optional]": " -");
+    std::cerr << (selector->has_parent_ref() ? " [has-parent]": " -");
     std::cerr << (selector->has_line_break() ? " [line-break]": " -");
     std::cerr << (selector->has_line_feed() ? " [line-feed]": " -");
     std::cerr << std::endl;
 
-    for(auto 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*>(node)) {
-//    Expression* expression = dynamic_cast<Expression*>(node);
+//  } else if (dynamic_cast<Expression_Ptr>(node)) {
+//    Expression_Ptr expression = dynamic_cast<Expression_Ptr>(node);
 //    std::cerr << ind << "Expression " << expression << " " << expression->concrete_type() << std::endl;
 
-  } else if (dynamic_cast<Parent_Selector*>(node)) {
-    Parent_Selector* selector = dynamic_cast<Parent_Selector*>(node);
+  } else if (dynamic_cast<Parent_Selector_Ptr>(node)) {
+    Parent_Selector_Ptr selector = dynamic_cast<Parent_Selector_Ptr>(node);
     std::cerr << ind << "Parent_Selector " << selector;
 //    if (selector->not_selector()) cerr << " [in_declaration]";
     std::cerr << " (" << pstate_source_position(node) << ")";
+    std::cerr << " <" << selector->hash() << ">";
+    std::cerr << " [" << (selector->is_real_parent_ref() ? "REAL" : "FAKE") << "]";
     std::cerr << " <" << prettyprint(selector->pstate().token.ws_before()) << ">" << std::endl;
 //    debug_ast(selector->selector(), ind + "->", env);
 
-  } else if (dynamic_cast<Complex_Selector*>(node)) {
-    Complex_Selector* selector = dynamic_cast<Complex_Selector*>(node);
+  } else if (dynamic_cast<Complex_Selector_Ptr>(node)) {
+    Complex_Selector_Ptr selector = dynamic_cast<Complex_Selector_Ptr>(node);
     std::cerr << ind << "Complex_Selector " << selector
       << " (" << pstate_source_position(node) << ")"
+      << " <" << selector->hash() << ">"
+      << " [length:" << longToHex(selector->length()) << "]"
       << " [weight:" << longToHex(selector->specificity()) << "]"
       << " [@media:" << selector->media_block() << "]"
+      << (selector->is_invisible() ? " [INVISIBLE]": " -")
+      << (selector->has_placeholder() ? " [PLACEHOLDER]": " -")
       << (selector->is_optional() ? " [is_optional]": " -")
+      << (selector->has_parent_ref() ? " [has parent]": " -")
       << (selector->has_line_feed() ? " [line-feed]": " -")
       << (selector->has_line_break() ? " [line-break]": " -")
       << " -- ";
@@ -117,64 +141,104 @@
       }
       // 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();
     // debug_sources_set(set, ind + "  @--> ");
-  } else if (dynamic_cast<Compound_Selector*>(node)) {
-    Compound_Selector* selector = dynamic_cast<Compound_Selector*>(node);
+  } else if (dynamic_cast<Compound_Selector_Ptr>(node)) {
+    Compound_Selector_Ptr selector = dynamic_cast<Compound_Selector_Ptr>(node);
     std::cerr << ind << "Compound_Selector " << selector;
     std::cerr << " (" << pstate_source_position(node) << ")";
+    std::cerr << " <" << selector->hash() << ">";
     std::cerr << " [weight:" << longToHex(selector->specificity()) << "]";
     std::cerr << " [@media:" << selector->media_block() << "]";
+    std::cerr << (selector->extended() ? " [extended]": " -");
     std::cerr << (selector->is_optional() ? " [is_optional]": " -");
+    std::cerr << (selector->has_parent_ref() ? " [has-parent]": " -");
     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(auto i : selector->elements()) { debug_ast(i, ind + " ", env); }
-  } else if (dynamic_cast<Propset*>(node)) {
-    Propset* selector = dynamic_cast<Propset*>(node);
-    std::cerr << ind << "Propset " << selector;
-    std::cerr << " (" << pstate_source_position(node) << ")";
-    std::cerr << " " << selector->tabs() << std::endl;
-    if (selector->block()) for(auto i : selector->block()->elements()) { debug_ast(i, ind + " ", env); }
-  } else if (dynamic_cast<Wrapped_Selector*>(node)) {
-    Wrapped_Selector* selector = dynamic_cast<Wrapped_Selector*>(node);
+    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);
     std::cerr << ind << "Wrapped_Selector " << selector;
     std::cerr << " (" << pstate_source_position(node) << ")";
-    std::cerr << " <<" << selector->ns_name() << ">>" << (selector->has_line_break() ? " [line-break]": " -") << (selector->has_line_feed() ? " [line-feed]": " -") << std::endl;
-    debug_ast(selector->selector(), ind + " () ", env);
-  } else if (dynamic_cast<Pseudo_Selector*>(node)) {
-    Pseudo_Selector* selector = dynamic_cast<Pseudo_Selector*>(node);
+    std::cerr << " <" << selector->hash() << ">";
+    std::cerr << " <<" << selector->ns_name() << ">>";
+    std::cerr << (selector->is_optional() ? " [is_optional]": " -");
+    std::cerr << (selector->has_parent_ref() ? " [has-parent]": " -");
+    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);
     std::cerr << ind << "Pseudo_Selector " << selector;
     std::cerr << " (" << pstate_source_position(node) << ")";
-    std::cerr << " <<" << selector->ns_name() << ">>" << (selector->has_line_break() ? " [line-break]": " -") << (selector->has_line_feed() ? " [line-feed]": " -") << std::endl;
-    debug_ast(selector->expression(), ind + " <= ", env);
-  } else if (dynamic_cast<Attribute_Selector*>(node)) {
-    Attribute_Selector* selector = dynamic_cast<Attribute_Selector*>(node);
+    std::cerr << " <" << selector->hash() << ">";
+    std::cerr << " <<" << selector->ns_name() << ">>";
+    std::cerr << (selector->is_optional() ? " [is_optional]": " -");
+    std::cerr << (selector->has_parent_ref() ? " [has-parent]": " -");
+    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);
     std::cerr << ind << "Attribute_Selector " << selector;
     std::cerr << " (" << pstate_source_position(node) << ")";
-    std::cerr << " <<" << selector->ns_name() << ">>" << (selector->has_line_break() ? " [line-break]": " -") << (selector->has_line_feed() ? " [line-feed]": " -") << std::endl;
-    debug_ast(selector->value(), ind + "[" + selector->matcher() + "] ", env);
-  } else if (dynamic_cast<Selector_Qualifier*>(node)) {
-    Selector_Qualifier* selector = dynamic_cast<Selector_Qualifier*>(node);
-    std::cerr << ind << "Selector_Qualifier " << selector;
+    std::cerr << " <" << selector->hash() << ">";
+    std::cerr << " <<" << selector->ns_name() << ">>";
+    std::cerr << (selector->is_optional() ? " [is_optional]": " -");
+    std::cerr << (selector->has_parent_ref() ? " [has-parent]": " -");
+    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);
+    std::cerr << ind << "Class_Selector " << selector;
     std::cerr << " (" << pstate_source_position(node) << ")";
-    std::cerr << " <<" << selector->ns_name() << ">>" << (selector->has_line_break() ? " [line-break]": " -") << (selector->has_line_feed() ? " [line-feed]": " -") << std::endl;
-  } else if (dynamic_cast<Type_Selector*>(node)) {
-    Type_Selector* selector = dynamic_cast<Type_Selector*>(node);
-    std::cerr << ind << "Type_Selector " << selector;
+    std::cerr << " <" << selector->hash() << ">";
+    std::cerr << " <<" << selector->ns_name() << ">>";
+    std::cerr << (selector->is_optional() ? " [is_optional]": " -");
+    std::cerr << (selector->has_parent_ref() ? " [has-parent]": " -");
+    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);
+    std::cerr << ind << "Id_Selector " << selector;
     std::cerr << " (" << pstate_source_position(node) << ")";
-    std::cerr << " <<" << selector->ns_name() << ">>" << (selector->has_line_break() ? " [line-break]": " -") <<
-      " <" << prettyprint(selector->pstate().token.ws_before()) << ">" << std::endl;
-  } else if (dynamic_cast<Selector_Placeholder*>(node)) {
+    std::cerr << " <" << selector->hash() << ">";
+    std::cerr << " <<" << selector->ns_name() << ">>";
+    std::cerr << (selector->is_optional() ? " [is_optional]": " -");
+    std::cerr << (selector->has_parent_ref() ? " [has-parent]": " -");
+    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);
+    std::cerr << ind << "Element_Selector " << selector;
+    std::cerr << " (" << pstate_source_position(node) << ")";
+    std::cerr << " <" << selector->hash() << ">";
+    std::cerr << " <<" << selector->ns_name() << ">>";
+    std::cerr << (selector->is_optional() ? " [is_optional]": " -");
+    std::cerr << (selector->has_parent_ref() ? " [has-parent]": " -");
+    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::cerr << std::endl;
+  } else if (dynamic_cast<Placeholder_Selector_Ptr>(node)) {
 
-    Selector_Placeholder* selector = dynamic_cast<Selector_Placeholder*>(node);
-    std::cerr << ind << "Selector_Placeholder [" << selector->ns_name() << "] " << selector
+    Placeholder_Selector_Ptr selector = dynamic_cast<Placeholder_Selector_Ptr>(node);
+    std::cerr << ind << "Placeholder_Selector [" << selector->ns_name() << "] " << selector;
+    std::cerr << " (" << pstate_source_position(selector) << ")"
+      << " <" << selector->hash() << ">"
       << " [@media:" << selector->media_block() << "]"
       << (selector->is_optional() ? " [is_optional]": " -")
       << (selector->has_line_break() ? " [line-break]": " -")
@@ -187,8 +251,8 @@
     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*>(node)) {
-    Selector_Schema* selector = dynamic_cast<Selector_Schema*>(node);
+  } else if (dynamic_cast<Selector_Schema_Ptr>(node)) {
+    Selector_Schema_Ptr selector = dynamic_cast<Selector_Schema_Ptr>(node);
     std::cerr << ind << "Selector_Schema " << selector;
     std::cerr << " (" << pstate_source_position(node) << ")"
       << (selector->at_root() && selector->at_root() ? " [@ROOT]" : "")
@@ -197,183 +261,196 @@
       << (selector->has_line_feed() ? " [line-feed]": " -")
     << 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*>(node)) {
-    Selector* selector = dynamic_cast<Selector*>(node);
+  } else if (dynamic_cast<Selector_Ptr>(node)) {
+    Selector_Ptr selector = dynamic_cast<Selector_Ptr>(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*>(node)) {
-    Media_Query_Expression* block = dynamic_cast<Media_Query_Expression*>(node);
+  } else if (dynamic_cast<Media_Query_Expression_Ptr>(node)) {
+    Media_Query_Expression_Ptr block = dynamic_cast<Media_Query_Expression_Ptr>(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*>(node)) {
-    Media_Query* block = dynamic_cast<Media_Query*>(node);
+  } else if (dynamic_cast<Media_Query_Ptr>(node)) {
+    Media_Query_Ptr block = dynamic_cast<Media_Query_Ptr>(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(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*>(node)) {
-    Media_Block* block = dynamic_cast<Media_Block*>(node);
+  } else if (dynamic_cast<Media_Block_Ptr>(node)) {
+    Media_Block_Ptr block = dynamic_cast<Media_Block_Ptr>(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(auto i : block->block()->elements()) { debug_ast(i, ind + " ", env); }
-  } else if (dynamic_cast<Supports_Block*>(node)) {
-    Supports_Block* block = dynamic_cast<Supports_Block*>(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 (dynamic_cast<Supports_Block_Ptr>(node)) {
+    Supports_Block_Ptr block = dynamic_cast<Supports_Block_Ptr>(node);
     std::cerr << ind << "Supports_Block " << block;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " " << block->tabs() << std::endl;
-    debug_ast(block->condition(), ind + " =@ ");
-  } else if (dynamic_cast<Supports_Operator*>(node)) {
-    Supports_Operator* block = dynamic_cast<Supports_Operator*>(node);
+    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);
     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*>(node)) {
-    Supports_Negation* block = dynamic_cast<Supports_Negation*>(node);
+    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);
     std::cerr << ind << "Supports_Negation " << block;
     std::cerr << " (" << pstate_source_position(node) << ")"
     << std::endl;
-    debug_ast(block->condition(), ind + " condition) ");
-  } else if (dynamic_cast<Supports_Declaration*>(node)) {
-    Supports_Declaration* block = dynamic_cast<Supports_Declaration*>(node);
+    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);
+    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);
     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*>(node)) {
-    Block* root_block = dynamic_cast<Block*>(node);
+    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);
     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;
-    if (root_block->block()) for(auto i : root_block->block()->elements()) { debug_ast(i, ind + " ", env); }
-  } else if (dynamic_cast<Warning*>(node)) {
-    Warning* block = dynamic_cast<Warning*>(node);
+    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);
     std::cerr << ind << "Warning " << block;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " " << block->tabs() << std::endl;
-  } else if (dynamic_cast<Error*>(node)) {
-    Error* block = dynamic_cast<Error*>(node);
+    debug_ast(&block->message(), ind + " : ");
+  } else if (dynamic_cast<Error_Ptr>(node)) {
+    Error_Ptr block = dynamic_cast<Error_Ptr>(node);
     std::cerr << ind << "Error " << block;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " " << block->tabs() << std::endl;
-  } else if (dynamic_cast<Debug*>(node)) {
-    Debug* block = dynamic_cast<Debug*>(node);
+  } else if (dynamic_cast<Debug_Ptr>(node)) {
+    Debug_Ptr block = dynamic_cast<Debug_Ptr>(node);
     std::cerr << ind << "Debug " << block;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " " << block->tabs() << std::endl;
-  } else if (dynamic_cast<Comment*>(node)) {
-    Comment* block = dynamic_cast<Comment*>(node);
+    debug_ast(&block->value(), ind + " ");
+  } else if (dynamic_cast<Comment_Ptr>(node)) {
+    Comment_Ptr block = dynamic_cast<Comment_Ptr>(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*>(node)) {
-    If* block = dynamic_cast<If*>(node);
+    debug_ast(&block->text(), ind + "// ", env);
+  } else if (dynamic_cast<If_Ptr>(node)) {
+    If_Ptr block = dynamic_cast<If_Ptr>(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*>(node)) {
-    Return* block = dynamic_cast<Return*>(node);
+    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);
     std::cerr << ind << "Return " << block;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " " << block->tabs() << std::endl;
-  } else if (dynamic_cast<Extension*>(node)) {
-    Extension* block = dynamic_cast<Extension*>(node);
+  } else if (dynamic_cast<Extension_Ptr>(node)) {
+    Extension_Ptr block = dynamic_cast<Extension_Ptr>(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*>(node)) {
-    Content* block = dynamic_cast<Content*>(node);
+    debug_ast(&block->selector(), ind + "-> ", env);
+  } else if (dynamic_cast<Content_Ptr>(node)) {
+    Content_Ptr block = dynamic_cast<Content_Ptr>(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*>(node)) {
-    Import_Stub* block = dynamic_cast<Import_Stub*>(node);
+  } else if (dynamic_cast<Import_Stub_Ptr>(node)) {
+    Import_Stub_Ptr block = dynamic_cast<Import_Stub_Ptr>(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*>(node)) {
-    Import* block = dynamic_cast<Import*>(node);
+  } else if (dynamic_cast<Import_Ptr>(node)) {
+    Import_Ptr block = dynamic_cast<Import_Ptr>(node);
     std::cerr << ind << "Import " << block;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " " << block->tabs() << std::endl;
-    debug_ast(block->media_queries(), ind + " @ ");
     // std::vector<std::string>         files_;
-    for (auto imp : block->urls()) debug_ast(imp, "@ ", env);
-  } else if (dynamic_cast<Assignment*>(node)) {
-    Assignment* block = dynamic_cast<Assignment*>(node);
+    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);
     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*>(node)) {
-    Declaration* block = dynamic_cast<Declaration*>(node);
+    debug_ast(&block->value(), ind + "=", env);
+  } else if (dynamic_cast<Declaration_Ptr>(node)) {
+    Declaration_Ptr block = dynamic_cast<Declaration_Ptr>(node);
     std::cerr << ind << "Declaration " << block;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " " << block->tabs() << std::endl;
-    debug_ast(block->property(), ind + " prop: ", env);
-    debug_ast(block->value(), ind + " value: ", env);
-  } else if (dynamic_cast<Keyframe_Rule*>(node)) {
-    Keyframe_Rule* has_block = dynamic_cast<Keyframe_Rule*>(node);
+    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);
     std::cerr << ind << "Keyframe_Rule " << has_block;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " " << has_block->tabs() << std::endl;
-    if (has_block->selector()) debug_ast(has_block->selector(), ind + "@");
-    if (has_block->block()) for(auto i : has_block->block()->elements()) { debug_ast(i, ind + " ", env); }
-  } else if (dynamic_cast<At_Rule*>(node)) {
-    At_Rule* block = dynamic_cast<At_Rule*>(node);
-    std::cerr << ind << "At_Rule " << block;
+    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);
+    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(auto i : block->block()->elements()) { debug_ast(i, ind + " ", env); }
-  } else if (dynamic_cast<Each*>(node)) {
-    Each* block = dynamic_cast<Each*>(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 (dynamic_cast<Each_Ptr>(node)) {
+    Each_Ptr block = dynamic_cast<Each_Ptr>(node);
     std::cerr << ind << "Each " << block;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " " << block->tabs() << std::endl;
-    if (block->block()) for(auto i : block->block()->elements()) { debug_ast(i, ind + " ", env); }
-  } else if (dynamic_cast<For*>(node)) {
-    For* block = dynamic_cast<For*>(node);
+    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);
     std::cerr << ind << "For " << block;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " " << block->tabs() << std::endl;
-    if (block->block()) for(auto i : block->block()->elements()) { debug_ast(i, ind + " ", env); }
-  } else if (dynamic_cast<While*>(node)) {
-    While* block = dynamic_cast<While*>(node);
+    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);
     std::cerr << ind << "While " << block;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " " << block->tabs() << std::endl;
-    if (block->block()) for(auto i : block->block()->elements()) { debug_ast(i, ind + " ", env); }
-  } else if (dynamic_cast<Definition*>(node)) {
-    Definition* block = dynamic_cast<Definition*>(node);
+    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);
     std::cerr << ind << "Definition " << block;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " [name: " << block->name() << "] ";
@@ -382,62 +459,73 @@
     // 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()) for(auto i : block->block()->elements()) { debug_ast(i, ind + " ", env); }
-  } else if (dynamic_cast<Mixin_Call*>(node)) {
-    Mixin_Call* block = dynamic_cast<Mixin_Call*>(node);
+    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);
     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()) for(auto i : block->block()->elements()) { debug_ast(i, ind + " ", env); }
-  } else if (Ruleset* ruleset = dynamic_cast<Ruleset*>(node)) {
+    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)) {
     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*>(node)) {
-    Block* block = dynamic_cast<Block*>(node);
+    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);
     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(auto i : block->elements()) { debug_ast(i, ind + " ", env); }
-  } else if (dynamic_cast<Textual*>(node)) {
-    Textual* expression = dynamic_cast<Textual*>(node);
-    std::cerr << ind << "Textual ";
+    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 << " [" << expression->value() << "]";
+    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*>(node)) {
-    Variable* expression = dynamic_cast<Variable*>(node);
+  } else if (dynamic_cast<Variable_Ptr>(node)) {
+    Variable_Ptr expression = dynamic_cast<Variable_Ptr>(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(static_cast<Expression*>((*env)[name]), ind + " -> ", env);
-  } else if (dynamic_cast<Function_Call_Schema*>(node)) {
-    Function_Call_Schema* expression = dynamic_cast<Function_Call_Schema*>(node);
+    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);
     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*>(node)) {
-    Function_Call* expression = dynamic_cast<Function_Call*>(node);
+    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);
     std::cerr << ind << "Function_Call " << expression;
+    std::cerr << " [interpolant: " << expression->is_interpolant() << "] ";
     std::cerr << " (" << pstate_source_position(node) << ")";
-    std::cerr << " [" << expression->name() << "]" << std::endl;
-    debug_ast(expression->arguments(), ind + " args: ", env);
-  } else if (dynamic_cast<Arguments*>(node)) {
-    Arguments* expression = dynamic_cast<Arguments*>(node);
+    std::cerr << " [" << expression->name() << "]";
+    if (expression->is_delayed()) std::cerr << " [delayed]";
+    if (expression->is_interpolant()) std::cerr << " [interpolant]";
+    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);
     std::cerr << ind << "Arguments " << expression;
     if (expression->is_delayed()) std::cerr << " [delayed]";
     std::cerr << " (" << pstate_source_position(node) << ")";
@@ -445,100 +533,120 @@
     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(auto i : expression->elements()) { debug_ast(i, ind + " ", env); }
-  } else if (dynamic_cast<Argument*>(node)) {
-    Argument* expression = dynamic_cast<Argument*>(node);
+    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);
     std::cerr << ind << "Argument " << expression;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " [" << expression->value() << "]";
     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*>(node)) {
-    Parameters* expression = dynamic_cast<Parameters*>(node);
+    debug_ast(&expression->value(), ind + " value: ", env);
+  } else if (dynamic_cast<Parameters_Ptr>(node)) {
+    Parameters_Ptr expression = dynamic_cast<Parameters_Ptr>(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(auto i : expression->elements()) { debug_ast(i, ind + " ", env); }
-  } else if (dynamic_cast<Parameter*>(node)) {
-    Parameter* expression = dynamic_cast<Parameter*>(node);
+    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);
     std::cerr << ind << "Parameter " << expression;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " [name: " << expression->name() << "] ";
     std::cerr << " [default: " << expression->default_value() << "] ";
     std::cerr << " [rest: " << expression->is_rest_parameter() << "] " << std::endl;
-  } else if (dynamic_cast<Unary_Expression*>(node)) {
-    Unary_Expression* expression = dynamic_cast<Unary_Expression*>(node);
+  } else if (dynamic_cast<Unary_Expression_Ptr>(node)) {
+    Unary_Expression_Ptr expression = dynamic_cast<Unary_Expression_Ptr>(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*>(node)) {
-    Binary_Expression* expression = dynamic_cast<Binary_Expression*>(node);
+    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);
     std::cerr << ind << "Binary_Expression " << expression;
+    if (expression->is_interpolant()) std::cerr << " [is interpolant] ";
+    if (expression->is_left_interpolant()) std::cerr << " [left interpolant] ";
+    if (expression->is_right_interpolant()) std::cerr << " [right interpolant] ";
     std::cerr << " [delayed: " << expression->is_delayed() << "] ";
+    std::cerr << " [ws_before: " << expression->op().ws_before << "] ";
+    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*>(node)) {
-    Map* expression = dynamic_cast<Map*>(node);
+    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);
     std::cerr << ind << "Map " << expression;
+    std::cerr << " [interpolant: " << expression->is_interpolant() << "] ";
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " [Hashed]" << std::endl;
-    for (auto i : expression->elements()) {
-      debug_ast(i.first, ind + " key: ");
-      debug_ast(i.second, ind + " val: ");
+    for (const auto& i : expression->elements()) {
+      debug_ast(&i.first, ind + " key: ");
+      debug_ast(&i.second, ind + " val: ");
     }
-  } else if (dynamic_cast<List*>(node)) {
-    List* expression = dynamic_cast<List*>(node);
+  } else if (dynamic_cast<List_Ptr>(node)) {
+    List_Ptr expression = dynamic_cast<List_Ptr>(node);
     std::cerr << ind << "List " << expression;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " (" << expression->length() << ") " <<
-      (expression->separator() == SASS_COMMA ? "Comma " : "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() << "] " <<
       " [hash: " << expression->hash() << "] " <<
       std::endl;
-    for(auto i : expression->elements()) { debug_ast(i, ind + " ", env); }
-  } else if (dynamic_cast<Content*>(node)) {
-    Content* expression = dynamic_cast<Content*>(node);
+    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);
     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*>(node)) {
-    Boolean* expression = dynamic_cast<Boolean*>(node);
+  } else if (dynamic_cast<Boolean_Ptr>(node)) {
+    Boolean_Ptr expression = dynamic_cast<Boolean_Ptr>(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*>(node)) {
-    Color* expression = dynamic_cast<Color*>(node);
+  } else if (dynamic_cast<Color_Ptr>(node)) {
+    Color_Ptr expression = dynamic_cast<Color_Ptr>(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*>(node)) {
-    Number* expression = dynamic_cast<Number*>(node);
+  } else if (dynamic_cast<Number_Ptr>(node)) {
+    Number_Ptr expression = dynamic_cast<Number_Ptr>(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<String_Quoted*>(node)) {
-    String_Quoted* expression = dynamic_cast<String_Quoted*>(node);
+  } else if (dynamic_cast<Null_Ptr>(node)) {
+    Null_Ptr expression = dynamic_cast<Null_Ptr>(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);
     std::cerr << ind << "String_Quoted " << expression;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " [" << prettyprint(expression->value()) << "]";
     if (expression->is_delayed()) std::cerr << " [delayed]";
-    if (expression->sass_fix_1291()) std::cerr << " [sass_fix_1291]";
     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*>(node)) {
-    String_Constant* expression = dynamic_cast<String_Constant*>(node);
+  } else if (dynamic_cast<String_Constant_Ptr>(node)) {
+    String_Constant_Ptr expression = dynamic_cast<String_Constant_Ptr>(node);
     std::cerr << ind << "String_Constant " << expression;
     if (expression->concrete_type()) {
       std::cerr << " " << expression->concrete_type();
@@ -546,28 +654,30 @@
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " [" << prettyprint(expression->value()) << "]";
     if (expression->is_delayed()) std::cerr << " [delayed]";
-    if (expression->sass_fix_1291()) std::cerr << " [sass_fix_1291]";
     if (expression->is_interpolant()) std::cerr << " [interpolant]";
     std::cerr << " <" << prettyprint(expression->pstate().token.ws_before()) << ">" << std::endl;
-  } else if (dynamic_cast<String_Schema*>(node)) {
-    String_Schema* expression = dynamic_cast<String_Schema*>(node);
+  } else if (dynamic_cast<String_Schema_Ptr>(node)) {
+    String_Schema_Ptr expression = dynamic_cast<String_Schema_Ptr>(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->is_delayed()) std::cerr << " [delayed]";
-    if (expression->has_interpolants()) std::cerr << " [has_interpolants]";
-    if (expression->is_interpolant()) std::cerr << " [interpolant]";
+    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(auto i : expression->elements()) { debug_ast(i, ind + " ", env); }
-  } else if (dynamic_cast<String*>(node)) {
-    String* expression = dynamic_cast<String*>(node);
+    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);
     std::cerr << ind << "String " << expression;
     std::cerr << " " << expression->concrete_type();
     std::cerr << " (" << pstate_source_position(node) << ")";
-    if (expression->sass_fix_1291()) std::cerr << " [sass_fix_1291]";
     if (expression->is_interpolant()) std::cerr << " [interpolant]";
     std::cerr << " <" << prettyprint(expression->pstate().token.ws_before()) << ">" << std::endl;
-  } else if (dynamic_cast<Expression*>(node)) {
-    Expression* expression = dynamic_cast<Expression*>(node);
+  } else if (dynamic_cast<Expression_Ptr>(node)) {
+    Expression_Ptr expression = dynamic_cast<Expression_Ptr>(node);
     std::cerr << ind << "Expression " << expression;
     std::cerr << " (" << pstate_source_position(node) << ")";
     switch (expression->concrete_type()) {
@@ -582,17 +692,18 @@
       case Expression::Concrete_Type::NULL_VAL: std::cerr << " [NULL_VAL]"; break;
       case Expression::Concrete_Type::C_WARNING: std::cerr << " [C_WARNING]"; break;
       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;
     }
     std::cerr << std::endl;
-  } else if (dynamic_cast<Has_Block*>(node)) {
-    Has_Block* has_block = dynamic_cast<Has_Block*>(node);
+  } else if (dynamic_cast<Has_Block_Ptr>(node)) {
+    Has_Block_Ptr has_block = dynamic_cast<Has_Block_Ptr>(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(auto i : has_block->block()->elements()) { debug_ast(i, ind + " ", env); }
-  } else if (dynamic_cast<Statement*>(node)) {
-    Statement* statement = dynamic_cast<Statement*>(node);
+    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);
     std::cerr << ind << "Statement " << statement;
     std::cerr << " (" << pstate_source_position(node) << ")";
     std::cerr << " " << statement->tabs() << std::endl;
@@ -624,7 +735,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 ";
@@ -650,35 +761,36 @@
   if (ind == "") std::cerr << "#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n";
 }
 
-inline void debug_ast(const AST_Node* node, std::string ind = "", Env* env = 0)
+/*
+inline void debug_ast(const AST_Node_Ptr node, std::string ind = "", Env* env = 0)
 {
-  debug_ast(const_cast<AST_Node*>(node), ind, env);
+  debug_ast(const_cast<AST_Node_Ptr>(node), ind, env);
 }
-
+*/
 inline void debug_node(const Node* node, std::string ind = "")
 {
   debug_node(const_cast<Node*>(node), ind);
 }
 
-inline void debug_extenstion_map(Sass::ExtensionSubsetMap* map, std::string ind = "")
+inline void debug_subset_map(Sass::Subset_Map& map, std::string ind = "")
 {
   if (ind == "") std::cerr << "#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
-  for(auto const &it : map->values()) {
-    debug_ast(it.first, ind + "first: ");
-    debug_ast(it.second, ind + "second: ");
+  for(auto const &it : map.values()) {
+    debug_ast(&it.first, ind + "first: ");
+    debug_ast(&it.second, ind + "second: ");
   }
   if (ind == "") std::cerr << "#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
 }
 
-typedef std::pair<Complex_Selector*, Compound_Selector*> ExtensionPair;
+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 = "")
 {
   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
@@ -1,3 +1,4 @@
+#include "sass.hpp"
 #include "util.hpp"
 #include "context.hpp"
 #include "output.hpp"
@@ -6,20 +7,20 @@
 
 namespace Sass {
 
-  Emitter::Emitter(Context* ctx)
+  Emitter::Emitter(struct Sass_Output_Options& opt)
   : wbuf(),
-    ctx(ctx),
+    opt(opt),
     indentation(0),
     scheduled_space(0),
     scheduled_linefeed(0),
     scheduled_delimiter(false),
+    scheduled_mapping(0),
     in_comment(false),
     in_wrapped(false),
     in_media_block(false),
     in_declaration(false),
     in_space_array(false),
-    in_comma_array(false),
-    in_debug(false)
+    in_comma_array(false)
   { }
 
   // return buffer as string
@@ -28,9 +29,9 @@
     return wbuf.buffer;
   }
 
-  Sass_Output_Style Emitter::output_style(void)
+  Sass_Output_Style Emitter::output_style(void) const
   {
-    return ctx ? ctx->output_style() : SASS_STYLE_COMPRESSED;
+    return opt.output_style;
   }
 
   // PROXY METHODS FOR SOURCE MAPS
@@ -44,9 +45,11 @@
   void Emitter::set_filename(const std::string& str)
   { wbuf.smap.file = str; }
 
-  void Emitter::add_open_mapping(AST_Node* node)
+  void Emitter::schedule_mapping(const AST_Node_Ptr node)
+  { scheduled_mapping = node; }
+  void Emitter::add_open_mapping(const AST_Node_Ptr node)
   { wbuf.smap.add_open_mapping(node); }
-  void Emitter::add_close_mapping(AST_Node* node)
+  void Emitter::add_close_mapping(const AST_Node_Ptr node)
   { wbuf.smap.add_close_mapping(node); }
   ParserState Emitter::remap(const ParserState& pstate)
   { return wbuf.smap.remap(pstate); }
@@ -54,9 +57,11 @@
   // MAIN BUFFER MANIPULATION
 
   // add outstanding delimiter
-  void Emitter::finalize(void)
+  void Emitter::finalize(bool final)
   {
     scheduled_space = 0;
+    if (output_style() == SASS_STYLE_COMPRESSED)
+      if (final) scheduled_delimiter = false;
     if (scheduled_linefeed)
       scheduled_linefeed = 1;
     flush_schedules();
@@ -70,7 +75,7 @@
       std::string linefeeds = "";
 
       for (size_t i = 0; i < scheduled_linefeed; i++)
-        linefeeds += ctx ? ctx->linefeed : "\n";
+        linefeeds += opt.linefeed;
       scheduled_space = 0;
       scheduled_linefeed = 0;
       append_string(linefeeds);
@@ -103,10 +108,11 @@
   // append some text or token to the buffer
   void Emitter::append_string(const std::string& text)
   {
+
     // write space/lf
     flush_schedules();
 
-    if (in_comment && output_style() == SASS_STYLE_COMPACT) {
+    if (in_comment && output_style() == COMPACT) {
       // unescape comment nodes
       std::string out = comment_to_string(text);
       // add to buffer
@@ -133,10 +139,16 @@
 
   // append some text or token to the buffer
   // this adds source-mappings for node start and end
-  void Emitter::append_token(const std::string& text, AST_Node* node)
+  void Emitter::append_token(const std::string& text, const AST_Node_Ptr node)
   {
     flush_schedules();
     add_open_mapping(node);
+    // hotfix for browser issues
+    // this is pretty ugly indeed
+    if (scheduled_mapping) {
+      add_open_mapping(scheduled_mapping);
+      scheduled_mapping = 0;
+    }
     append_string(text);
     add_close_mapping(node);
   }
@@ -145,27 +157,27 @@
 
   void Emitter::append_indentation()
   {
-    if (output_style() == SASS_STYLE_COMPRESSED) return;
-    if (output_style() == SASS_STYLE_COMPACT) return;
+    if (output_style() == COMPRESSED) return;
+    if (output_style() == COMPACT) return;
     if (in_declaration && in_comma_array) return;
     if (scheduled_linefeed && indentation)
       scheduled_linefeed = 1;
     std::string indent = "";
     for (size_t i = 0; i < indentation; i++)
-      indent += ctx ? ctx->indent : "  ";
+      indent += opt.indent;
     append_string(indent);
   }
 
   void Emitter::append_delimiter()
   {
     scheduled_delimiter = true;
-    if (output_style() == SASS_STYLE_COMPACT) {
+    if (output_style() == COMPACT) {
       if (indentation == 0) {
         append_mandatory_linefeed();
       } else {
         append_mandatory_space();
       }
-    } else if (output_style() != SASS_STYLE_COMPRESSED) {
+    } else if (output_style() != COMPRESSED) {
       append_optional_linefeed();
     }
   }
@@ -191,8 +203,8 @@
 
   void Emitter::append_optional_space()
   {
-    if ((output_style() != SASS_STYLE_COMPRESSED || in_debug) && buffer().size()) {
-      char lst = buffer().at(buffer().length() - 1);
+    if ((output_style() != COMPRESSED) && buffer().size()) {
+      unsigned char lst = buffer().at(buffer().length() - 1);
       if (!isspace(lst) || scheduled_delimiter) {
         append_mandatory_space();
       }
@@ -201,17 +213,17 @@
 
   void Emitter::append_special_linefeed()
   {
-    if (output_style() == SASS_STYLE_COMPACT) {
+    if (output_style() == COMPACT) {
       append_mandatory_linefeed();
       for (size_t p = 0; p < indentation; p++)
-        append_string(ctx ? ctx->indent : "  ");
+        append_string(opt.indent);
     }
   }
 
   void Emitter::append_optional_linefeed()
   {
     if (in_declaration && in_comma_array) return;
-    if (output_style() == SASS_STYLE_COMPACT) {
+    if (output_style() == COMPACT) {
       append_mandatory_space();
     } else {
       append_mandatory_linefeed();
@@ -220,14 +232,14 @@
 
   void Emitter::append_mandatory_linefeed()
   {
-    if (output_style() != SASS_STYLE_COMPRESSED) {
+    if (output_style() != COMPRESSED) {
       scheduled_linefeed = 1;
       scheduled_space = 0;
       // flush_schedules();
     }
   }
 
-  void Emitter::append_scope_opener(AST_Node* node)
+  void Emitter::append_scope_opener(AST_Node_Ptr node)
   {
     scheduled_linefeed = 0;
     append_optional_space();
@@ -238,13 +250,13 @@
     // append_optional_space();
     ++ indentation;
   }
-  void Emitter::append_scope_closer(AST_Node* node)
+  void Emitter::append_scope_closer(AST_Node_Ptr node)
   {
     -- indentation;
     scheduled_linefeed = 0;
-    if (output_style() == SASS_STYLE_COMPRESSED)
+    if (output_style() == COMPRESSED)
       scheduled_delimiter = false;
-    if (output_style() == SASS_STYLE_EXPANDED) {
+    if (output_style() == EXPANDED) {
       append_optional_linefeed();
       append_indentation();
     } else {
@@ -254,7 +266,7 @@
     if (node) add_close_mapping(node);
     append_optional_linefeed();
     if (indentation != 0) return;
-    if (output_style() != SASS_STYLE_COMPRESSED)
+    if (output_style() != COMPRESSED)
       scheduled_linefeed = 2;
   }
 
diff --git a/libsass/src/emitter.hpp b/libsass/src/emitter.hpp
--- a/libsass/src/emitter.hpp
+++ b/libsass/src/emitter.hpp
@@ -2,6 +2,7 @@
 #define SASS_EMITTER_H
 
 #include <string>
+#include "sass.hpp"
 #include "sass/base.h"
 #include "source_map.hpp"
 #include "ast_fwd_decl.hpp"
@@ -12,7 +13,7 @@
   class Emitter {
 
     public:
-      Emitter(Context* ctx);
+      Emitter(struct Sass_Output_Options& opt);
       virtual ~Emitter() { }
 
     protected:
@@ -24,17 +25,19 @@
       // proxy methods for source maps
       void add_source_index(size_t idx);
       void set_filename(const std::string& str);
-      void add_open_mapping(AST_Node* node);
-      void add_close_mapping(AST_Node* node);
+      void add_open_mapping(const AST_Node_Ptr node);
+      void add_close_mapping(const AST_Node_Ptr node);
+      void schedule_mapping(const AST_Node_Ptr node);
       std::string render_srcmap(Context &ctx);
       ParserState remap(const ParserState& pstate);
 
     public:
-      Context* ctx;
+      struct Sass_Output_Options& opt;
       size_t indentation;
       size_t scheduled_space;
       size_t scheduled_linefeed;
       bool scheduled_delimiter;
+      AST_Node_Ptr scheduled_mapping;
 
     public:
       // output strings different in comments
@@ -48,16 +51,14 @@
       // nested lists need parentheses
       bool in_space_array;
       bool in_comma_array;
-      // list separators don't get compressed in @debug
-      bool in_debug;
 
     public:
       // return buffer as std::string
       std::string get_buffer(void);
       // flush scheduled space/linefeed
-      Sass_Output_Style output_style(void);
+      Sass_Output_Style output_style(void) const;
       // add outstanding linefeed
-      void finalize(void);
+      void finalize(bool final = true);
       // flush scheduled space/linefeed
       void flush_schedules(void);
       // prepend some text or token to the buffer
@@ -69,7 +70,7 @@
       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, AST_Node* node);
+      void append_token(const std::string& text, const AST_Node_Ptr node);
 
     public: // syntax sugar
       void append_indentation();
@@ -78,8 +79,8 @@
       void append_special_linefeed(void);
       void append_optional_linefeed(void);
       void append_mandatory_linefeed(void);
-      void append_scope_opener(AST_Node* node = 0);
-      void append_scope_closer(AST_Node* node = 0);
+      void append_scope_opener(AST_Node_Ptr node = 0);
+      void append_scope_closer(AST_Node_Ptr node = 0);
       void append_comma_separator(void);
       void append_colon_separator(void);
       void append_delimiter(void);
diff --git a/libsass/src/environment.cpp b/libsass/src/environment.cpp
--- a/libsass/src/environment.cpp
+++ b/libsass/src/environment.cpp
@@ -1,14 +1,24 @@
+#include "sass.hpp"
 #include "ast.hpp"
 #include "environment.hpp"
 
 namespace Sass {
 
   template <typename T>
-  Environment<T>::Environment() : local_frame_(std::map<std::string, T>()), parent_(0) { }
+  Environment<T>::Environment(bool is_shadow)
+  : local_frame_(std::map<std::string, T>()),
+    parent_(0), is_shadow_(false)
+  { }
   template <typename T>
-  Environment<T>::Environment(Environment<T>* env) : local_frame_(std::map<std::string, T>()), parent_(env) { }
+  Environment<T>::Environment(Environment<T>* env, bool is_shadow)
+  : local_frame_(std::map<std::string, T>()),
+    parent_(env), is_shadow_(is_shadow)
+  { }
   template <typename T>
-  Environment<T>::Environment(Environment<T>& env) : local_frame_(std::map<std::string, T>()), parent_(&env) { }
+  Environment<T>::Environment(Environment<T>& env, bool is_shadow)
+  : local_frame_(std::map<std::string, T>()),
+    parent_(&env), is_shadow_(is_shadow)
+  { }
 
   // link parent to create a stack
   template <typename T>
@@ -118,12 +128,13 @@
   template <typename T>
   void Environment<T>::set_lexical(const std::string& key, T val)
   {
-    auto cur = this;
-    while (cur->is_lexical()) {
+    auto cur = this; bool shadow = false;
+    while (cur->is_lexical() || shadow) {
       if (cur->has_local(key)) {
         cur->set_local(key, val);
         return;
       }
+      shadow = cur->is_shadow();
       cur = cur->parent_;
     }
     set_local(key, val);
@@ -168,8 +179,8 @@
     for (typename std::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* val = dynamic_cast<Value*>(i->second))
-        { std::cerr << " : " << val->to_string(true, 5); }
+        if (Value_Ptr val = SASS_MEMORY_CAST_PTR(Value, i->second))
+        { std::cerr << " : " << val->to_string(); }
         std::cerr << std::endl;
       }
     }
@@ -178,7 +189,7 @@
   #endif
 
   // compile implementation for AST_Node
-  template class Environment<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
@@ -6,7 +6,6 @@
 
 #include "ast_fwd_decl.hpp"
 #include "ast_def_macros.hpp"
-#include "memory_manager.hpp"
 
 namespace Sass {
 
@@ -15,12 +14,12 @@
     // TODO: test with map
     std::map<std::string, T> local_frame_;
     ADD_PROPERTY(Environment*, parent)
+    ADD_PROPERTY(bool, is_shadow)
 
   public:
-    Memory_Manager mem;
-    Environment();
-    Environment(Environment* env);
-    Environment(Environment& env);
+    Environment(bool is_shadow = false);
+    Environment(Environment* env, bool is_shadow = false);
+    Environment(Environment& env, bool is_shadow = false);
 
     // link parent to create a stack
     void link(Environment& env);
@@ -87,6 +86,7 @@
     #endif
 
   };
+
 }
 
 #endif
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
@@ -1,7 +1,7 @@
+#include "sass.hpp"
 #include "ast.hpp"
 #include "prelexer.hpp"
 #include "backtrace.hpp"
-#include "to_string.hpp"
 #include "error_handling.hpp"
 
 #include <iostream>
@@ -10,43 +10,133 @@
 
   namespace Exception {
 
-    Base::Base(ParserState pstate, std::string msg)
-    : std::runtime_error(msg),
-      msg(msg), pstate(pstate)
+    Base::Base(ParserState pstate, std::string msg, std::vector<Sass_Import_Entry>* import_stack)
+    : std::runtime_error(msg), msg(msg),
+      prefix("Error"), pstate(pstate),
+      import_stack(import_stack)
     { }
 
-    const char* Base::what() const throw()
-    {
-      return msg.c_str();
-    }
-
     InvalidSass::InvalidSass(ParserState pstate, std::string msg)
     : Base(pstate, msg)
     { }
 
 
-    InvalidParent::InvalidParent(Selector* parent, Selector* selector)
+    InvalidParent::InvalidParent(Selector_Ptr parent, Selector_Ptr selector)
     : Base(selector->pstate()), parent(parent), selector(selector)
     {
       msg = "Invalid parent selector for \"";
-      msg += selector->to_string(false);
+      msg += selector->to_string(Sass_Inspect_Options());
       msg += "\": \"";
-      msg += parent->to_string(false);;
+      msg += parent->to_string(Sass_Inspect_Options());
       msg += "\"";
     }
 
-    InvalidArgumentType::InvalidArgumentType(ParserState pstate, std::string fn, std::string arg, std::string type, const Value* value)
+    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)
     {
       msg  = arg + ": \"";
-      msg += value->to_string(true, 5);
+      if (value) msg += value->to_string(Sass_Inspect_Options());
       msg += "\" is not a " + type;
       msg += " for `" + fn + "'";
     }
 
-    InvalidSyntax::InvalidSyntax(ParserState pstate, std::string msg)
-    : Base(pstate, msg)
+    MissingArgument::MissingArgument(ParserState pstate, std::string fn, std::string arg, std::string fntype)
+    : Base(pstate), 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)
     { }
+
+    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";
+    }
+
+    DuplicateKeyError::DuplicateKeyError(const Map& dup, const Expression& org)
+    : Base(org.pstate()), dup(dup), org(org)
+    {
+      msg  = "Duplicate key ";
+      msg += dup.get_duplicate_key()->inspect();
+      msg += " in map (";
+      msg += org.inspect();
+      msg += ").";
+    }
+
+    TypeMismatch::TypeMismatch(const Expression& var, const std::string type)
+    : Base(var.pstate()), var(var), type(type)
+    {
+      msg  = var.to_string();
+      msg += " is not an ";
+      msg += type;
+      msg += ".";
+    }
+
+    InvalidValue::InvalidValue(const Expression& val)
+    : Base(val.pstate()), val(val)
+    {
+      msg  = val.to_string();
+      msg += " isn't a valid CSS value.";
+    }
+
+    StackError::StackError(const AST_Node& node)
+    : Base(node.pstate()), node(node)
+    {
+      msg  = "stack level too deep";
+    }
+
+    IncompatibleUnits::IncompatibleUnits(const Number& lhs, const Number& rhs)
+    : lhs(lhs), rhs(rhs)
+    {
+      msg  = "Incompatible units: '";
+      msg += rhs.unit();
+      msg += "' and '";
+      msg += lhs.unit();
+      msg += "'.";
+    }
+
+    AlphaChannelsNotEqual::AlphaChannelsNotEqual(Expression_Ptr_Const lhs, Expression_Ptr_Const rhs, const std::string& op)
+    : lhs(lhs), rhs(rhs), op(op)
+    {
+      msg  = "Alpha channels must be equal: ";
+      msg += lhs->to_string({ NESTED, 5 });
+      msg += " " + op + " ";
+      msg += rhs->to_string({ NESTED, 5 });
+      msg += ".";
+    }
+
+
+    SassValueError::SassValueError(ParserState pstate, OperationError& err)
+    : Base(pstate, err.what())
+    {
+      msg = err.what();
+      prefix = err.errtype();
+    }
 
   }
 
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
@@ -12,16 +12,21 @@
 
   namespace Exception {
 
-    const std::string def_msg = "Invalid sass";
+    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";
 
     class Base : public std::runtime_error {
       protected:
         std::string msg;
+        std::string prefix;
       public:
         ParserState pstate;
+        std::vector<Sass_Import_Entry>* import_stack;
       public:
-        Base(ParserState pstate, std::string msg = def_msg);
-        virtual const char* what() const throw();
+        Base(ParserState pstate, std::string msg = def_msg, std::vector<Sass_Import_Entry>* import_stack = 0);
+        virtual const char* errtype() const { return prefix.c_str(); }
+        virtual const char* what() const throw() { return msg.c_str(); }
         virtual ~Base() throw() {};
     };
 
@@ -33,28 +38,143 @@
 
     class InvalidParent : public Base {
       protected:
-        Selector* parent;
-        Selector* selector;
+        Selector_Ptr parent;
+        Selector_Ptr selector;
       public:
-        InvalidParent(Selector* parent, Selector* selector);
+        InvalidParent(Selector_Ptr parent, Selector_Ptr selector);
         virtual ~InvalidParent() throw() {};
     };
 
+    class MissingArgument : public Base {
+      protected:
+        std::string fn;
+        std::string arg;
+        std::string fntype;
+      public:
+        MissingArgument(ParserState pstate, std::string fn, std::string arg, std::string fntype);
+        virtual ~MissingArgument() throw() {};
+    };
+
     class InvalidArgumentType : public Base {
       protected:
         std::string fn;
         std::string arg;
         std::string type;
-        const Value* value;
+        const Value_Ptr value;
       public:
-        InvalidArgumentType(ParserState pstate, std::string fn, std::string arg, std::string type, const Value* value = 0);
+        InvalidArgumentType(ParserState pstate, std::string fn, std::string arg, std::string type, const Value_Ptr value = 0);
         virtual ~InvalidArgumentType() throw() {};
     };
 
     class InvalidSyntax : public Base {
       public:
-        InvalidSyntax(ParserState pstate, std::string msg);
+        InvalidSyntax(ParserState pstate, std::string msg, std::vector<Sass_Import_Entry>* import_stack = 0);
         virtual ~InvalidSyntax() 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)
+        {};
+      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 DuplicateKeyError : public Base {
+      protected:
+        const Map& dup;
+        const Expression& org;
+      public:
+        DuplicateKeyError(const Map& dup, const Expression& org);
+        virtual const char* errtype() const { return "Error"; }
+        virtual ~DuplicateKeyError() throw() {};
+    };
+
+    class TypeMismatch : public Base {
+      protected:
+        const Expression& var;
+        const std::string type;
+      public:
+        TypeMismatch(const Expression& var, const std::string type);
+        virtual const char* errtype() const { return "Error"; }
+        virtual ~TypeMismatch() throw() {};
+    };
+
+    class InvalidValue : public Base {
+      protected:
+        const Expression& val;
+      public:
+        InvalidValue(const Expression& val);
+        virtual const char* errtype() const { return "Error"; }
+        virtual ~InvalidValue() throw() {};
+    };
+
+    class StackError : public Base {
+      protected:
+        const AST_Node& node;
+      public:
+        StackError(const AST_Node& node);
+        virtual const char* errtype() const { return "SystemStackError"; }
+        virtual ~StackError() throw() {};
+    };
+
+    class IncompatibleUnits : public OperationError {
+      protected:
+        const Number& lhs;
+        const Number& rhs;
+      public:
+        IncompatibleUnits(const Number& lhs, const Number& rhs);
+        virtual ~IncompatibleUnits() throw() {};
+    };
+
+    class UndefinedOperation : public OperationError {
+      protected:
+        Expression_Ptr_Const lhs;
+        Expression_Ptr_Const rhs;
+        const std::string op;
+      public:
+        UndefinedOperation(Expression_Ptr_Const lhs, Expression_Ptr_Const rhs, const std::string& 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);
+        virtual ~InvalidNullOperation() throw() {};
+    };
+
+    class AlphaChannelsNotEqual : public OperationError {
+      protected:
+        Expression_Ptr_Const lhs;
+        Expression_Ptr_Const rhs;
+        const std::string op;
+      public:
+        AlphaChannelsNotEqual(Expression_Ptr_Const lhs, Expression_Ptr_Const rhs, const std::string& op);
+        // virtual const char* errtype() const { return "Error"; }
+        virtual ~AlphaChannelsNotEqual() throw() {};
+    };
+
+    class SassValueError : public Base {
+      public:
+        SassValueError(ParserState pstate, OperationError& err);
+        virtual ~SassValueError() throw() {};
     };
 
   }
diff --git a/libsass/src/eval.cpp b/libsass/src/eval.cpp
--- a/libsass/src/eval.cpp
+++ b/libsass/src/eval.cpp
@@ -1,1530 +1,1712 @@
-#include <cstdlib>
-#include <cmath>
-#include <iostream>
-#include <sstream>
-#include <iomanip>
-#include <typeinfo>
-
-#include "file.hpp"
-#include "eval.hpp"
-#include "ast.hpp"
-#include "bind.hpp"
-#include "util.hpp"
-#include "to_string.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) { return std::abs(std::fmod(x, y)); } // x/0 checked by caller
-  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),
-    listize(exp.ctx)
-  { }
-  Eval::~Eval() { }
-
-  Context& Eval::context()
-  {
-    return ctx;
-  }
-
-  Env* Eval::environment()
-  {
-    return exp.environment();
-  }
-
-  Selector_List* Eval::selector()
-  {
-    return exp.selector();
-  }
-
-  Backtrace* Eval::backtrace()
-  {
-    return exp.backtrace();
-  }
-
-  Expression* Eval::operator()(Block* b)
-  {
-    Expression* val = 0;
-    for (size_t i = 0, L = b->length(); i < L; ++i) {
-      val = (*b)[i]->perform(this);
-      if (val) return val;
-    }
-    return val;
-  }
-
-  Expression* Eval::operator()(Assignment* a)
-  {
-    Env* env = exp.environment();
-    std::string var(a->variable());
-    if (a->is_global()) {
-      if (a->is_default()) {
-        if (env->has_global(var)) {
-          Expression* e = dynamic_cast<Expression*>(env->get_global(var));
-          if (!e || e->concrete_type() == Expression::NULL_VAL) {
-            env->set_global(var, a->value()->perform(this));
-          }
-        }
-        else {
-          env->set_global(var, a->value()->perform(this));
-        }
-      }
-      else {
-        env->set_global(var, a->value()->perform(this));
-      }
-    }
-    else if (a->is_default()) {
-      if (env->has_lexical(var)) {
-        auto cur = env;
-        while (cur && cur->is_lexical()) {
-          if (cur->has_local(var)) {
-            if (AST_Node* node = cur->get_local(var)) {
-              Expression* e = dynamic_cast<Expression*>(node);
-              if (!e || e->concrete_type() == Expression::NULL_VAL) {
-                cur->set_local(var, a->value()->perform(this));
-              }
-            }
-            else {
-              throw 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* node = env->get_global(var)) {
-          Expression* e = dynamic_cast<Expression*>(node);
-          if (!e || e->concrete_type() == Expression::NULL_VAL) {
-            env->set_global(var, a->value()->perform(this));
-          }
-        }
-      }
-      else if (env->is_lexical()) {
-        env->set_local(var, a->value()->perform(this));
-      }
-      else {
-        env->set_local(var, a->value()->perform(this));
-      }
-    }
-    else {
-      env->set_lexical(var, a->value()->perform(this));
-    }
-    return 0;
-  }
-
-  Expression* Eval::operator()(If* i)
-  {
-    Expression* rv = 0;
-    Env env(exp.environment());
-    exp.env_stack.push_back(&env);
-    if (*i->predicate()->perform(this)) {
-      rv = i->block()->perform(this);
-    }
-    else {
-      Block* alt = i->alternative();
-      if (alt) rv = alt->perform(this);
-    }
-    exp.env_stack.pop_back();
-    return rv;
-  }
-
-  // For does not create a new env scope
-  // But iteration vars are reset afterwards
-  Expression* Eval::operator()(For* f)
-  {
-    std::string variable(f->variable());
-    Expression* low = f->lower_bound()->perform(this);
-    if (low->concrete_type() != Expression::NUMBER) {
-      error("lower bound of `@for` directive must be numeric", low->pstate());
-    }
-    Expression* high = f->upper_bound()->perform(this);
-    if (high->concrete_type() != Expression::NUMBER) {
-      error("upper bound of `@for` directive must be numeric", high->pstate());
-    }
-    Number* sass_start = static_cast<Number*>(low);
-    Number* sass_end = static_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());
-    }
-    double start = sass_start->value();
-    double end = sass_end->value();
-    // only create iterator once in this environment
-    Env* env = exp.environment();
-    Number* it = SASS_MEMORY_NEW(env->mem, Number, low->pstate(), start, sass_end->unit());
-    AST_Node* old_var = env->has_local(variable) ? env->get_local(variable) : 0;
-    env->set_local(variable, it);
-    Block* body = f->block();
-    Expression* val = 0;
-    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;
-      }
-    }
-    // restore original environment
-    if (!old_var) env->del_local(variable);
-    else env->set_local(variable, old_var);
-    return val;
-  }
-
-  // Eval does not create a new env scope
-  // But iteration vars are reset afterwards
-  Expression* Eval::operator()(Each* e)
-  {
-    std::vector<std::string> variables(e->variables());
-    Expression* expr = e->list()->perform(this);
-    Env* env = exp.environment();
-    List* list = 0;
-    Map* map = 0;
-    if (expr->concrete_type() == Expression::MAP) {
-      map = static_cast<Map*>(expr);
-    }
-    else if (expr->concrete_type() != Expression::LIST) {
-      list = SASS_MEMORY_NEW(ctx.mem, List, expr->pstate(), 1, SASS_COMMA);
-      *list << expr;
-    }
-    else {
-      list = static_cast<List*>(expr);
-    }
-    // remember variables and then reset them
-    std::vector<AST_Node*> old_vars(variables.size());
-    for (size_t i = 0, L = variables.size(); i < L; ++i) {
-      old_vars[i] = env->has_local(variables[i]) ? env->get_local(variables[i]) : 0;
-      env->set_local(variables[i], 0);
-    }
-    Block* body = e->block();
-    Expression* val = 0;
-
-    if (map) {
-      for (auto key : map->keys()) {
-        Expression* value = map->at(key);
-
-        if (variables.size() == 1) {
-          List* variable = SASS_MEMORY_NEW(ctx.mem, List, map->pstate(), 2, SASS_SPACE);
-          *variable << key;
-          *variable << 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 {
-      for (size_t i = 0, L = list->length(); i < L; ++i) {
-        Expression* e = (*list)[i];
-        // unwrap value if the expression is an argument
-        if (Argument* arg = dynamic_cast<Argument*>(e)) e = arg->value();
-        // check if we got passed a list of args (investigate)
-        if (List* scalars = dynamic_cast<List*>(e)) {
-          if (variables.size() == 1) {
-            Expression* var = scalars;
-            env->set_local(variables[0], var);
-          } else {
-            for (size_t j = 0, K = variables.size(); j < K; ++j) {
-              Expression* res = j >= scalars->length()
-                ? SASS_MEMORY_NEW(ctx.mem, Null, expr->pstate())
-                : (*scalars)[j];
-              env->set_local(variables[j], res);
-            }
-          }
-        } else {
-          if (variables.size() > 0) {
-            env->set_local(variables[0], e);
-            for (size_t j = 1, K = variables.size(); j < K; ++j) {
-              Expression* res = SASS_MEMORY_NEW(ctx.mem, Null, expr->pstate());
-              env->set_local(variables[j], res);
-            }
-          }
-        }
-        val = body->perform(this);
-        if (val) break;
-      }
-    }
-    // restore original environment
-    for (size_t j = 0, K = variables.size(); j < K; ++j) {
-      if(!old_vars[j]) env->del_local(variables[j]);
-      else env->set_local(variables[j], old_vars[j]);
-    }
-    return val;
-  }
-
-  Expression* Eval::operator()(While* w)
-  {
-    Expression* pred = w->predicate();
-    Block* body = w->block();
-    while (*pred->perform(this)) {
-      Expression* val = body->perform(this);
-      if (val) return val;
-    }
-    return 0;
-  }
-
-  Expression* Eval::operator()(Return* r)
-  {
-    return r->value()->perform(this);
-  }
-
-  Expression* Eval::operator()(Warning* w)
-  {
-    Expression* message = w->message()->perform(this);
-    To_String to_string(&ctx);
-    Env* env = exp.environment();
-
-    // try to use generic function
-    if (env->has("@warn[f]")) {
-
-      Definition* def = static_cast<Definition*>((*env)["@warn[f]"]);
-      // Block*          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);
-      sass_delete_value(c_args);
-      sass_delete_value(c_val);
-      return 0;
-
-    }
-
-    std::string result(unquote(message->perform(&to_string)));
-    Backtrace top(backtrace(), w->pstate(), "");
-    std::cerr << "WARNING: " << result;
-    std::cerr << top.to_string(true);
-    std::cerr << std::endl << std::endl;
-    return 0;
-  }
-
-  Expression* Eval::operator()(Error* e)
-  {
-    Expression* message = e->message()->perform(this);
-    To_String to_string(&ctx);
-    Env* env = exp.environment();
-
-    // try to use generic function
-    if (env->has("@error[f]")) {
-
-      Definition* def = static_cast<Definition*>((*env)["@error[f]"]);
-      // Block*          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);
-      sass_delete_value(c_args);
-      sass_delete_value(c_val);
-      return 0;
-
-    }
-
-    std::string result(unquote(message->perform(&to_string)));
-    error(result, e->pstate());
-    return 0;
-  }
-
-  Expression* Eval::operator()(Debug* d)
-  {
-    Expression* message = d->value()->perform(this);
-    To_String to_string(&ctx, false, true);
-    Env* env = exp.environment();
-
-    // try to use generic function
-    if (env->has("@debug[f]")) {
-
-      Definition* def = static_cast<Definition*>((*env)["@debug[f]"]);
-      // Block*          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);
-      sass_delete_value(c_args);
-      sass_delete_value(c_val);
-      return 0;
-
-    }
-
-    std::string cwd(ctx.cwd());
-    std::string result(unquote(message->perform(&to_string)));
-    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));
-
-    std::cerr << output_path << ":" << d->pstate().line+1 << " DEBUG: " << result;
-    std::cerr << std::endl;
-    return 0;
-  }
-
-  Expression* Eval::operator()(List* l)
-  {
-    if (l->is_expanded()) return l;
-    List* ll = SASS_MEMORY_NEW(ctx.mem, List,
-                               l->pstate(),
-                               l->length(),
-                               l->separator(),
-                               l->is_arglist());
-    for (size_t i = 0, L = l->length(); i < L; ++i) {
-      *ll << (*l)[i]->perform(this);
-    }
-    ll->is_expanded(true);
-    return ll;
-  }
-
-  Expression* Eval::operator()(Map* 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()) {
-      To_String to_string(&ctx);
-      error("Duplicate key \"" + m->get_duplicate_key()->perform(&to_string) + "\" in map " + m->perform(&to_string) + ".", m->pstate());
-    }
-
-    Map* mm = SASS_MEMORY_NEW(ctx.mem, Map,
-                                m->pstate(),
-                                m->length());
-    for (auto key : m->keys()) {
-      Expression* ex_key = key->perform(this);
-      Expression* 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()) {
-      To_String to_string(&ctx);
-      error("Duplicate key \"" + mm->get_duplicate_key()->perform(&to_string) + "\" in map " + m->perform(&to_string) + ".", mm->pstate());
-    }
-
-    mm->is_expanded(true);
-    return mm;
-  }
-
-  Expression* Eval::operator()(Binary_Expression* b)
-  {
-    enum Sass_OP op_type = b->type();
-    // don't eval delayed expressions (the '/' when used as a separator)
-    if (op_type == Sass_OP::DIV && b->is_delayed()) return b;
-    b->is_delayed(false);
-    // if one of the operands is a '/' then make sure it's evaluated
-    Expression* lhs = b->left()->perform(this);
-    lhs->is_delayed(false);
-    while (typeid(*lhs) == typeid(Binary_Expression)) {
-      Binary_Expression* lhs_ex = static_cast<Binary_Expression*>(lhs);
-      if (lhs_ex->type() == Sass_OP::DIV && lhs_ex->is_delayed()) break;
-      lhs = Eval::operator()(lhs_ex);
-    }
-
-    switch (op_type) {
-      case Sass_OP::AND:
-        return *lhs ? b->right()->perform(this) : lhs;
-        break;
-
-      case Sass_OP::OR:
-        return *lhs ? lhs : b->right()->perform(this);
-        break;
-
-      default:
-        break;
-    }
-    // not a logical connective, so go ahead and eval the rhs
-    Expression* rhs = b->right()->perform(this);
-    // maybe fully evaluate structure
-    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)
-    {
-      rhs->is_expanded(false);
-      rhs->set_delayed(false);
-      rhs = rhs->perform(this);
-    }
-    else
-    {
-      // rhs->set_delayed(false);
-      // rhs = rhs->perform(this);
-    }
-
-    // upgrade string to number if possible (issue #948)
-    if (op_type == Sass_OP::DIV || op_type == Sass_OP::MUL) {
-      if (String_Constant* str = dynamic_cast<String_Constant*>(rhs)) {
-        std::string value(str->value());
-        const char* start = value.c_str();
-        if (Prelexer::sequence < Prelexer::number >(start) != 0) {
-          rhs = SASS_MEMORY_NEW(ctx.mem, Textual, rhs->pstate(), Textual::DIMENSION, str->value());
-          rhs->is_delayed(false); rhs = rhs->perform(this);
-        }
-      }
-    }
-
-    // see if it's a relational expression
-    switch(op_type) {
-      case Sass_OP::EQ:  return SASS_MEMORY_NEW(ctx.mem, Boolean, b->pstate(), eq(lhs, rhs));
-      case Sass_OP::NEQ: return SASS_MEMORY_NEW(ctx.mem, Boolean, b->pstate(), !eq(lhs, rhs));
-      case Sass_OP::GT:  return SASS_MEMORY_NEW(ctx.mem, Boolean, b->pstate(), !lt(lhs, rhs) && !eq(lhs, rhs));
-      case Sass_OP::GTE: return SASS_MEMORY_NEW(ctx.mem, Boolean, b->pstate(), !lt(lhs, rhs));
-      case Sass_OP::LT:  return SASS_MEMORY_NEW(ctx.mem, Boolean, b->pstate(), lt(lhs, rhs));
-      case Sass_OP::LTE: return SASS_MEMORY_NEW(ctx.mem, Boolean, b->pstate(), lt(lhs, rhs) || eq(lhs, rhs));
-
-      default:                     break;
-    }
-
-
-    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* s1 = dynamic_cast<String_Schema*>(b->left());
-    String_Schema* s2 = dynamic_cast<String_Schema*>(b->right());
-
-    if ((s1 && s1->has_interpolants()) || (s2 && s2->has_interpolants())) {
-      std::string sep;
-      switch (op_type) {
-        case Sass_OP::SUB: sep = "-"; break;
-        case Sass_OP::DIV: sep = "/"; break;
-        case Sass_OP::ADD: sep = "+"; break;
-        case Sass_OP::MUL: sep = "*"; break;
-        default:                      break;
-      }
-
-      // If possible upgrade LHS to a number
-      if (op_type == Sass_OP::DIV || op_type == Sass_OP::MUL || op_type == Sass_OP::ADD || op_type == Sass_OP::SUB) {
-        if (String_Constant* str = dynamic_cast<String_Constant*>(lhs)) {
-          std::string value(str->value());
-          const char* start = value.c_str();
-          if (Prelexer::sequence < Prelexer::number >(start) != 0) {
-            lhs = SASS_MEMORY_NEW(ctx.mem, Textual, lhs->pstate(), Textual::DIMENSION, str->value());
-            lhs->is_delayed(false); lhs = lhs->perform(this);
-          }
-        }
-        if (String_Constant* str = dynamic_cast<String_Constant*>(rhs)) {
-          std::string value(str->value());
-          const char* start = value.c_str();
-          if (Prelexer::sequence < Prelexer::number >(start) != 0) {
-            rhs = SASS_MEMORY_NEW(ctx.mem, Textual, rhs->pstate(), Textual::DIMENSION, str->value());
-            rhs->is_delayed(false); rhs = rhs->perform(this);
-          }
-        }
-      }
-
-      To_Value to_value(ctx, ctx.mem);
-      Value* v_l = dynamic_cast<Value*>(lhs->perform(&to_value));
-      Value* v_r = dynamic_cast<Value*>(rhs->perform(&to_value));
-      Expression::Concrete_Type l_type = lhs->concrete_type();
-      Expression::Concrete_Type r_type = rhs->concrete_type();
-
-      if (l_type == Expression::NUMBER && r_type == Expression::NUMBER) {
-        return SASS_MEMORY_NEW(ctx.mem, String_Constant, lhs->pstate(),
-          v_l->to_string() + " " + sep + " " + v_r->to_string());
-      }
-    }
-
-    // ToDo: throw error in op functions
-    // ToDo: then catch and re-throw them
-    ParserState pstate(b->pstate());
-    int precision = (int)ctx.c_options->precision;
-    bool compressed = ctx.output_style() == SASS_STYLE_COMPRESSED;
-    if (l_type == Expression::NUMBER && r_type == Expression::NUMBER) {
-      const Number* l_n = dynamic_cast<const Number*>(lhs);
-      const Number* r_n = dynamic_cast<const Number*>(rhs);
-      return op_numbers(ctx.mem, op_type, *l_n, *r_n, compressed, precision, &pstate);
-    }
-    if (l_type == Expression::NUMBER && r_type == Expression::COLOR) {
-      const Number* l_n = dynamic_cast<const Number*>(lhs);
-      const Color* r_c = dynamic_cast<const Color*>(rhs);
-      return op_number_color(ctx.mem, op_type, *l_n, *r_c, compressed, precision, &pstate);
-    }
-    if (l_type == Expression::COLOR && r_type == Expression::NUMBER) {
-      const Color* l_c = dynamic_cast<const Color*>(lhs);
-      const Number* r_n = dynamic_cast<const Number*>(rhs);
-      return op_color_number(ctx.mem, op_type, *l_c, *r_n, compressed, precision, &pstate);
-    }
-    if (l_type == Expression::COLOR && r_type == Expression::COLOR) {
-      const Color* l_c = dynamic_cast<const Color*>(lhs);
-      const Color* r_c = dynamic_cast<const Color*>(rhs);
-      return op_colors(ctx.mem, op_type, *l_c, *r_c, compressed, precision, &pstate);
-    }
-
-    To_Value to_value(ctx, ctx.mem);
-    Value* v_l = dynamic_cast<Value*>(lhs->perform(&to_value));
-    Value* v_r = dynamic_cast<Value*>(rhs->perform(&to_value));
-    Value* ex = op_strings(ctx.mem, op_type, *v_l, *v_r, compressed, precision, &pstate);
-    if (String_Constant* str = dynamic_cast<String_Constant*>(ex))
-    {
-      if (str->concrete_type() != Expression::STRING) return ex;
-      String_Constant* lstr = dynamic_cast<String_Constant*>(lhs);
-      String_Constant* rstr = dynamic_cast<String_Constant*>(rhs);
-      if (String_Constant* org = lstr ? lstr : rstr)
-      { str->quote_mark(org->quote_mark()); }
-    }
-    return ex;
-
-  }
-
-  Expression* Eval::operator()(Unary_Expression* u)
-  {
-    Expression* operand = u->operand()->perform(this);
-    if (u->type() == Unary_Expression::NOT) {
-      Boolean* result = SASS_MEMORY_NEW(ctx.mem, Boolean, u->pstate(), (bool)*operand);
-      result->value(!result->value());
-      return result;
-    }
-    else if (operand->concrete_type() == Expression::NUMBER) {
-      Number* result = SASS_MEMORY_NEW(ctx.mem, Number, *static_cast<Number*>(operand));
-      result->value(u->type() == Unary_Expression::MINUS
-                    ? -result->value()
-                    :  result->value());
-      return result;
-    }
-    else {
-      To_String to_string(&ctx);
-      // Special cases: +/- variables which evaluate to null ouput just +/-,
-      // but +/- null itself outputs the string
-      if (operand->concrete_type() == Expression::NULL_VAL && typeid(*(u->operand())) == typeid(Variable)) {
-        u->operand(SASS_MEMORY_NEW(ctx.mem, String_Quoted, u->pstate(), ""));
-      }
-      else u->operand(operand);
-      String_Constant* result = SASS_MEMORY_NEW(ctx.mem, String_Quoted,
-                                                  u->pstate(),
-                                                  u->perform(&to_string));
-      return result;
-    }
-    // unreachable
-    return u;
-  }
-
-  Expression* Eval::operator()(Function_Call* c)
-  {
-    if (backtrace()->parent != NULL && backtrace()->depth() > Constants::MaxCallStack) {
-        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]");
-    Arguments* args = c->arguments();
-    if (full_name != "if[f]") {
-      args = static_cast<Arguments*>(args->perform(this));
-    }
-
-    Env* env = environment();
-    if (!env->has(full_name)) {
-      if (!env->has("*[f]")) {
-        // just pass it through as a literal
-        Function_Call* lit = SASS_MEMORY_NEW(ctx.mem, Function_Call,
-                                             c->pstate(),
-                                             c->name(),
-                                             args);
-        To_String to_string(&ctx);
-        if (args->has_named_arguments()) {
-          error("Function " + c->name() + " doesn't support keyword arguments", c->pstate());
-        }
-        return SASS_MEMORY_NEW(ctx.mem, String_Quoted,
-                               c->pstate(),
-                               lit->perform(&to_string));
-      } else {
-        // call generic function
-        full_name = "*[f]";
-      }
-    }
-
-    Definition* def = static_cast<Definition*>((*env)[full_name]);
-
-    if (def->is_overload_stub()) {
-      std::stringstream ss;
-      ss << full_name
-         << args->length();
-      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 = static_cast<Definition*>((*env)[resolved_name]);
-    }
-
-    Expression*     result = c;
-    Block*          body   = def->block();
-    Native_Function func   = def->native_function();
-    Sass_Function_Entry c_function = def->c_function();
-
-    Parameters* 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);
-      // if it's user-defined, eval the body
-      if (body) result = body->perform(this);
-      // if it's native, invoke the underlying CPP function
-      else result = func(fn_env, *env, ctx, def->signature(), c->pstate(), backtrace());
-      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 *str = SASS_MEMORY_NEW(ctx.mem, String_Quoted, c->pstate(), c->name());
-        Arguments* new_args = SASS_MEMORY_NEW(ctx.mem, Arguments, c->pstate());
-        *new_args << SASS_MEMORY_NEW(ctx.mem, Argument, c->pstate(), str);
-        *new_args += 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[0].length(), SASS_COMMA);
-      for(size_t i = 0; i < params[0].length(); i++) {
-        std::string key = params[0][i]->name();
-        AST_Node* node = fn_env.get_local(key);
-        Expression* arg = static_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(ctx.mem, c_val, ctx, 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->is_delayed(result->concrete_type() == Expression::STRING);
-    if (!result->is_delayed()) result = result->perform(this);
-    exp.env_stack.pop_back();
-    return result;
-  }
-
-  Expression* Eval::operator()(Function_Call_Schema* s)
-  {
-    Expression* evaluated_name = s->name()->perform(this);
-    Expression* evaluated_args = s->arguments()->perform(this);
-    String_Schema* ss = SASS_MEMORY_NEW(ctx.mem, String_Schema, s->pstate(), 2);
-    (*ss) << evaluated_name << evaluated_args;
-    return ss->perform(this);
-  }
-
-  Expression* Eval::operator()(Variable* v)
-  {
-    To_String to_string(&ctx);
-    std::string name(v->name());
-    Expression* value = 0;
-    Env* env = environment();
-    if (env->has(name)) value = static_cast<Expression*>((*env)[name]);
-    else error("Undefined variable: \"" + v->name() + "\".", v->pstate());
-    // std::cerr << "name: " << v->name() << "; type: " << typeid(*value).name() << "; value: " << value->perform(&to_string) << std::endl;
-    if (typeid(*value) == typeid(Argument)) value = static_cast<Argument*>(value)->value();
-
-    // behave according to as ruby sass (add leading zero)
-    if (value->concrete_type() == Expression::NUMBER) {
-      value = SASS_MEMORY_NEW(ctx.mem, Number, *static_cast<Number*>(value));
-      static_cast<Number*>(value)->zero(true);
-    }
-    else if (value->concrete_type() == Expression::STRING) {
-      if (auto str = dynamic_cast<String_Quoted*>(value)) {
-        value = SASS_MEMORY_NEW(ctx.mem, String_Quoted, *str);
-      } else if (auto str = dynamic_cast<String_Constant*>(value)) {
-        value = SASS_MEMORY_NEW(ctx.mem, String_Quoted, str->pstate(), str->perform(&to_string));
-      }
-    }
-    else if (value->concrete_type() == Expression::LIST) {
-      value = SASS_MEMORY_NEW(ctx.mem, List, *static_cast<List*>(value));
-    }
-    else if (value->concrete_type() == Expression::MAP) {
-      value = SASS_MEMORY_NEW(ctx.mem, Map, *static_cast<Map*>(value));
-    }
-    else if (value->concrete_type() == Expression::BOOLEAN) {
-      value = SASS_MEMORY_NEW(ctx.mem, Boolean, *static_cast<Boolean*>(value));
-    }
-    else if (value->concrete_type() == Expression::COLOR) {
-      value = SASS_MEMORY_NEW(ctx.mem, Color, *static_cast<Color*>(value));
-    }
-    else if (value->concrete_type() == Expression::NULL_VAL) {
-      value = SASS_MEMORY_NEW(ctx.mem, Null, value->pstate());
-    }
-    else if (value->concrete_type() == Expression::SELECTOR) {
-      value = value->perform(this); // ->perform(&listize);
-    }
-
-    // std::cerr << "\ttype is now: " << typeid(*value).name() << std::endl << std::endl;
-    return value;
-  }
-
-  Expression* Eval::operator()(Textual* t)
-  {
-    using Prelexer::number;
-    Expression* result = 0;
-    bool zero = !( t->value().substr(0, 1) == "." ||
-                   t->value().substr(0, 2) == "-." );
-
-    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(ctx.mem, Number,
-                                 t->pstate(),
-                                 sass_atof(num.c_str()),
-                                 "",
-                                 zero);
-        break;
-      case Textual::PERCENTAGE:
-        result = SASS_MEMORY_NEW(ctx.mem, Number,
-                                 t->pstate(),
-                                 sass_atof(num.c_str()),
-                                 "%",
-                                 zero);
-        break;
-      case Textual::DIMENSION:
-        result = SASS_MEMORY_NEW(ctx.mem, 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(ctx.mem, 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(ctx.mem, 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, true,
-                                   t->value());
-        }
-        else {
-          result = SASS_MEMORY_NEW(ctx.mem, 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, false,
-                                   t->value());
-        }
-      } break;
-    }
-    return result;
-  }
-
-  Expression* Eval::operator()(Number* n)
-  {
-    return n;
-  }
-
-  Expression* Eval::operator()(Boolean* b)
-  {
-    return b;
-  }
-
-  char is_quoted(std::string str)
-  {
-    size_t len = str.length();
-    if (len < 2) return 0;
-    if ((str[0] == '"' && str[len-1] == '"') || (str[0] == '\'' && str[len-1] == '\'')) {
-      return str[0];
-    }
-    else {
-      return 0;
-    }
-  }
-
-  std::string Eval::interpolation(Expression* s, bool into_quotes) {
-    Env* env = environment();
-    if (String_Quoted* str_quoted = dynamic_cast<String_Quoted*>(s)) {
-      if (str_quoted->quote_mark()) {
-        if (str_quoted->quote_mark() == '*' || str_quoted->is_delayed()) {
-          return evacuate_escapes(str_quoted->value());
-        } else {
-          return string_escape(quote(str_quoted->value(), str_quoted->quote_mark()));
-        }
-      } else {
-        return evacuate_escapes(str_quoted->value());
-      }
-    } else if (String_Constant* str_constant = dynamic_cast<String_Constant*>(s)) {
-      if (into_quotes && !str_constant->is_interpolant()) return str_constant->value();
-      return evacuate_escapes(str_constant->value());
-    } else if (dynamic_cast<Parent_Selector*>(s)) {
-      To_String to_string(&ctx);
-      Expression* sel = s->perform(this);
-      return evacuate_quotes(sel ? sel->perform(&to_string) : "");
-
-    } else if (String_Schema* str_schema = dynamic_cast<String_Schema*>(s)) {
-      // To_String to_string(&ctx);
-      // return evacuate_quotes(str_schema->perform(&to_string));
-
-      std::string res = "";
-      for(auto i : str_schema->elements())
-        res += (interpolation(i));
-      //ToDo: do this in one step
-      auto esc = evacuate_escapes(res);
-      auto unq = unquote(esc);
-      if (unq == esc) {
-        return string_to_output(res);
-      } else {
-        return evacuate_quotes(unq);
-      }
-    } else if (List* list = dynamic_cast<List*>(s)) {
-      std::string acc = ""; // ToDo: different output styles
-      std::string sep = list->separator() == SASS_COMMA ? "," : " ";
-      if (ctx.output_style() != SASS_STYLE_COMPRESSED && sep == ",") sep += " ";
-      bool initial = false;
-      for(auto item : list->elements()) {
-        if (item->concrete_type() != Expression::NULL_VAL) {
-          if (initial) acc += sep;
-          acc += interpolation(item);
-          initial = true;
-        }
-      }
-      return evacuate_quotes(acc);
-    } else if (Variable* var = dynamic_cast<Variable*>(s)) {
-      std::string name(var->name());
-      if (!env->has(name)) error("Undefined variable: \"" + var->name() + "\".", var->pstate());
-      Expression* value = static_cast<Expression*>((*env)[name]);
-      return evacuate_quotes(interpolation(value));
-    } else if (dynamic_cast<Binary_Expression*>(s)) {
-      Expression* ex = s->perform(this);
-      // avoid recursive calls if same object gets returned
-      // since we will call interpolate again for the result
-      if (ex == s) {
-        To_String to_string(&ctx);
-        return evacuate_quotes(s->perform(&to_string));
-      }
-      return evacuate_quotes(interpolation(ex));
-    } else if (dynamic_cast<Function_Call*>(s)) {
-      Expression* ex = s->perform(this);
-      return evacuate_quotes(unquote(interpolation(ex)));
-    } else if (dynamic_cast<Unary_Expression*>(s)) {
-      Expression* ex = s->perform(this);
-      return evacuate_quotes(interpolation(ex));
-    } else if (dynamic_cast<Map*>(s)) {
-      To_String to_string(&ctx);
-      std::string dbg(s->perform(&to_string));
-      error(dbg + " isn't a valid CSS value.", s->pstate());
-      return dbg;
-    } else {
-      To_String to_string(&ctx);
-      return evacuate_quotes(s->perform(&to_string));
-    }
-  }
-
-  Expression* Eval::operator()(String_Schema* s)
-  {
-    std::string acc;
-    bool into_quotes = false;
-    size_t L = s->length();
-    if (L > 1) {
-      if (String_Constant* l = dynamic_cast<String_Constant*>((*s)[0])) {
-        if (String_Constant* r = dynamic_cast<String_Constant*>((*s)[L - 1])) {
-          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;
-        }
-      }
-    }
-    for (size_t i = 0; i < L; ++i) {
-      // really a very special fix, but this is the logic I got from
-      // analyzing the ruby sass behavior and it actually seems to work
-      // https://github.com/sass/libsass/issues/1333
-      if (i == 0 && L > 1 && dynamic_cast<Function_Call*>((*s)[i])) {
-        Expression* ex = (*s)[i]->perform(this);
-        if (auto sq = dynamic_cast<String_Quoted*>(ex)) {
-          if (sq->is_delayed() && ! s->has_interpolants()) {
-            acc += string_escape(quote(sq->value(), sq->quote_mark()));
-          } else {
-            acc += interpolation((*s)[i], into_quotes);
-          }
-        } else if (ex) {
-          acc += interpolation((*s)[i], into_quotes);
-        }
-      } else if ((*s)[i]) {
-        acc += interpolation((*s)[i], into_quotes);
-      }
-    }
-    String_Quoted* str = SASS_MEMORY_NEW(ctx.mem, String_Quoted, s->pstate(), acc);
-    if (!str->quote_mark()) {
-      str->value(string_unescape(str->value()));
-    } else if (str->quote_mark()) {
-      str->quote_mark('*');
-    }
-    str->is_delayed(true);
-    return str;
-  }
-
-  Expression* Eval::operator()(String_Constant* s)
-  {
-    if (!s->is_delayed() && name_to_color(s->value())) {
-      Color* c = SASS_MEMORY_NEW(ctx.mem, Color, *name_to_color(s->value()));
-      c->pstate(s->pstate());
-      c->disp(s->value());
-      return c;
-    }
-    return s;
-  }
-
-  Expression* Eval::operator()(String_Quoted* s)
-  {
-    return s;
-  }
-
-  Expression* Eval::operator()(Supports_Operator* c)
-  {
-    Expression* left = c->left()->perform(this);
-    Expression* right = c->right()->perform(this);
-    Supports_Operator* cc = SASS_MEMORY_NEW(ctx.mem, Supports_Operator,
-                                 c->pstate(),
-                                 static_cast<Supports_Condition*>(left),
-                                 static_cast<Supports_Condition*>(right),
-                                 c->operand());
-    return cc;
-  }
-
-  Expression* Eval::operator()(Supports_Negation* c)
-  {
-    Expression* condition = c->condition()->perform(this);
-    Supports_Negation* cc = SASS_MEMORY_NEW(ctx.mem, Supports_Negation,
-                                 c->pstate(),
-                                 static_cast<Supports_Condition*>(condition));
-    return cc;
-  }
-
-  Expression* Eval::operator()(Supports_Declaration* c)
-  {
-    Expression* feature = c->feature()->perform(this);
-    Expression* value = c->value()->perform(this);
-    Supports_Declaration* cc = SASS_MEMORY_NEW(ctx.mem, Supports_Declaration,
-                              c->pstate(),
-                              feature,
-                              value);
-    return cc;
-  }
-
-  Expression* Eval::operator()(Supports_Interpolation* c)
-  {
-    Expression* value = c->value()->perform(this);
-    Supports_Interpolation* cc = SASS_MEMORY_NEW(ctx.mem, Supports_Interpolation,
-                            c->pstate(),
-                            value);
-    return cc;
-  }
-
-  Expression* Eval::operator()(At_Root_Expression* e)
-  {
-    Expression* feature = e->feature();
-    feature = (feature ? feature->perform(this) : 0);
-    Expression* value = e->value();
-    value = (value ? value->perform(this) : 0);
-    Expression* ee = SASS_MEMORY_NEW(ctx.mem, At_Root_Expression,
-                                     e->pstate(),
-                                     static_cast<String*>(feature),
-                                     value,
-                                     e->is_interpolated());
-    return ee;
-  }
-
-  Expression* Eval::operator()(Media_Query* q)
-  {
-    To_String to_string(&ctx);
-    String* t = q->media_type();
-    t = static_cast<String*>(t ? t->perform(this) : 0);
-    Media_Query* qq = SASS_MEMORY_NEW(ctx.mem, 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 << static_cast<Media_Query_Expression*>((*q)[i]->perform(this));
-    }
-    return qq;
-  }
-
-  Expression* Eval::operator()(Media_Query_Expression* e)
-  {
-    Expression* feature = e->feature();
-    feature = (feature ? feature->perform(this) : 0);
-    if (feature && dynamic_cast<String_Quoted*>(feature)) {
-      feature = SASS_MEMORY_NEW(ctx.mem, String_Quoted,
-                                  feature->pstate(),
-                                  dynamic_cast<String_Quoted*>(feature)->value());
-    }
-    Expression* value = e->value();
-    value = (value ? value->perform(this) : 0);
-    if (value && dynamic_cast<String_Quoted*>(value)) {
-      value = SASS_MEMORY_NEW(ctx.mem, String_Quoted,
-                                value->pstate(),
-                                dynamic_cast<String_Quoted*>(value)->value());
-    }
-    return SASS_MEMORY_NEW(ctx.mem, Media_Query_Expression,
-                           e->pstate(),
-                           feature,
-                           value,
-                           e->is_interpolated());
-  }
-
-  Expression* Eval::operator()(Null* n)
-  {
-    return n;
-  }
-
-  Expression* Eval::operator()(Argument* a)
-  {
-    Expression* val = a->value();
-    val->is_delayed(false);
-    val = val->perform(this);
-    val->is_delayed(false);
-
-    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* wrapper = SASS_MEMORY_NEW(ctx.mem, List,
-                                        val->pstate(),
-                                        0,
-                                        SASS_COMMA,
-                                        true);
-        *wrapper << val;
-        val = wrapper;
-      }
-    }
-    return SASS_MEMORY_NEW(ctx.mem, Argument,
-                           a->pstate(),
-                           val,
-                           a->name(),
-                           is_rest_argument,
-                           is_keyword_argument);
-  }
-
-  Expression* Eval::operator()(Arguments* a)
-  {
-    Arguments* aa = SASS_MEMORY_NEW(ctx.mem, Arguments, a->pstate());
-    for (size_t i = 0, L = a->length(); i < L; ++i) {
-      *aa << static_cast<Argument*>((*a)[i]->perform(this));
-    }
-    return aa;
-  }
-
-  Expression* Eval::operator()(Comment* c)
-  {
-    return 0;
-  }
-
-  inline Expression* Eval::fallback_impl(AST_Node* n)
-  {
-    return static_cast<Expression*>(n);
-  }
-
-  // All the binary helpers.
-
-  bool Eval::eq(Expression* lhs, Expression* rhs)
-  {
-    // use compare operator from ast node
-    return lhs && rhs && *lhs == *rhs;
-  }
-
-  bool Eval::lt(Expression* lhs, Expression* rhs)
-  {
-    Number* l = dynamic_cast<Number*>(lhs);
-    Number* r = dynamic_cast<Number*>(rhs);
-    if (!l) error("may only compare numbers", lhs->pstate());
-    if (!r) error("may only compare numbers", rhs->pstate());
-    // use compare operator from ast node
-    return *l < *r;
-  }
-
-  Value* Eval::op_numbers(Memory_Manager& mem, enum Sass_OP op, const Number& l, const Number& r, bool compressed, int precision, ParserState* pstate)
-  {
-    double lv = l.value();
-    double rv = r.value();
-    if (op == Sass_OP::DIV && !rv) {
-      return SASS_MEMORY_NEW(mem, String_Quoted, pstate ? *pstate : l.pstate(), "Infinity");
-    }
-    if (op == Sass_OP::MOD && !rv) {
-      error("division by zero", pstate ? *pstate : r.pstate());
-    }
-
-    Number tmp(r);
-    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());
-    if (l_unit != r_unit && !l_unit.empty() && !r_unit.empty() &&
-        (op == Sass_OP::ADD || op == Sass_OP::SUB)) {
-      error("Incompatible units: '"+r_unit+"' and '"+l_unit+"'.", pstate ? *pstate : r.pstate());
-    }
-    Number* v = SASS_MEMORY_NEW(mem, Number, l);
-    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, tmp.value()));
-    }
-    v->normalize();
-    return v;
-  }
-
-  Value* Eval::op_number_color(Memory_Manager& mem, enum Sass_OP op, const Number& l, const Color& rh, bool compressed, int precision, ParserState* pstate)
-  {
-    Color r(rh);
-    r.disp("");
-    double lv = l.value();
-    switch (op) {
-      case Sass_OP::ADD:
-      case Sass_OP::MUL: {
-        return SASS_MEMORY_NEW(mem, 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(compressed||!r.sixtuplet(), precision));
-        return SASS_MEMORY_NEW(mem, String_Quoted,
-                               pstate ? *pstate : l.pstate(),
-                               l.to_string(compressed, precision)
-                               + sep
-                               + color);
-      } break;
-      case Sass_OP::MOD: {
-        error("cannot divide a number by a color", pstate ? *pstate : r.pstate());
-      } break;
-      default: break; // caller should ensure that we don't get here
-    }
-    // unreachable
-    return SASS_MEMORY_NEW(mem, Color, rh);
-  }
-
-  Value* Eval::op_color_number(Memory_Manager& mem, enum Sass_OP op, const Color& l, const Number& r, bool compressed, int precision, ParserState* pstate)
-  {
-    double rv = r.value();
-    if (op == Sass_OP::DIV && !rv) error("division by zero", pstate ? *pstate : r.pstate());
-    return SASS_MEMORY_NEW(mem, Color,
-                           pstate ? *pstate : l.pstate(),
-                           ops[op](l.r(), rv),
-                           ops[op](l.g(), rv),
-                           ops[op](l.b(), rv),
-                           l.a());
-  }
-
-  Value* Eval::op_colors(Memory_Manager& mem, enum Sass_OP op, const Color& l, const Color& r, bool compressed, int precision, ParserState* pstate)
-  {
-    if (l.a() != r.a()) {
-      error("alpha channels must be equal when combining colors", pstate ? *pstate : r.pstate());
-    }
-    if (op == Sass_OP::DIV && (!r.r() || !r.g() ||!r.b())) {
-      error("division by zero", pstate ? *pstate : r.pstate());
-    }
-    return SASS_MEMORY_NEW(mem, 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* Eval::op_strings(Memory_Manager& mem, enum Sass_OP op, Value& lhs, Value& rhs, bool compressed, int precision, ParserState* pstate)
-  {
-    Expression::Concrete_Type ltype = lhs.concrete_type();
-    Expression::Concrete_Type rtype = rhs.concrete_type();
-
-    String_Quoted* lqstr = dynamic_cast<String_Quoted*>(&lhs);
-    String_Quoted* rqstr = dynamic_cast<String_Quoted*>(&rhs);
-
-    std::string lstr(lqstr ? lqstr->value() : lhs.to_string(compressed, precision));
-    std::string rstr(rqstr ? rqstr->value() : rhs.to_string(compressed, precision));
-
-    bool l_str_quoted = ((Sass::String*)&lhs) && ((Sass::String*)&lhs)->sass_fix_1291();
-    bool r_str_quoted = ((Sass::String*)&rhs) && ((Sass::String*)&rhs)->sass_fix_1291();
-    bool l_str_color = ltype == Expression::STRING && name_to_color(lstr) && !l_str_quoted;
-    bool r_str_color = rtype == Expression::STRING && name_to_color(rstr) && !r_str_quoted;
-
-    if (l_str_color && r_str_color) {
-      const Color* c_l = name_to_color(lstr);
-      const Color* c_r = name_to_color(rstr);
-      return op_colors(mem, op,*c_l, *c_r, compressed, precision);
-    }
-    else if (l_str_color && rtype == Expression::COLOR) {
-      const Color* c_l = name_to_color(lstr);
-      const Color* c_r = dynamic_cast<const Color*>(&rhs);
-      return op_colors(mem, op, *c_l, *c_r, compressed, precision);
-    }
-    else if (ltype == Expression::COLOR && r_str_color) {
-      const Color* c_l = dynamic_cast<const Color*>(&lhs);
-      const Color* c_r = name_to_color(rstr);
-      return op_colors(mem, op, *c_l, *c_r, compressed, precision);
-    }
-    else if (l_str_color && rtype == Expression::NUMBER) {
-      const Color* c_l = name_to_color(lstr);
-      const Number* n_r = dynamic_cast<const Number*>(&rhs);
-      return op_color_number(mem, op, *c_l, *n_r, compressed, precision);
-    }
-    else if (ltype == Expression::NUMBER && r_str_color) {
-      const Number* n_l = dynamic_cast<const Number*>(&lhs);
-      const Color* c_r = name_to_color(rstr);
-      return op_number_color(mem, op, *n_l, *c_r, compressed, precision);
-    }
-    if (op == Sass_OP::MUL) error("invalid operands for multiplication", lhs.pstate());
-    if (op == Sass_OP::MOD) error("invalid operands for modulo", lhs.pstate());
-    std::string sep;
-    switch (op) {
-      case Sass_OP::SUB: sep = "-"; break;
-      case Sass_OP::DIV: sep = "/"; break;
-      default:                      break;
-    }
-    if (ltype == Expression::NULL_VAL) error("Invalid null operation: \"null plus "+quote(unquote(rstr), '"')+"\".", lhs.pstate());
-    if (rtype == Expression::NULL_VAL) error("Invalid null operation: \""+quote(unquote(lstr), '"')+" plus null\".", rhs.pstate());
-
-    if (ltype == Expression::NUMBER && sep == "/" && rtype == Expression::STRING)
-    {
-      return SASS_MEMORY_NEW(mem, String_Constant, lhs.pstate(),
-        lhs.to_string() + sep + rhs.to_string());
-    }
-
-    if ( (ltype == Expression::STRING || sep == "") &&
-         (sep != "/" || !rqstr || !rqstr->quote_mark())
-    ) {
-      char quote_mark = 0;
-      std::string unq(unquote(lstr + sep + rstr, &quote_mark, true));
-      if (quote_mark && quote_mark != '*') {
-        return SASS_MEMORY_NEW(mem, String_Constant, lhs.pstate(), quote_mark + unq + quote_mark);
-      }
-      return SASS_MEMORY_NEW(mem, String_Quoted, lhs.pstate(), lstr + sep + rstr);
-    }
-    return SASS_MEMORY_NEW(mem, String_Constant, lhs.pstate(), (lstr) + sep + quote(rstr));
-  }
-
-  Expression* cval_to_astnode(Memory_Manager& mem, union Sass_Value* v, Context& ctx, Backtrace* backtrace, ParserState pstate)
-  {
-    using std::strlen;
-    using std::strcpy;
-    Expression* e = 0;
-    switch (sass_value_get_tag(v)) {
-      case SASS_BOOLEAN: {
-        e = SASS_MEMORY_NEW(mem, Boolean, pstate, !!sass_boolean_get_value(v));
-      } break;
-      case SASS_NUMBER: {
-        e = SASS_MEMORY_NEW(mem, Number, pstate, sass_number_get_value(v), sass_number_get_unit(v));
-      } break;
-      case SASS_COLOR: {
-        e = SASS_MEMORY_NEW(mem, 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(mem, String_Quoted, pstate, sass_string_get_value(v));
-        else {
-          e = SASS_MEMORY_NEW(mem, String_Constant, pstate, sass_string_get_value(v));
-        }
-      } break;
-      case SASS_LIST: {
-        List* l = SASS_MEMORY_NEW(mem, 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 << cval_to_astnode(mem, sass_list_get_value(v, i), ctx, backtrace, pstate);
-        }
-        e = l;
-      } break;
-      case SASS_MAP: {
-        Map* m = SASS_MEMORY_NEW(mem, Map, pstate);
-        for (size_t i = 0, L = sass_map_get_length(v); i < L; ++i) {
-          *m << std::make_pair(
-            cval_to_astnode(mem, sass_map_get_key(v, i), ctx, backtrace, pstate),
-            cval_to_astnode(mem, sass_map_get_value(v, i), ctx, backtrace, pstate));
-        }
-        e = m;
-      } break;
-      case SASS_NULL: {
-        e = SASS_MEMORY_NEW(mem, 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* Eval::operator()(Selector_List* s)
-  {
-    std::vector<Selector_List*> rv;
-    Selector_List* sl = SASS_MEMORY_NEW(ctx.mem, Selector_List, s->pstate());
-    sl->media_block(s->media_block());
-    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 << (*rv[i])[round];
-          abort = false;
-        }
-      }
-      if (abort) {
-        round = std::string::npos;
-      } else {
-        ++ round;
-      }
-
-    }
-    return sl;
-  }
-
-
-  Selector_List* Eval::operator()(Complex_Selector* s)
-  {
-    return s->parentize(selector(), ctx);
-
-  }
-
-  Attribute_Selector* Eval::operator()(Attribute_Selector* s)
-  {
-    String* attr = s->value();
-    if (attr) { attr = static_cast<String*>(attr->perform(this)); }
-    Attribute_Selector* ss = SASS_MEMORY_NEW(ctx.mem, Attribute_Selector, *s);
-    ss->value(attr);
-    return ss;
-  }
-
-  Selector_List* Eval::operator()(Selector_Schema* s)
-  {
-    To_String to_string;
-    // the parser will look for a brace to end the selector
-    std::string result_str(s->contents()->perform(this)->perform(&to_string));
-    result_str = unquote(Util::rtrim(result_str)) + "{";
-    Parser p = Parser::from_c_str(result_str.c_str(), ctx, s->pstate());
-    return operator()(p.parse_selector_list(exp.block_stack.back()->is_root()));
-  }
-
-  Expression* Eval::operator()(Parent_Selector* p)
-  {
-    Selector_List* pr = selector();
-    if (pr) {
-      exp.selector_stack.pop_back();
-      pr = operator()(pr);
-      exp.selector_stack.push_back(pr);
-      return pr;
-    } else {
-      return SASS_MEMORY_NEW(ctx.mem, Null, p->pstate());
+#include "sass.hpp"
+#include <cstdlib>
+#include <cmath>
+#include <iostream>
+#include <sstream>
+#include <iomanip>
+#include <typeinfo>
+
+#include "file.hpp"
+#include "eval.hpp"
+#include "ast.hpp"
+#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());
     }
   }
 
diff --git a/libsass/src/eval.hpp b/libsass/src/eval.hpp
--- a/libsass/src/eval.hpp
+++ b/libsass/src/eval.hpp
@@ -1,106 +1,108 @@
 #ifndef SASS_EVAL_H
 #define SASS_EVAL_H
 
+#include "ast.hpp"
 #include "context.hpp"
 #include "listize.hpp"
 #include "operation.hpp"
+#include "environment.hpp"
 
 namespace Sass {
 
   class Expand;
   class Context;
-  class Listize;
 
-  class Eval : public Operation_CRTP<Expression*, Eval> {
+  class Eval : public Operation_CRTP<Expression_Ptr, Eval> {
 
    private:
-    Expression* fallback_impl(AST_Node* n);
+    Expression_Ptr fallback_impl(AST_Node_Ptr n);
 
    public:
     Expand&  exp;
     Context& ctx;
-    Listize  listize;
     Eval(Expand& exp);
-    virtual ~Eval();
+    ~Eval();
 
+    bool force;
+    bool is_in_comment;
+
     Env* environment();
-    Context& context();
-    Selector_List* selector();
     Backtrace* backtrace();
-
-    using Operation<Expression*>::operator();
+    Selector_List_Obj selector();
 
     // for evaluating function bodies
-    Expression* operator()(Block*);
-    Expression* operator()(Assignment*);
-    Expression* operator()(If*);
-    Expression* operator()(For*);
-    Expression* operator()(Each*);
-    Expression* operator()(While*);
-    Expression* operator()(Return*);
-    Expression* operator()(Warning*);
-    Expression* operator()(Error*);
-    Expression* operator()(Debug*);
+    Expression_Ptr operator()(Block_Ptr);
+    Expression_Ptr operator()(Assignment_Ptr);
+    Expression_Ptr operator()(If_Ptr);
+    Expression_Ptr operator()(For_Ptr);
+    Expression_Ptr operator()(Each_Ptr);
+    Expression_Ptr operator()(While_Ptr);
+    Expression_Ptr operator()(Return_Ptr);
+    Expression_Ptr operator()(Warning_Ptr);
+    Expression_Ptr operator()(Error_Ptr);
+    Expression_Ptr operator()(Debug_Ptr);
 
-    Expression* operator()(List*);
-    Expression* operator()(Map*);
-    Expression* operator()(Binary_Expression*);
-    Expression* operator()(Unary_Expression*);
-    Expression* operator()(Function_Call*);
-    Expression* operator()(Function_Call_Schema*);
-    Expression* operator()(Variable*);
-    Expression* operator()(Textual*);
-    Expression* operator()(Number*);
-    Expression* operator()(Boolean*);
-    Expression* operator()(String_Schema*);
-    Expression* operator()(String_Quoted*);
-    Expression* operator()(String_Constant*);
-    // Expression* operator()(Selector_List*);
-    Expression* operator()(Media_Query*);
-    Expression* operator()(Media_Query_Expression*);
-    Expression* operator()(At_Root_Expression*);
-    Expression* operator()(Supports_Operator*);
-    Expression* operator()(Supports_Negation*);
-    Expression* operator()(Supports_Declaration*);
-    Expression* operator()(Supports_Interpolation*);
-    Expression* operator()(Null*);
-    Expression* operator()(Argument*);
-    Expression* operator()(Arguments*);
-    Expression* operator()(Comment*);
+    Expression_Ptr operator()(List_Ptr);
+    Expression_Ptr operator()(Map_Ptr);
+    Expression_Ptr operator()(Binary_Expression_Ptr);
+    Expression_Ptr operator()(Unary_Expression_Ptr);
+    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);
+    Expression_Ptr operator()(String_Schema_Ptr);
+    Expression_Ptr operator()(String_Quoted_Ptr);
+    Expression_Ptr operator()(String_Constant_Ptr);
+    // Expression_Ptr operator()(Selector_List_Ptr);
+    Expression_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);
+    Expression_Ptr operator()(Supports_Negation_Ptr);
+    Expression_Ptr operator()(Supports_Declaration_Ptr);
+    Expression_Ptr operator()(Supports_Interpolation_Ptr);
+    Expression_Ptr operator()(Null_Ptr);
+    Expression_Ptr operator()(Argument_Ptr);
+    Expression_Ptr operator()(Arguments_Ptr);
+    Expression_Ptr operator()(Comment_Ptr);
 
     // these will return selectors
-    Selector_List* operator()(Selector_List*);
-    Selector_List* operator()(Complex_Selector*);
-    Attribute_Selector* operator()(Attribute_Selector*);
+    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)
-    Type_Selector* operator()(Type_Selector* s) { return s; };
-    Pseudo_Selector* operator()(Pseudo_Selector* s) { return s; };
-    Wrapped_Selector* operator()(Wrapped_Selector* s) { return s; };
-    Selector_Qualifier* operator()(Selector_Qualifier* s) { return s; };
-    Selector_Placeholder* operator()(Selector_Placeholder* s) { return s; };
+    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; };
     // actual evaluated selectors
-    Selector_List* operator()(Selector_Schema*);
-    Expression* operator()(Parent_Selector*);
+    Selector_List_Ptr operator()(Selector_Schema_Ptr);
+    Expression_Ptr operator()(Parent_Selector_Ptr);
 
     template <typename U>
-    Expression* fallback(U x) { return fallback_impl(x); }
+    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*, Expression*);
-    static bool lt(Expression*, Expression*);
+    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* op_numbers(Memory_Manager&, enum Sass_OP, const Number&, const Number&, bool compressed = false, int precision = 5, ParserState* pstate = 0);
-    static Value* op_number_color(Memory_Manager&, enum Sass_OP, const Number&, const Color&, bool compressed = false, int precision = 5, ParserState* pstate = 0);
-    static Value* op_color_number(Memory_Manager&, enum Sass_OP, const Color&, const Number&, bool compressed = false, int precision = 5, ParserState* pstate = 0);
-    static Value* op_colors(Memory_Manager&, enum Sass_OP, const Color&, const Color&, bool compressed = false, int precision = 5, ParserState* pstate = 0);
-    static Value* op_strings(Memory_Manager&, enum Sass_OP, Value&, Value&, bool compressed = false, int precision = 5, ParserState* pstate = 0);
+    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:
-    std::string interpolation(Expression* s, bool into_quotes = false);
+    void interpolation(Context& ctx, std::string& res, Expression_Obj ex, bool into_quotes, bool was_itpl = false);
 
   };
 
-  Expression* cval_to_astnode(Memory_Manager& mem, union Sass_Value* v, Context& ctx, Backtrace* backtrace, ParserState pstate = ParserState("[AST]"));
+  Expression_Ptr cval_to_astnode(union Sass_Value* v, Backtrace* backtrace, 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
@@ -1,36 +1,41 @@
-#ifdef _MSC_VER
-#pragma warning(disable : 4503)
-#endif
-
+#include "sass.hpp"
 #include <iostream>
 #include <typeinfo>
 
+#include "ast.hpp"
 #include "expand.hpp"
 #include "bind.hpp"
 #include "eval.hpp"
-#include "to_string.hpp"
 #include "backtrace.hpp"
 #include "context.hpp"
 #include "parser.hpp"
 
 namespace Sass {
 
-  Expand::Expand(Context& ctx, Env* env, Backtrace* bt)
+  // simple endless recursion protection
+  const size_t maxRecursion = 500;
+
+  Expand::Expand(Context& ctx, Env* env, Backtrace* bt, std::vector<Selector_List_Obj>* stack)
   : ctx(ctx),
     eval(Eval(*this)),
+    recursions(0),
+    in_keyframes(false),
+    at_root_without_rule(false),
+    old_at_root_without_rule(false),
     env_stack(std::vector<Env*>()),
-    block_stack(std::vector<Block*>()),
-    property_stack(std::vector<String*>()),
-    selector_stack(std::vector<Selector_List*>()),
-    backtrace_stack(std::vector<Backtrace*>()),
-    in_keyframes(false)
+    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*>())
   {
     env_stack.push_back(0);
     env_stack.push_back(env);
     block_stack.push_back(0);
-    // import_stack.push_back(0);
-    property_stack.push_back(0);
-    selector_stack.push_back(0);
+    call_stack.push_back(0);
+    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);
   }
@@ -47,7 +52,7 @@
     return 0;
   }
 
-  Selector_List* Expand::selector()
+  Selector_List_Obj Expand::selector()
   {
     if (selector_stack.size() > 0)
       return selector_stack.back();
@@ -62,161 +67,167 @@
   }
 
   // blocks create new variable scopes
-  Statement* Expand::operator()(Block* b)
+  Block_Ptr Expand::operator()(Block_Ptr b)
   {
     // create new local environment
     // set the current env as parent
     Env env(environment());
     // copy the block object (add items later)
-    Block* bb = SASS_MEMORY_NEW(ctx.mem, Block,
+    Block_Obj bb = SASS_MEMORY_NEW(Block,
                                 b->pstate(),
                                 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!
     this->append_block(b);
     // revert block and env stack
     this->block_stack.pop_back();
     this->env_stack.pop_back();
     // return copy
-    return bb;
+    return bb.detach();
   }
 
-  Statement* Expand::operator()(Ruleset* r)
+  Statement_Ptr Expand::operator()(Ruleset_Ptr r)
   {
-    // reset when leaving scope
+    LOCAL_FLAG(old_at_root_without_rule, at_root_without_rule);
 
     if (in_keyframes) {
-      Keyframe_Rule* k = SASS_MEMORY_NEW(ctx.mem, Keyframe_Rule, r->pstate(), r->block()->perform(this)->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->selector(static_cast<Selector_List*>(r->selector()->perform(&eval)));
+        k->name(SASS_MEMORY_CAST_PTR(Selector_List, r->selector()->perform(&eval)));
         selector_stack.pop_back();
       }
-      return k;
+      return k.detach();
     }
 
+    // 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* selector_list = dynamic_cast<Selector_List*>(r->selector())) {
-        for (Complex_Selector* complex_selector : selector_list->elements()) {
-          Complex_Selector* tail = complex_selector;
+      if (Selector_List_Ptr selector_list = SASS_MEMORY_CAST(Selector_List, r->selector())) {
+        for (Complex_Selector_Obj complex_selector : selector_list->elements()) {
+          Complex_Selector_Ptr tail = &complex_selector;
           while (tail) {
-            if (tail->head()) for (Simple_Selector* header : tail->head()->elements()) {
-              if (dynamic_cast<Parent_Selector*>(header) == NULL) continue; // skip all others
-              To_String to_string(&ctx); std::string sel_str(complex_selector->perform(&to_string));
+            if (tail->head()) for (Simple_Selector_Obj header : tail->head()->elements()) {
+              if (SASS_MEMORY_CAST(Parent_Selector, header) == NULL) continue; // skip all others
+              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());
             }
-            tail = tail->tail();
+            tail = &tail->tail();
           }
         }
       }
     }
 
-    Expression* ex = r->selector()->perform(&eval);
-    Selector_List* sel = dynamic_cast<Selector_List*>(ex);
+    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");
 
-    selector_stack.push_back(sel);
-    Block* blk = r->block()->perform(this)->block();
-    Ruleset* rr = SASS_MEMORY_NEW(ctx.mem, Ruleset,
+    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());
+      }
+    }
+
+    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());
+    Ruleset_Ptr rr = SASS_MEMORY_NEW(Ruleset,
                                   r->pstate(),
-                                  sel,
+                                  &sel,
                                   blk);
     selector_stack.pop_back();
-    rr->tabs(r->tabs());
-
-    return rr;
-  }
-
-  Statement* Expand::operator()(Propset* p)
-  {
-    property_stack.push_back(p->property_fragment());
-    Block* expanded_block = p->block()->perform(this)->block();
-
-    for (size_t i = 0, L = expanded_block->length(); i < L; ++i) {
-      Statement* stm = (*expanded_block)[i];
-      if (Declaration* dec = static_cast<Declaration*>(stm)) {
-        String_Schema* combined_prop = SASS_MEMORY_NEW(ctx.mem, String_Schema, p->pstate());
-        if (!property_stack.empty()) {
-          *combined_prop << property_stack.back()->perform(&eval)
-                         << SASS_MEMORY_NEW(ctx.mem, String_Quoted,
-             p->pstate(), "-")
-             << dec->property(); // TODO: eval the prop into a string constant
-        }
-        else {
-          *combined_prop << dec->property();
-        }
-        dec->property(combined_prop);
-        *block_stack.back() << dec;
-      }
-      else if (typeid(*stm) == typeid(Comment)) {
-        // drop comments in propsets
-      }
-      else {
-        error("contents of namespaced properties must result in style declarations only", stm->pstate(), backtrace());
-      }
+    if (block_stack.back()->is_root()) {
+      env_stack.pop_back();
     }
 
-    property_stack.pop_back();
+    rr->is_root(r->is_root());
+    rr->tabs(r->tabs());
 
-    return 0;
+    return rr;
   }
 
-  Statement* Expand::operator()(Supports_Block* f)
+  Statement_Ptr Expand::operator()(Supports_Block_Ptr f)
   {
-    Expression* condition = f->condition()->perform(&eval);
-    Supports_Block* ff = SASS_MEMORY_NEW(ctx.mem, Supports_Block,
+    Expression_Obj condition = f->condition()->perform(&eval);
+    Supports_Block_Obj ff = SASS_MEMORY_NEW(Supports_Block,
                                        f->pstate(),
-                                       static_cast<Supports_Condition*>(condition),
-                                       f->block()->perform(this)->block());
-    return ff;
+                                       SASS_MEMORY_CAST(Supports_Condition, condition),
+                                       operator()(&f->block()));
+    return ff.detach();
   }
 
-  Statement* Expand::operator()(Media_Block* m)
+  Statement_Ptr Expand::operator()(Media_Block_Ptr m)
   {
-    To_String to_string(&ctx);
-    Expression* mq = m->media_queries()->perform(&eval);
-    mq = Parser::from_c_str(mq->perform(&to_string).c_str(), ctx, mq->pstate()).parse_media_queries();
-    Media_Block* mm = SASS_MEMORY_NEW(ctx.mem, Media_Block,
+    media_block_stack.push_back(m);
+    Expression_Obj mq = m->media_queries()->perform(&eval);
+    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());
+    Media_Block_Ptr mm = SASS_MEMORY_NEW(Media_Block,
                                       m->pstate(),
-                                      static_cast<List*>(mq),
-                                      m->block()->perform(this)->block(),
+                                      ls,
+                                      blk,
                                       0);
+    media_block_stack.pop_back();
     mm->tabs(m->tabs());
     return mm;
   }
 
-  Statement* Expand::operator()(At_Root_Block* a)
+  Statement_Ptr Expand::operator()(At_Root_Block_Ptr a)
   {
-    Block* ab = a->block();
-    // if (ab) ab->is_root(true);
-    Expression* ae = a->expression();
+    Block_Obj ab = a->block();
+    Expression_Obj ae = &a->expression();
+
     if (ae) ae = ae->perform(&eval);
-    else ae = SASS_MEMORY_NEW(ctx.mem, At_Root_Expression, a->pstate());
-    Block* bb = ab ? ab->perform(this)->block() : 0;
-    At_Root_Block* aa = SASS_MEMORY_NEW(ctx.mem, At_Root_Block,
+    else ae = SASS_MEMORY_NEW(At_Root_Query, a->pstate());
+
+    LOCAL_FLAG(at_root_without_rule, true);
+    LOCAL_FLAG(in_keyframes, false);
+
+                                       ;
+
+    Block_Obj bb = ab ? operator()(&ab) : NULL;
+    At_Root_Block_Obj aa = SASS_MEMORY_NEW(At_Root_Block,
                                         a->pstate(),
                                         bb,
-                                        static_cast<At_Root_Expression*>(ae));
-    // aa->block()->is_root(true);
-    return aa;
+                                        SASS_MEMORY_CAST(At_Root_Query, ae));
+    return aa.detach();
   }
 
-  Statement* Expand::operator()(At_Rule* a)
+  Statement_Ptr Expand::operator()(Directive_Ptr a)
   {
     LOCAL_FLAG(in_keyframes, a->is_keyframes());
-    Block* ab = a->block();
-    Selector* as = a->selector();
-    Expression* av = a->value();
+    Block_Ptr ab = &a->block();
+    Selector_Ptr as = &a->selector();
+    Expression_Ptr av = &a->value();
     selector_stack.push_back(0);
     if (av) av = av->perform(&eval);
-    if (as) as = dynamic_cast<Selector*>(as->perform(&eval));
+    if (as) as = SASS_MEMORY_CAST_PTR(Selector, as->perform(&eval));
     selector_stack.pop_back();
-    Block* bb = ab ? ab->perform(this)->block() : 0;
-    At_Rule* aa = SASS_MEMORY_NEW(ctx.mem, At_Rule,
+    Block_Ptr bb = ab ? operator()(ab) : NULL;
+    Directive_Ptr aa = SASS_MEMORY_NEW(Directive,
                                   a->pstate(),
                                   a->keyword(),
                                   as,
@@ -225,29 +236,40 @@
     return aa;
   }
 
-  Statement* Expand::operator()(Declaration* d)
+  Statement_Ptr Expand::operator()(Declaration_Ptr d)
   {
-    String* old_p = d->property();
-    String* new_p = static_cast<String*>(old_p->perform(&eval));
-    Expression* value = d->value()->perform(&eval);
-    if (!value || (value->is_invisible() && !d->is_important())) return 0;
-    Declaration* decl = SASS_MEMORY_NEW(ctx.mem, Declaration,
+    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);
+    // 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;
+    if (!bb) {
+      if (!value || (value->is_invisible() && !d->is_important())) return 0;
+    }
+    Declaration_Ptr decl = SASS_MEMORY_NEW(Declaration,
                                         d->pstate(),
                                         new_p,
                                         value,
-                                        d->is_important());
+                                        d->is_important(),
+                                        bb);
     decl->tabs(d->tabs());
     return decl;
   }
 
-  Statement* Expand::operator()(Assignment* a)
+  Statement_Ptr Expand::operator()(Assignment_Ptr a)
   {
     Env* env = environment();
     std::string var(a->variable());
     if (a->is_global()) {
       if (a->is_default()) {
         if (env->has_global(var)) {
-          Expression* e = dynamic_cast<Expression*>(env->get_global(var));
+          Expression_Obj e = SASS_MEMORY_CAST(Expression, env->get_global(var));
           if (!e || e->concrete_type() == Expression::NULL_VAL) {
             env->set_global(var, a->value()->perform(&eval));
           }
@@ -265,8 +287,8 @@
         auto cur = env;
         while (cur && cur->is_lexical()) {
           if (cur->has_local(var)) {
-            if (AST_Node* node = cur->get_local(var)) {
-              Expression* e = dynamic_cast<Expression*>(node);
+            if (AST_Node_Obj node = cur->get_local(var)) {
+              Expression_Obj e = SASS_MEMORY_CAST(Expression, node);
               if (!e || e->concrete_type() == Expression::NULL_VAL) {
                 cur->set_local(var, a->value()->perform(&eval));
               }
@@ -281,8 +303,8 @@
         throw std::runtime_error("Env not in sync");
       }
       else if (env->has_global(var)) {
-        if (AST_Node* node = env->get_global(var)) {
-          Expression* e = dynamic_cast<Expression*>(node);
+        if (AST_Node_Obj node = env->get_global(var)) {
+          Expression_Obj e = SASS_MEMORY_CAST(Expression, node);
           if (!e || e->concrete_type() == Expression::NULL_VAL) {
             env->set_global(var, a->value()->perform(&eval));
           }
@@ -301,23 +323,28 @@
     return 0;
   }
 
-  Statement* Expand::operator()(Import* imp)
+  Statement_Ptr Expand::operator()(Import_Ptr imp)
   {
-    Import* result = SASS_MEMORY_NEW(ctx.mem, Import, imp->pstate());
-    if (imp->media_queries() && imp->media_queries()->size()) {
-      Expression* ex = imp->media_queries()->perform(&eval);
-      result->media_queries(dynamic_cast<List*>(ex));
+    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));
     }
     for ( size_t i = 0, S = imp->urls().size(); i < S; ++i) {
       result->urls().push_back(imp->urls()[i]->perform(&eval));
     }
     // all resources have been dropped for Input_Stubs
     // for ( size_t i = 0, S = imp->incs().size(); i < S; ++i) {}
-    return result;
+    return result.detach();
   }
 
-  Statement* Expand::operator()(Import_Stub* i)
+  Statement_Ptr Expand::operator()(Import_Stub_Ptr i)
   {
+    // 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());
+    }
     // we don't seem to need that actually afterall
     Sass_Import_Entry import = sass_make_import(
       i->imp_path().c_str(),
@@ -326,66 +353,75 @@
     );
     ctx.import_stack.push_back(import);
     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();
     return 0;
   }
 
-  Statement* Expand::operator()(Warning* w)
+  Statement_Ptr Expand::operator()(Warning_Ptr w)
   {
     // eval handles this too, because warnings may occur in functions
     w->perform(&eval);
     return 0;
   }
 
-  Statement* Expand::operator()(Error* e)
+  Statement_Ptr Expand::operator()(Error_Ptr e)
   {
     // eval handles this too, because errors may occur in functions
     e->perform(&eval);
     return 0;
   }
 
-  Statement* Expand::operator()(Debug* d)
+  Statement_Ptr Expand::operator()(Debug_Ptr d)
   {
     // eval handles this too, because warnings may occur in functions
     d->perform(&eval);
     return 0;
   }
 
-  Statement* Expand::operator()(Comment* c)
+  Statement_Ptr Expand::operator()(Comment_Ptr c)
   {
+    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());
+    eval.is_in_comment = false;
     // TODO: eval the text, once we're parsing/storing it as a String_Schema
-    return SASS_MEMORY_NEW(ctx.mem, Comment, c->pstate(), static_cast<String*>(c->text()->perform(&eval)), c->is_important());
+    return rv;
   }
 
-  Statement* Expand::operator()(If* i)
+  Statement_Ptr Expand::operator()(If_Ptr i)
   {
-    if (*i->predicate()->perform(&eval)) {
-      append_block(i->block());
+    Env env(environment(), true);
+    env_stack.push_back(&env);
+    call_stack.push_back(i);
+    Expression_Obj rv = i->predicate()->perform(&eval);
+    if (*rv) {
+      append_block(&i->block());
     }
     else {
-      Block* alt = i->alternative();
+      Block_Ptr alt = &i->alternative();
       if (alt) append_block(alt);
     }
+    call_stack.pop_back();
+    env_stack.pop_back();
     return 0;
   }
 
   // For does not create a new env scope
   // But iteration vars are reset afterwards
-  Statement* Expand::operator()(For* f)
+  Statement_Ptr Expand::operator()(For_Ptr f)
   {
     std::string variable(f->variable());
-    Expression* low = f->lower_bound()->perform(&eval);
+    Expression_Obj low = f->lower_bound()->perform(&eval);
     if (low->concrete_type() != Expression::NUMBER) {
-      error("lower bound of `@for` directive must be numeric", low->pstate(), backtrace());
+      throw Exception::TypeMismatch(*low, "integer");
     }
-    Expression* high = f->upper_bound()->perform(&eval);
+    Expression_Obj high = f->upper_bound()->perform(&eval);
     if (high->concrete_type() != Expression::NUMBER) {
-      error("upper bound of `@for` directive must be numeric", high->pstate(), backtrace());
+      throw Exception::TypeMismatch(*high, "integer");
     }
-    Number* sass_start = static_cast<Number*>(low);
-    Number* sass_end = static_cast<Number*>(high);
+    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: '"
@@ -396,18 +432,20 @@
     double start = sass_start->value();
     double end = sass_end->value();
     // only create iterator once in this environment
-    Env* env = environment();
-    Number* it = SASS_MEMORY_NEW(env->mem, Number, low->pstate(), start, sass_end->unit());
-    AST_Node* old_var = env->has_local(variable) ? env->get_local(variable) : 0;
-    env->set_local(variable, it);
-    Block* body = f->block();
+    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();
     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);
+        env.set_local(variable, &it);
         append_block(body);
       }
     } else {
@@ -415,131 +453,136 @@
       for (double i = start;
            i > end;
            --i) {
+        it = SASS_MEMORY_COPY(it);
         it->value(i);
-        env->set_local(variable, it);
+        env.set_local(variable, &it);
         append_block(body);
       }
     }
-    // restore original environment
-    if (!old_var) env->del_local(variable);
-    else env->set_local(variable, old_var);
+    call_stack.pop_back();
+    env_stack.pop_back();
     return 0;
   }
 
   // Eval does not create a new env scope
   // But iteration vars are reset afterwards
-  Statement* Expand::operator()(Each* e)
+  Statement_Ptr Expand::operator()(Each_Ptr e)
   {
     std::vector<std::string> variables(e->variables());
-    Expression* expr = e->list()->perform(&eval);
-    List* list = 0;
-    Map* map = 0;
+    Expression_Obj expr = e->list()->perform(&eval);
+    List_Obj list = 0;
+    Map_Obj map;
     if (expr->concrete_type() == Expression::MAP) {
-      map = static_cast<Map*>(expr);
+      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 = SASS_MEMORY_CAST(List, rv);
+    }
     else if (expr->concrete_type() != Expression::LIST) {
-      list = SASS_MEMORY_NEW(ctx.mem, List, expr->pstate(), 1, SASS_COMMA);
-      *list << expr;
+      list = SASS_MEMORY_NEW(List, expr->pstate(), 1, SASS_COMMA);
+      list->append(expr);
     }
     else {
-      list = static_cast<List*>(expr);
+      list = SASS_MEMORY_CAST(List, expr);
     }
     // remember variables and then reset them
-    Env* env = environment();
-    std::vector<AST_Node*> old_vars(variables.size());
-    for (size_t i = 0, L = variables.size(); i < L; ++i) {
-      old_vars[i] = env->has_local(variables[i]) ? env->get_local(variables[i]) : 0;
-      env->set_local(variables[i], 0);
-    }
-    Block* body = e->block();
+    Env env(environment(), true);
+    env_stack.push_back(&env);
+    call_stack.push_back(e);
+    Block_Ptr body = &e->block();
 
     if (map) {
       for (auto key : map->keys()) {
-        Expression* k = key->perform(&eval);
-        Expression* v = map->at(key)->perform(&eval);
+        Expression_Obj k = key->perform(&eval);
+        Expression_Obj v = map->at(key)->perform(&eval);
 
         if (variables.size() == 1) {
-          List* variable = SASS_MEMORY_NEW(ctx.mem, List, map->pstate(), 2, SASS_SPACE);
-          *variable << k;
-          *variable << v;
-          env->set_local(variables[0], variable);
+          List_Obj variable = SASS_MEMORY_NEW(List, map->pstate(), 2, SASS_SPACE);
+          variable->append(k);
+          variable->append(v);
+          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();
+      // bool arglist = list->is_arglist();
+      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* e = (*list)[i];
+        Expression_Obj e = list->at(i);
         // unwrap value if the expression is an argument
-        if (Argument* arg = dynamic_cast<Argument*>(e)) e = arg->value();
+        if (Argument_Obj arg = SASS_MEMORY_CAST(Argument, e)) e = arg->value();
         // check if we got passed a list of args (investigate)
-        if (List* scalars = dynamic_cast<List*>(e)) {
+        if (List_Obj scalars = SASS_MEMORY_CAST(List, e)) {
           if (variables.size() == 1) {
-            Expression* var = scalars;
-            if (arglist) var = (*scalars)[0];
-            env->set_local(variables[0], var);
+            List_Obj var = scalars;
+            // if (arglist) var = (*scalars)[0];
+            env.set_local(variables[0], &var);
           } else {
             for (size_t j = 0, K = variables.size(); j < K; ++j) {
-              Expression* res = j >= scalars->length()
-                ? SASS_MEMORY_NEW(ctx.mem, Null, expr->pstate())
+              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[0], e);
+            env.set_local(variables.at(0), &e);
             for (size_t j = 1, K = variables.size(); j < K; ++j) {
-              Expression* res = SASS_MEMORY_NEW(ctx.mem, Null, expr->pstate());
-              env->set_local(variables[j], res);
+              Expression_Obj res = SASS_MEMORY_NEW(Null, expr->pstate());
+              env.set_local(variables[j], &res);
             }
           }
         }
         append_block(body);
       }
     }
-    // restore original environment
-    for (size_t j = 0, K = variables.size(); j < K; ++j) {
-      if(!old_vars[j]) env->del_local(variables[j]);
-      else env->set_local(variables[j], old_vars[j]);
-    }
+    call_stack.pop_back();
+    env_stack.pop_back();
     return 0;
   }
 
-  Statement* Expand::operator()(While* w)
+  Statement_Ptr Expand::operator()(While_Ptr w)
   {
-    Expression* pred = w->predicate();
-    Block* body = w->block();
-    while (*pred->perform(&eval)) {
+    Expression_Obj pred = w->predicate();
+    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) {
       append_block(body);
+      cond = pred->perform(&eval);
     }
+    call_stack.pop_back();
+    env_stack.pop_back();
     return 0;
   }
 
-  Statement* Expand::operator()(Return* r)
+  Statement_Ptr Expand::operator()(Return_Ptr r)
   {
     error("@return may only be used within a function", r->pstate(), backtrace());
     return 0;
   }
 
-  Statement* Expand::operator()(Extension* e)
-  {
-    To_String to_string(&ctx);
-    Selector_List* extender = dynamic_cast<Selector_List*>(selector());
-    if (!extender) return 0;
-    selector_stack.push_back(0);
 
-    if (Selector_List* selector_list = dynamic_cast<Selector_List*>(e->selector())) {
-      for (Complex_Selector* complex_selector : selector_list->elements()) {
-        Complex_Selector* tail = complex_selector;
+  void Expand::expand_selector_list(Selector_Obj s, Selector_List_Obj extender) {
+
+    if (Selector_List_Obj sl = SASS_MEMORY_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* header : tail->head()->elements()) {
-            if (dynamic_cast<Parent_Selector*>(header) == NULL) continue; // skip all others
-            To_String to_string(&ctx); std::string sel_str(complex_selector->perform(&to_string));
+          if (tail->head()) for (Simple_Selector_Obj header : tail->head()->elements()) {
+            if (SASS_MEMORY_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());
           }
           tail = tail->tail();
@@ -547,52 +590,82 @@
       }
     }
 
-    Selector_List* contextualized = dynamic_cast<Selector_List*>(e->selector()->perform(&eval));
-    if (contextualized == NULL) return 0;
+
+    Selector_List_Obj contextualized = SASS_MEMORY_CAST_PTR(Selector_List, s->perform(&eval));
+    if (contextualized == false) return;
     for (auto complex_sel : contextualized->elements()) {
-      Complex_Selector* c = complex_sel;
+      Complex_Selector_Obj c = complex_sel;
       if (!c->head() || c->tail()) {
-        To_String to_string(&ctx); std::string sel_str(contextualized->perform(&to_string));
+        std::string sel_str(contextualized->to_string(ctx.c_options));
         error("Can't extend " + sel_str + ": can't extend nested selectors", c->pstate(), backtrace());
       }
-      Compound_Selector* placeholder = c->head();
-      placeholder->is_optional(e->selector()->is_optional());
+      Compound_Selector_Obj placeholder = c->head();
+      if (contextualized->is_optional()) placeholder->is_optional(true);
       for (size_t i = 0, L = extender->length(); i < L; ++i) {
-        Complex_Selector* sel = (*extender)[i];
+        Complex_Selector_Obj sel = (*extender)[i];
         if (!(sel->head() && sel->head()->length() > 0 &&
-            dynamic_cast<Parent_Selector*>((*sel->head())[0])))
+            SASS_MEMORY_CAST(Parent_Selector, (*sel->head())[0])))
         {
-          Compound_Selector* hh = SASS_MEMORY_NEW(ctx.mem, Compound_Selector, (*extender)[i]->pstate());
+          Compound_Selector_Obj hh = SASS_MEMORY_NEW(Compound_Selector, (*extender)[i]->pstate());
           hh->media_block((*extender)[i]->media_block());
-          Complex_Selector* ssel = SASS_MEMORY_NEW(ctx.mem, Complex_Selector, (*extender)[i]->pstate());
+          Complex_Selector_Obj ssel = SASS_MEMORY_NEW(Complex_Selector, (*extender)[i]->pstate());
           ssel->media_block((*extender)[i]->media_block());
           if (sel->has_line_feed()) ssel->has_line_feed(true);
-          Parent_Selector* ps = SASS_MEMORY_NEW(ctx.mem, Parent_Selector, (*extender)[i]->pstate());
+          Parent_Selector_Obj ps = SASS_MEMORY_NEW(Parent_Selector, (*extender)[i]->pstate());
           ps->media_block((*extender)[i]->media_block());
-          *hh << 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->to_str_vec(), std::make_pair(sel, placeholder));
+        ctx.subset_map.put(placeholder, std::make_pair(sel, placeholder));
       }
     }
 
-    selector_stack.pop_back();
+  }
 
+  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 (schema->has_real_parent_ref()) {
+          sl = eval(&schema);
+        } else {
+          selector_stack.push_back(0);
+          sl = eval(&schema);
+          sl->remove_parent_selectors();
+          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);
+      selector_stack.pop_back();
+    }
     return 0;
   }
 
-  Statement* Expand::operator()(Definition* d)
+  Statement_Ptr Expand::operator()(Definition_Ptr d)
   {
     Env* env = environment();
-    Definition* dd = SASS_MEMORY_NEW(ctx.mem, Definition, *d);
+    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 && (
-      d->name() == "calc"       ||
+      Prelexer::calc_fn_call(d->name().c_str()) ||
       d->name() == "element"    ||
       d->name() == "expression" ||
       d->name() == "url"
@@ -604,86 +677,113 @@
       );
     }
 
-
     // set the static link so we can have lexical scoping
     dd->environment(env);
     return 0;
   }
 
-  Statement* Expand::operator()(Mixin_Call* c)
+  Statement_Ptr Expand::operator()(Mixin_Call_Ptr c)
   {
+
+    if (recursions > maxRecursion) {
+      throw Exception::StackError(*c);
+    }
+
+    recursions ++;
+
     Env* env = environment();
     std::string full_name(c->name() + "[m]");
     if (!env->has(full_name)) {
       error("no mixin named " + c->name(), c->pstate(), backtrace());
     }
-    Definition* def = static_cast<Definition*>((*env)[full_name]);
-    Block* body = def->block();
-    Parameters* params = def->parameters();
+    Definition_Obj def = SASS_MEMORY_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());
     }
-    Arguments* args = static_cast<Arguments*>(c->arguments()
-                                               ->perform(&eval));
+    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);
     Env new_env(def->environment());
     env_stack.push_back(&new_env);
     if (c->block()) {
       // represent mixin content blocks as thunks/closures
-      Definition* thunk = SASS_MEMORY_NEW(ctx.mem, Definition,
+      Definition_Obj thunk = SASS_MEMORY_NEW(Definition,
                                           c->pstate(),
                                           "@content",
-                                          SASS_MEMORY_NEW(ctx.mem, Parameters, c->pstate()),
+                                          SASS_MEMORY_NEW(Parameters, c->pstate()),
                                           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);
-    append_block(body);
-    backtrace_stack.pop_back();
+
+    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);
+    for (auto bb : body->elements()) {
+      Statement_Obj ith = bb->perform(this);
+      if (ith) trace->block()->append(ith);
+    }
+    block_stack.pop_back();
+
     env_stack.pop_back();
-    return 0;
+    backtrace_stack.pop_back();
+
+    recursions --;
+    return trace.detach();
   }
 
-  Statement* Expand::operator()(Content* c)
+  Statement_Ptr Expand::operator()(Content_Ptr c)
   {
     Env* env = environment();
     // convert @content directives into mixin calls to the underlying thunk
     if (!env->has("@content[m]")) return 0;
+
     if (block_stack.back()->is_root()) {
       selector_stack.push_back(0);
     }
-    Mixin_Call* call = SASS_MEMORY_NEW(ctx.mem, Mixin_Call,
+
+    Mixin_Call_Obj call = SASS_MEMORY_NEW(Mixin_Call,
                                        c->pstate(),
                                        "@content",
-                                       SASS_MEMORY_NEW(ctx.mem, Arguments, c->pstate()));
-    Statement* stm = call->perform(this);
+                                       SASS_MEMORY_NEW(Arguments, c->pstate()));
+
+    Trace_Obj trace = SASS_MEMORY_CAST_PTR(Trace, call->perform(this));
+
     if (block_stack.back()->is_root()) {
       selector_stack.pop_back();
     }
-    return stm;
+
+    return trace.detach();
   }
 
   // produce an error if something is not implemented
-  inline Statement* Expand::fallback_impl(AST_Node* n)
+  inline Statement_Ptr Expand::fallback_impl(AST_Node_Ptr n)
   {
     std::string err =std:: string("`Expand` doesn't handle ") + typeid(*n).name();
-    String_Quoted* msg = SASS_MEMORY_NEW(ctx.mem, String_Quoted, ParserState("[WARN]"), err);
+    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(ctx.mem, Warning, ParserState("[WARN]"), msg);
+    return SASS_MEMORY_NEW(Warning, ParserState("[WARN]"), &msg);
   }
 
   // process and add to last block on stack
-  inline void Expand::append_block(Block* b)
+  inline void Expand::append_block(Block_Ptr b)
   {
+    if (b->is_root()) call_stack.push_back(b);
     for (size_t i = 0, L = b->length(); i < L; ++i) {
-      Statement* ith = (*b)[i]->perform(this);
-      if (ith) *block_stack.back() << ith;
+      Statement_Ptr stm = &b->at(i);
+      Statement_Obj ith = stm->perform(this);
+      if (ith) block_stack.back()->append(ith);
     }
+    if (b->is_root()) call_stack.pop_back();
   }
 
 }
diff --git a/libsass/src/expand.hpp b/libsass/src/expand.hpp
--- a/libsass/src/expand.hpp
+++ b/libsass/src/expand.hpp
@@ -13,65 +13,69 @@
   class Listize;
   class Context;
   class Eval;
-  typedef Environment<AST_Node*> Env;
+  typedef Environment<AST_Node_Obj> Env;
   struct Backtrace;
 
-  class Expand : public Operation_CRTP<Statement*, Expand> {
+  class Expand : public Operation_CRTP<Statement_Ptr, Expand> {
   public:
 
     Env* environment();
     Context& context();
-    Selector_List* selector();
+    Selector_List_Obj selector();
     Backtrace* backtrace();
 
     Context&          ctx;
     Eval              eval;
+    size_t            recursions;
+    bool              in_keyframes;
+    bool              at_root_without_rule;
+    bool              old_at_root_without_rule;
 
     // it's easier to work with vectors
-    std::vector<Env*>      env_stack;
-    std::vector<Block*>    block_stack;
-    std::vector<String*>   property_stack;
-    std::vector<Selector_List*> selector_stack;
-    std::vector<Backtrace*>backtrace_stack;
-    bool              in_keyframes;
+    std::vector<Env*>              env_stack;
+    std::vector<Block_Ptr>         block_stack;
+    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;
 
-    Statement* fallback_impl(AST_Node* n);
+    Statement_Ptr fallback_impl(AST_Node_Ptr n);
 
-  public:
-    Expand(Context&, Env*, Backtrace*);
-    virtual ~Expand() { }
+  private:
+    void expand_selector_list(Selector_Obj, Selector_List_Obj extender);
 
-    using Operation<Statement*>::operator();
+  public:
+    Expand(Context&, Env*, Backtrace*, std::vector<Selector_List_Obj>* stack = NULL);
+    ~Expand() { }
 
-    Statement* operator()(Block*);
-    Statement* operator()(Ruleset*);
-    Statement* operator()(Propset*);
-    Statement* operator()(Media_Block*);
-    Statement* operator()(Supports_Block*);
-    Statement* operator()(At_Root_Block*);
-    Statement* operator()(At_Rule*);
-    Statement* operator()(Declaration*);
-    Statement* operator()(Assignment*);
-    Statement* operator()(Import*);
-    Statement* operator()(Import_Stub*);
-    Statement* operator()(Warning*);
-    Statement* operator()(Error*);
-    Statement* operator()(Debug*);
-    Statement* operator()(Comment*);
-    Statement* operator()(If*);
-    Statement* operator()(For*);
-    Statement* operator()(Each*);
-    Statement* operator()(While*);
-    Statement* operator()(Return*);
-    Statement* operator()(Extension*);
-    Statement* operator()(Definition*);
-    Statement* operator()(Mixin_Call*);
-    Statement* operator()(Content*);
+    Block_Ptr operator()(Block_Ptr);
+    Statement_Ptr operator()(Ruleset_Ptr);
+    Statement_Ptr operator()(Media_Block_Ptr);
+    Statement_Ptr operator()(Supports_Block_Ptr);
+    Statement_Ptr operator()(At_Root_Block_Ptr);
+    Statement_Ptr operator()(Directive_Ptr);
+    Statement_Ptr operator()(Declaration_Ptr);
+    Statement_Ptr operator()(Assignment_Ptr);
+    Statement_Ptr operator()(Import_Ptr);
+    Statement_Ptr operator()(Import_Stub_Ptr);
+    Statement_Ptr operator()(Warning_Ptr);
+    Statement_Ptr operator()(Error_Ptr);
+    Statement_Ptr operator()(Debug_Ptr);
+    Statement_Ptr operator()(Comment_Ptr);
+    Statement_Ptr operator()(If_Ptr);
+    Statement_Ptr operator()(For_Ptr);
+    Statement_Ptr operator()(Each_Ptr);
+    Statement_Ptr operator()(While_Ptr);
+    Statement_Ptr operator()(Return_Ptr);
+    Statement_Ptr operator()(Extension_Ptr);
+    Statement_Ptr operator()(Definition_Ptr);
+    Statement_Ptr operator()(Mixin_Call_Ptr);
+    Statement_Ptr operator()(Content_Ptr);
 
     template <typename U>
-    Statement* fallback(U x) { return fallback_impl(x); }
+    Statement_Ptr fallback(U x) { return fallback_impl(x); }
 
-    void append_block(Block*);
+    void append_block(Block_Ptr);
   };
 
 }
diff --git a/libsass/src/extend.cpp b/libsass/src/extend.cpp
--- a/libsass/src/extend.cpp
+++ b/libsass/src/extend.cpp
@@ -1,21 +1,17 @@
-#ifdef _MSC_VER
-#pragma warning(disable : 4503)
-#endif
-
+#include "sass.hpp"
 #include "extend.hpp"
 #include "context.hpp"
-#include "to_string.hpp"
 #include "backtrace.hpp"
 #include "paths.hpp"
 #include "parser.hpp"
 #include "node.hpp"
 #include "sass_util.hpp"
+#include "remove_placeholders.hpp"
 #include "debug.hpp"
 #include <iostream>
 #include <deque>
 #include <set>
 
-
 /*
  NOTES:
 
@@ -65,7 +61,7 @@
 namespace Sass {
 
 
-  typedef std::pair<Complex_Selector*, Compound_Selector*> ExtensionPair;
+  typedef std::pair<Complex_Selector_Obj, Compound_Selector_Obj> ExtensionPair;
   typedef std::vector<ExtensionPair> SubsetMapEntries;
 
 #ifdef DEBUG
@@ -77,7 +73,7 @@
       case Complex_Selector::PARENT_OF:   os << "\">\""; break;
       case Complex_Selector::PRECEDES:    os << "\"~\""; break;
       case Complex_Selector::ADJACENT_TO: os << "\"+\""; break;
-      case Complex_Selector::REFERENCE: os    << "\"/\""; break;
+      case Complex_Selector::REFERENCE:   os << "\"/\""; break;
     }
 
     return os;
@@ -85,23 +81,20 @@
 
 
   std::ostream& operator<<(std::ostream& os, Compound_Selector& compoundSelector) {
-    To_String to_string;
     for (size_t i = 0, L = compoundSelector.length(); i < L; ++i) {
       if (i > 0) os << ", ";
-      os << compoundSelector[i]->perform(&to_string);
+      os << compoundSelector[i]->to_string();
     }
     return os;
   }
 
   std::ostream& operator<<(std::ostream& os, Simple_Selector& simpleSelector) {
-    To_String to_string;
-    os << simpleSelector.perform(&to_string);
+    os << simpleSelector.to_string();
     return os;
   }
 
   // Print a string representation of a Compound_Selector
   static void printSimpleSelector(Simple_Selector* pSimpleSelector, const char* message=NULL, bool newline=true) {
-    To_String to_string;
 
     if (message) {
       std::cerr << message;
@@ -119,13 +112,12 @@
   }
 
   // Print a string representation of a Compound_Selector
-    typedef std::pair<Compound_Selector*, Complex_Selector*> SelsNewSeqPair;
+    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* pCompoundSelector, const char* message=NULL, bool newline=true) {
-    To_String to_string;
+  static void printCompoundSelector(Compound_Selector_Ptr pCompoundSelector, const char* message=NULL, bool newline=true) {
 
     if (message) {
       std::cerr << message;
@@ -144,10 +136,9 @@
 
 
   std::ostream& operator<<(std::ostream& os, Complex_Selector& complexSelector) {
-    To_String to_string;
 
     os << "[";
-    Complex_Selector* pIter = &complexSelector;
+    Complex_Selector_Ptr pIter = &complexSelector;
     bool first = true;
     while (pIter) {
       if (pIter->combinator() != Complex_Selector::ANCESTOR_OF) {
@@ -164,7 +155,7 @@
       first = false;
 
       if (pIter->head()) {
-        os << pIter->head()->perform(&to_string);
+        os << pIter->head()->to_string();
       } else {
         os << "NULL_HEAD";
       }
@@ -178,8 +169,7 @@
 
 
   // Print a string representation of a Complex_Selector
-  static void printComplexSelector(Complex_Selector* pComplexSelector, const char* message=NULL, bool newline=true) {
-    To_String to_string;
+  static void printComplexSelector(Complex_Selector_Ptr pComplexSelector, const char* message=NULL, bool newline=true) {
 
     if (message) {
       std::cerr << message;
@@ -197,7 +187,6 @@
   }
 
   static void printSelsNewSeqPairCollection(SelsNewSeqPairCollection& collection, const char* message=NULL, bool newline=true) {
-    To_String to_string;
 
     if (message) {
       std::cerr << message;
@@ -211,8 +200,8 @@
         std::cerr << ", ";
       }
       std::cerr << "[";
-      Compound_Selector* pSels = pair.first;
-      Complex_Selector* pNewSelector = pair.second;
+      Compound_Selector_Ptr pSels = pair.first;
+      Complex_Selector_Ptr pNewSelector = pair.second;
       std::cerr << "[" << *pSels << "], ";
       printComplexSelector(pNewSelector, NULL, false);
     }
@@ -225,7 +214,6 @@
 
   // Print a string representation of a SourcesSet
   static void printSourcesSet(SourcesSet& sources, Context& ctx, const char* message=NULL, bool newline=true) {
-    To_String to_string;
 
     if (message) {
       std::cerr << message;
@@ -236,7 +224,7 @@
     typedef std::deque<std::string> SourceStrings;
     SourceStrings sourceStrings;
     for (SourcesSet::iterator iterator = sources.begin(), iteratorEnd = sources.end(); iterator != iteratorEnd; ++iterator) {
-      Complex_Selector* pSource = *iterator;
+      Complex_Selector_Ptr pSource = *iterator;
       std::stringstream sstream;
       sstream << complexSelectorToNode(pSource, ctx);
       sourceStrings.push_back(sstream.str());
@@ -265,8 +253,8 @@
     os << "SUBSET_MAP_ENTRIES[";
 
     for (SubsetMapEntries::iterator iterator = entries.begin(), endIterator = entries.end(); iterator != endIterator; ++iterator) {
-      Complex_Selector* pExtComplexSelector = iterator->first;    // The selector up to where the @extend is (ie, the thing to merge)
-      Compound_Selector* pExtCompoundSelector = iterator->second; // The stuff after the @extend
+      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
 
       if (iterator != entries.begin()) {
         os << ", ";
@@ -298,14 +286,14 @@
   }
 #endif
 
-  static bool parentSuperselector(Complex_Selector* pOne, Complex_Selector* pTwo, Context& ctx) {
+  static bool parentSuperselector(Complex_Selector_Ptr pOne, Complex_Selector_Ptr pTwo, Context& ctx) {
     // 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);
-    Type_Selector fakeParent(ParserState("[FAKE]"), "temp");
-    Compound_Selector fakeHead(ParserState("[FAKE]"), 1 /*size*/);
-    fakeHead.elements().push_back(&fakeParent);
-    Complex_Selector fakeParentContainer(ParserState("[FAKE]"), Complex_Selector::ANCESTOR_OF, &fakeHead /*head*/, NULL /*tail*/);
+    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*/);
 
     pOne->set_innermost(&fakeParentContainer, Complex_Selector::ANCESTOR_OF);
     pTwo->set_innermost(&fakeParentContainer, Complex_Selector::ANCESTOR_OF);
@@ -329,8 +317,8 @@
     Node result = Node::createCollection();
 
     for (ComplexSelectorDeque::const_iterator iter = deque.begin(), iterEnd = deque.end(); iter != iterEnd; iter++) {
-      Complex_Selector* pChild = *iter;
-      result.collection()->push_back(complexSelectorToNode(pChild, ctx));
+      Complex_Selector_Obj pChild = *iter;
+      result.collection()->push_back(complexSelectorToNode(&pChild, ctx));
     }
 
     return result;
@@ -342,7 +330,7 @@
 
     Context& mCtx;
 
-    bool operator()(Complex_Selector* pOne, Complex_Selector* pTwo, Complex_Selector*& pOut) const {
+    bool operator()(Complex_Selector_Obj pOne, Complex_Selector_Obj pTwo, Complex_Selector_Obj& pOut) const {
       /*
       This code is based on the following block from ruby sass' subweave
         do |s1, s2|
@@ -362,12 +350,12 @@
         return false;
       }
 
-      if (parentSuperselector(pOne, pTwo, mCtx)) {
+      if (parentSuperselector(&pOne, &pTwo, mCtx)) {
         pOut = pTwo;
         return true;
       }
 
-      if (parentSuperselector(pTwo, pOne, mCtx)) {
+      if (parentSuperselector(&pTwo, &pOne, mCtx)) {
         pOut = pOne;
         return true;
       }
@@ -393,7 +381,7 @@
     }
 
 
-    Complex_Selector* pCompareOut = NULL;
+    Complex_Selector_Obj pCompareOut;
     if (comparator(x[i], y[j], pCompareOut)) {
       DEBUG_PRINTLN(LCS, "RETURNING AFTER ELEM COMPARE")
       lcs_backtrace(c, x, y, i - 1, j - 1, comparator, out);
@@ -430,9 +418,9 @@
 
     for (size_t i = 1; i < x.size(); i++) {
       for (size_t j = 1; j < y.size(); j++) {
-        Complex_Selector* pCompareOut = NULL;
+        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]);
@@ -570,7 +558,7 @@
       for (NodeDeque::iterator seqs1Iter = seqs1.collection()->begin(), seqs1EndIter = seqs1.collection()->end(); seqs1Iter != seqs1EndIter; ++seqs1Iter) {
         Node& seq1 = *seqs1Iter;
 
-        Complex_Selector* pSeq1 = nodeToComplexSelector(seq1, ctx);
+        Complex_Selector_Obj pSeq1 = nodeToComplexSelector(seq1, ctx);
 
         // 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.
@@ -587,7 +575,7 @@
         DEBUG_EXEC(TRIM, printSourcesSet(sources, ctx, "TRIM SOURCES: "))
 
         for (SourcesSet::iterator sourcesSetIterator = sources.begin(), sourcesSetIteratorEnd = sources.end(); sourcesSetIterator != sourcesSetIteratorEnd; ++sourcesSetIterator) {
-          const Complex_Selector* const pCurrentSelector = *sourcesSetIterator;
+          const Complex_Selector_Obj& pCurrentSelector = *sourcesSetIterator;
           maxSpecificity = std::max(maxSpecificity, pCurrentSelector->specificity());
         }
 
@@ -617,7 +605,7 @@
           for (NodeDeque::iterator seqs2Iter = seqs2.collection()->begin(), seqs2IterEnd = seqs2.collection()->end(); seqs2Iter != seqs2IterEnd; ++seqs2Iter) {
             Node& seq2 = *seqs2Iter;
 
-            Complex_Selector* pSeq2 = nodeToComplexSelector(seq2, ctx);
+            Complex_Selector_Obj pSeq2 = nodeToComplexSelector(seq2, ctx);
 
             DEBUG_PRINTLN(TRIM, "SEQ2 SPEC: " << pSeq2->specificity())
             DEBUG_PRINTLN(TRIM, "IS SPEC: " << pSeq2->specificity() << " >= " << maxSpecificity << " " << (pSeq2->specificity() >= maxSpecificity ? "true" : "false"))
@@ -665,14 +653,14 @@
     // 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);
-    Type_Selector fakeParent(ParserState("[FAKE]"), "temp");
-    Compound_Selector fakeHead(ParserState("[FAKE]"), 1 /*size*/);
-    fakeHead.elements().push_back(&fakeParent);
-    Complex_Selector fakeParentContainer(ParserState("[FAKE]"), Complex_Selector::ANCESTOR_OF, &fakeHead /*head*/, NULL /*tail*/);
+    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*/);
 
-    Complex_Selector* pOneWithFakeParent = nodeToComplexSelector(one, ctx);
+    Complex_Selector_Obj pOneWithFakeParent = nodeToComplexSelector(one, ctx);
     pOneWithFakeParent->set_innermost(&fakeParentContainer, Complex_Selector::ANCESTOR_OF);
-    Complex_Selector* pTwoWithFakeParent = nodeToComplexSelector(two, ctx);
+    Complex_Selector_Obj pTwoWithFakeParent = nodeToComplexSelector(two, ctx);
     pTwoWithFakeParent->set_innermost(&fakeParentContainer, Complex_Selector::ANCESTOR_OF);
 
     return pOneWithFakeParent->is_superselector_of(pTwoWithFakeParent);
@@ -860,7 +848,7 @@
     DefaultLcsComparator lcsDefaultComparator;
     Node opsLcs = lcs(ops1, ops2, lcsDefaultComparator, ctx);
 
-    if (!(opsLcs == ops1 || opsLcs == ops2)) {
+    if (!(nodesEqual(opsLcs, ops1, true) || nodesEqual(opsLcs, ops2, true))) {
       return Node::createNil();
     }
 
@@ -957,7 +945,7 @@
 
       // If there are multiple operators, something hacky's going on. If one is a supersequence of the other, use that, otherwise give up.
 
-      if (!(opsLcs == ops1 || opsLcs == ops2)) {
+      if (!(nodesEqual(opsLcs, ops1, true) || nodesEqual(opsLcs, ops2, true))) {
         return Node::createNil();
       }
 
@@ -998,9 +986,9 @@
           DEBUG_PRINTLN(ALL, "sel1: " << sel1)
           DEBUG_PRINTLN(ALL, "sel2: " << sel2)
 
-          Complex_Selector* pMergedWrapper = sel1.selector()->clone(ctx); // Clone the Complex_Selector to get back to something we can transform to a node once we replace the head with the unification result
+          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* pMerged = sel1.selector()->head()->unify_with(sel2.selector()->head(), ctx);
+          Compound_Selector_Ptr pMerged = sel1.selector()->head()->unify_with(&sel2.selector()->head(), ctx);
           pMergedWrapper->head(pMerged);
 
           DEBUG_EXEC(ALL, printCompoundSelector(pMerged, "MERGED: "))
@@ -1023,7 +1011,7 @@
 
           if (pMerged) {
             Node mergedPerm = Node::createCollection();
-            mergedPerm.collection()->push_back(Node::createSelector(pMergedWrapper, ctx));
+            mergedPerm.collection()->push_back(Node::createSelector(&pMergedWrapper, ctx));
             mergedPerm.collection()->push_back(Node::createCombinator(Complex_Selector::PRECEDES));
             newRes.collection()->push_back(mergedPerm);
           }
@@ -1057,9 +1045,9 @@
             DEBUG_PRINTLN(ALL, "PLUS SEL: " << plusSel)
             DEBUG_PRINTLN(ALL, "TILDE SEL: " << tildeSel)
 
-            Complex_Selector* pMergedWrapper = plusSel.selector()->clone(ctx); // Clone the Complex_Selector to get back to something we can transform to a node once we replace the head with the unification result
+            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* pMerged = plusSel.selector()->head()->unify_with(tildeSel.selector()->head(), ctx);
+            Compound_Selector_Ptr pMerged = plusSel.selector()->head()->unify_with(&tildeSel.selector()->head(), ctx);
             pMergedWrapper->head(pMerged);
 
             DEBUG_EXEC(ALL, printCompoundSelector(pMerged, "MERGED: "))
@@ -1075,7 +1063,7 @@
 
             if (pMerged) {
               Node mergedPerm = Node::createCollection();
-              mergedPerm.collection()->push_back(Node::createSelector(pMergedWrapper, ctx));
+              mergedPerm.collection()->push_back(Node::createSelector(&pMergedWrapper, ctx));
               mergedPerm.collection()->push_back(Node::createCombinator(Complex_Selector::ADJACENT_TO));
               newRes.collection()->push_back(mergedPerm);
             }
@@ -1106,9 +1094,9 @@
         DEBUG_PRINTLN(ALL, "sel1: " << sel1)
         DEBUG_PRINTLN(ALL, "sel2: " << sel2)
 
-        Complex_Selector* pMergedWrapper = sel1.selector()->clone(ctx); // Clone the Complex_Selector to get back to something we can transform to a node once we replace the head with the unification result
+        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* pMerged = sel1.selector()->head()->unify_with(sel2.selector()->head(), ctx);
+        Compound_Selector_Ptr pMerged = sel1.selector()->head()->unify_with(&sel2.selector()->head(), ctx);
         pMergedWrapper->head(pMerged);
 
         DEBUG_EXEC(ALL, printCompoundSelector(pMerged, "MERGED: "))
@@ -1118,7 +1106,7 @@
         }
 
         res.collection()->push_front(op1);
-        res.collection()->push_front(Node::createSelector(pMergedWrapper, ctx));
+        res.collection()->push_front(Node::createSelector(&pMergedWrapper, ctx));
 
         DEBUG_PRINTLN(ALL, "RESULT: " << res)
 
@@ -1365,20 +1353,20 @@
 
     // Check for the simple cases
     if (one.isNil()) {
-      out.collection()->push_back(two.clone(ctx));
+      out.collection()->push_back(two.klone(ctx));
     } else if (two.isNil()) {
-      out.collection()->push_back(one.clone(ctx));
+      out.collection()->push_back(one.klone(ctx));
     } 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.clone(ctx);
-      Node twoCloned = two.clone(ctx);
+      Node firstPerm = one.klone(ctx);
+      Node twoCloned = two.klone(ctx);
       firstPerm.plus(twoCloned);
       out.collection()->push_back(firstPerm);
 
-      Node secondPerm = two.clone(ctx);
-      Node oneCloned = one.clone(ctx);
+      Node secondPerm = two.klone(ctx);
+      Node oneCloned = one.klone(ctx);
       secondPerm.plus(oneCloned );
       out.collection()->push_back(secondPerm);
     }
@@ -1472,9 +1460,10 @@
     afters.plus(path);
 
     while (!afters.collection()->empty()) {
-      Node current = afters.collection()->front().clone(ctx);
+      Node current = afters.collection()->front().klone(ctx);
       afters.collection()->pop_front();
       DEBUG_PRINTLN(WEAVE, "CURRENT: " << current)
+      if (current.collection()->size() == 0) continue;
 
       Node last_current = Node::createCollection();
       last_current.collection()->push_back(current.collection()->back());
@@ -1519,9 +1508,9 @@
   // This forward declaration is needed since extendComplexSelector calls extendCompoundSelector, which may recursively
   // call extendComplexSelector again.
   static Node extendComplexSelector(
-    Complex_Selector* pComplexSelector,
+    Complex_Selector_Ptr pComplexSelector,
     Context& ctx,
-    ExtensionSubsetMap& subset_map,
+    Subset_Map& subset_map,
     std::set<Compound_Selector> seen, bool isReplace, bool isOriginal);
 
 
@@ -1542,14 +1531,14 @@
   class GroupByToAFunctor {
   public:
     KeyType operator()(ExtensionPair& extPair) const {
-      Complex_Selector* pSelector = extPair.first;
-      return *pSelector;
+      Complex_Selector_Obj pSelector = extPair.first;
+      return &pSelector;
     }
   };
   static Node extendCompoundSelector(
-    Compound_Selector* pSelector,
+    Compound_Selector_Ptr pSelector,
     Context& ctx,
-    ExtensionSubsetMap& subset_map,
+    Subset_Map& subset_map,
     std::set<Compound_Selector> seen, bool isReplace) {
 
     DEBUG_EXEC(EXTEND_COMPOUND, printCompoundSelector(pSelector, "EXTEND COMPOUND: "))
@@ -1558,17 +1547,15 @@
     Node extendedSelectors = Node::createCollection();
     // extendedSelectors.got_line_feed = true;
 
-    To_String to_string;
-
-    SubsetMapEntries entries = subset_map.get_v(pSelector->to_str_vec());
+    SubsetMapEntries entries = subset_map.get_v(pSelector);
 
-    typedef std::vector<std::pair<Complex_Selector, std::vector<ExtensionPair> > > GroupedByToAResult;
+    typedef std::vector<std::pair<Complex_Selector_Obj, std::vector<ExtensionPair> > > GroupedByToAResult;
 
-    GroupByToAFunctor<Complex_Selector> extPairKeyFunctor;
+    GroupByToAFunctor<Complex_Selector_Obj> extPairKeyFunctor;
     GroupedByToAResult arr;
     group_by_to_a(entries, extPairKeyFunctor, arr);
 
-    typedef std::pair<Compound_Selector*, Complex_Selector*> SelsNewSeqPair;
+    typedef std::pair<Compound_Selector_Obj, Complex_Selector_Obj> SelsNewSeqPair;
     typedef std::vector<SelsNewSeqPair> SelsNewSeqPairCollection;
 
 
@@ -1576,45 +1563,42 @@
 
 
     for (GroupedByToAResult::iterator groupedIter = arr.begin(), groupedIterEnd = arr.end(); groupedIter != groupedIterEnd; groupedIter++) {
-      std::pair<Complex_Selector, std::vector<ExtensionPair> >& groupedPair = *groupedIter;
+      std::pair<Complex_Selector_Obj, std::vector<ExtensionPair> >& groupedPair = *groupedIter;
 
-      Complex_Selector& seq = groupedPair.first;
+      Complex_Selector_Obj seq = groupedPair.first;
       std::vector<ExtensionPair>& group = groupedPair.second;
 
       DEBUG_EXEC(EXTEND_COMPOUND, printComplexSelector(&seq, "SEQ: "))
 
-
-      Compound_Selector* pSels = SASS_MEMORY_NEW(ctx.mem, Compound_Selector, pSelector->pstate());
+// 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* pCompound = pair.second;
+        Compound_Selector_Obj pCompound = pair.second;
         for (size_t index = 0; index < pCompound->length(); index++) {
-          Simple_Selector* pSimpleSelector = (*pCompound)[index];
-          (*pSels) << pSimpleSelector;
+          Simple_Selector_Obj pSimpleSelector = (*pCompound)[index];
+          pSels->append(&pSimpleSelector);
+          pCompound->extended(true);
         }
       }
 
-      DEBUG_EXEC(EXTEND_COMPOUND, printCompoundSelector(pSels, "SELS: "))
+      DEBUG_EXEC(EXTEND_COMPOUND, printCompoundSelector(&pSels, "SELS: "))
 
-      Complex_Selector* pExtComplexSelector = &seq;    // The selector up to where the @extend is (ie, the thing to merge)
-      Compound_Selector* pExtCompoundSelector = pSels; // All the simple selectors to be replaced from the current compound selector from all extensions
+      Complex_Selector_Ptr pExtComplexSelector = &seq;    // The selector up to where the @extend is (ie, the thing to merge)
 
       // 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* pSelectorWithoutExtendSelectors = pSelector->minus(pExtCompoundSelector, ctx);
+      Compound_Selector_Obj pSelectorWithoutExtendSelectors = pSelector->minus(&pSels, ctx);
 
       DEBUG_EXEC(EXTEND_COMPOUND, printCompoundSelector(pSelector, "MEMBERS: "))
       DEBUG_EXEC(EXTEND_COMPOUND, printCompoundSelector(pSelectorWithoutExtendSelectors, "SELF_WO_SEL: "))
 
-      Compound_Selector* pInnermostCompoundSelector = pExtComplexSelector->last()->head();
-      Compound_Selector* pUnifiedSelector = NULL;
+      Compound_Selector_Obj pInnermostCompoundSelector = pExtComplexSelector->last()->head();
 
       if (!pInnermostCompoundSelector) {
-        pInnermostCompoundSelector = SASS_MEMORY_NEW(ctx.mem, Compound_Selector, pSelector->pstate());
+        pInnermostCompoundSelector = SASS_MEMORY_NEW(Compound_Selector, pSelector->pstate());
       }
-
-      pUnifiedSelector = pInnermostCompoundSelector->unify_with(pSelectorWithoutExtendSelectors, ctx);
-
+      Compound_Selector_Obj pUnifiedSelector = pInnermostCompoundSelector->unify_with(&pSelectorWithoutExtendSelectors, ctx);
 
       DEBUG_EXEC(EXTEND_COMPOUND, printCompoundSelector(pInnermostCompoundSelector, "LHS: "))
       DEBUG_EXEC(EXTEND_COMPOUND, printCompoundSelector(pSelectorWithoutExtendSelectors, "RHS: "))
@@ -1632,22 +1616,22 @@
       // get rid of the last Compound_Selector and replace it with this one. I think the reason this code is more
       // complex is that Complex_Selector contains a combinator, but in ruby combinators have already been filtered
       // out and aren't operated on.
-      Complex_Selector* pNewSelector = pExtComplexSelector->cloneFully(ctx); // ->first();
+      Complex_Selector_Obj pNewSelector = SASS_MEMORY_CLONE(pExtComplexSelector); // ->first();
 
-      Complex_Selector* pNewInnerMost = SASS_MEMORY_NEW(ctx.mem, Complex_Selector, pSelector->pstate(), Complex_Selector::ANCESTOR_OF, pUnifiedSelector, NULL);
+      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;
       debugSet = pNewSelector->sources();
       if (debugSet.size() > 0) {
-        throw "The new selector should start with no sources. Something needs to be cloned to fix this.";
+        throw std::runtime_error("The new selector should start with no sources. Something needs to be cloned to fix this.");
       }
       debugSet = pExtComplexSelector->sources();
       if (debugSet.size() > 0) {
-        throw "The extension selector from our subset map should not have sources. These will bleed to the new selector. Something needs to be cloned to fix this.";
+        throw std::runtime_error("The extension selector from our subset map should not have sources. These will bleed to the new selector. Something needs to be cloned to fix this.");
       }
 #endif
 
@@ -1671,7 +1655,7 @@
       DEBUG_EXEC(EXTEND_COMPOUND, printSourcesSet(pSelector->sources(), ctx, "SOURCES THIS EXTEND WHICH SHOULD BE SAME STILL: "))
 
 
-      if (pSels->has_line_feed()) pNewSelector->has_line_feed(true);;
+      if (pSels->has_line_feed()) pNewSelector->has_line_feed(true);
 
       holder.push_back(std::make_pair(pSels, pNewSelector));
     }
@@ -1680,8 +1664,8 @@
     for (SelsNewSeqPairCollection::iterator holderIter = holder.begin(), holderIterEnd = holder.end(); holderIter != holderIterEnd; holderIter++) {
       SelsNewSeqPair& pair = *holderIter;
 
-      Compound_Selector* pSels = pair.first;
-      Complex_Selector* pNewSelector = pair.second;
+      Compound_Selector_Obj pSels = pair.first;
+      Complex_Selector_Obj pNewSelector = pair.second;
 
 
       // RUBY??: next [] if seen.include?(sels)
@@ -1695,13 +1679,13 @@
 
 
       DEBUG_PRINTLN(EXTEND_COMPOUND, "RECURSING DO EXTEND: " << complexSelectorToNode(pNewSelector, ctx))
-      Node recurseExtendedSelectors = extendComplexSelector(pNewSelector, ctx, subset_map, recurseSeen, isReplace, false); // !:isOriginal
+      Node recurseExtendedSelectors = extendComplexSelector(&pNewSelector, ctx, subset_map, recurseSeen, isReplace, false); // !:isOriginal
 
       DEBUG_PRINTLN(EXTEND_COMPOUND, "RECURSING DO EXTEND RETURN: " << recurseExtendedSelectors)
 
       for (NodeDeque::iterator iterator = recurseExtendedSelectors.collection()->begin(), endIterator = recurseExtendedSelectors.collection()->end();
            iterator != endIterator; ++iterator) {
-        Node& newSelector = *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*/));
@@ -1720,30 +1704,30 @@
 
 
   static bool complexSelectorHasExtension(
-    Complex_Selector* pComplexSelector,
+    Complex_Selector_Ptr pComplexSelector,
     Context& ctx,
-    ExtensionSubsetMap& subset_map) {
+    Subset_Map& subset_map,
+    std::set<Compound_Selector>& seen) {
 
     bool hasExtension = false;
 
-    Complex_Selector* pIter = pComplexSelector;
+    Complex_Selector_Obj pIter = pComplexSelector;
 
     while (!hasExtension && pIter) {
-      Compound_Selector* pHead = pIter->head();
+      Compound_Selector_Obj pHead = pIter->head();
 
       if (pHead) {
-        SubsetMapEntries entries = subset_map.get_v(pHead->to_str_vec());
+        SubsetMapEntries entries = subset_map.get_v(pHead);
         for (ExtensionPair ext : entries) {
           // check if both selectors have the same media block parent
-          if (ext.first->media_block() == pComplexSelector->media_block()) continue;
-          To_String to_string(&ctx);
+          // if (ext.first->media_block() == pComplexSelector->media_block()) continue;
           if (ext.second->media_block() == 0) continue;
-          if (pComplexSelector->media_block() &&
+          if (pHead->media_block() &&
               ext.second->media_block()->media_queries() &&
-              pComplexSelector->media_block()->media_queries()
+              pHead->media_block()->media_queries()
           ) {
-            std::string query_left(ext.second->media_block()->media_queries()->perform(&to_string));
-            std::string query_right(pComplexSelector->media_block()->media_queries()->perform(&to_string));
+            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));
             if (query_left == query_right) continue;
           }
 
@@ -1754,7 +1738,7 @@
           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->perform(&to_string) << "\"";
+          err << "From \"@extend " << ext.second->to_string(ctx.c_options) << "\"";
           err << " on line " << pstate.line+1 << " of " << rel_path << "\n";
           error(err.str(), pComplexSelector->pstate());
         }
@@ -1764,29 +1748,6 @@
       pIter = pIter->tail();
     }
 
-    if (!hasExtension) {
-      /* ToDo: don't break stuff
-      std::stringstream err;
-      To_String to_string(&ctx);
-      std::string cwd(Sass::File::get_cwd());
-      std::string sel1(pComplexSelector->perform(&to_string));
-      Compound_Selector* pExtendSelector = 0;
-      for (auto i : subset_map.values()) {
-        if (i.first == pComplexSelector) {
-          pExtendSelector = i.second;
-          break;
-        }
-      }
-      if (!pExtendSelector || !pExtendSelector->is_optional()) {
-        std::string sel2(pExtendSelector ? pExtendSelector->perform(&to_string) : "[unknown]");
-        err << "\"" << sel1 << "\" failed to @extend \"" << sel2 << "\"\n";
-        err << "The selector \"" << sel2 << "\" was not found.\n";
-        err << "Use \"@extend " << sel2 << " !optional\" if the extend should be able to fail.";
-        error(err.str(), pExtendSelector ? pExtendSelector->pstate() : pComplexSelector->pstate());
-      }
-      */
-    }
-
     return hasExtension;
   }
 
@@ -1803,9 +1764,9 @@
      next [[sseq_or_op]] unless sseq_or_op.is_a?(SimpleSequence)
    */
   static Node extendComplexSelector(
-    Complex_Selector* pComplexSelector,
+    Complex_Selector_Ptr pComplexSelector,
     Context& ctx,
-    ExtensionSubsetMap& subset_map,
+    Subset_Map& subset_map,
     std::set<Compound_Selector> seen, bool isReplace, bool isOriginal) {
 
     Node complexSelector = complexSelectorToNode(pComplexSelector, ctx);
@@ -1835,17 +1796,17 @@
         continue;
       }
 
-      Compound_Selector* pCompoundSelector = sseqOrOp.selector()->head();
+      Compound_Selector_Obj pCompoundSelector = sseqOrOp.selector()->head();
 
       // RUBY: extended = sseq_or_op.do_extend(extends, parent_directives, replace, seen)
-      Node extended = extendCompoundSelector(pCompoundSelector, ctx, subset_map, seen, isReplace);
+      Node extended = extendCompoundSelector(&pCompoundSelector, ctx, subset_map, seen, isReplace);
       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* pJustCurrentCompoundSelector = sseqOrOp.selector();
+      Complex_Selector_Obj pJustCurrentCompoundSelector = sseqOrOp.selector();
 
       // RUBY: extended.first.add_sources!([self]) if original && !has_placeholder?
       if (isOriginal && !pComplexSelector->has_placeholder()) {
@@ -1859,7 +1820,7 @@
       for (NodeDeque::iterator iterator = extended.collection()->begin(), endIterator = extended.collection()->end();
            iterator != endIterator; ++iterator) {
         Node& childNode = *iterator;
-        Complex_Selector* pExtensionSelector = nodeToComplexSelector(childNode, ctx);
+        Complex_Selector_Obj pExtensionSelector = nodeToComplexSelector(childNode, ctx);
         if (pExtensionSelector->is_superselector_of(pJustCurrentCompoundSelector)) {
           isSuperselector = true;
           break;
@@ -1868,7 +1829,7 @@
 
       if (!isSuperselector) {
         if (sseqOrOp.got_line_feed) pJustCurrentCompoundSelector->has_line_feed(sseqOrOp.got_line_feed);
-        extended.collection()->push_front(complexSelectorToNode(pJustCurrentCompoundSelector, ctx));
+        extended.collection()->push_front(complexSelectorToNode(&pJustCurrentCompoundSelector, ctx));
       }
 
       DEBUG_PRINTLN(EXTEND_COMPLEX, "CHOICES UNSHIFTED: " << extended)
@@ -1926,35 +1887,40 @@
   /*
    This is the equivalent of ruby's CommaSequence.do_extend.
   */
-  Selector_List* Extend::extendSelectorList(Selector_List* pSelectorList, Context& ctx, ExtensionSubsetMap& subset_map, bool isReplace, bool& extendedSomething) {
+  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);
+  }
 
-    To_String to_string(&ctx);
+  /*
+   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) {
 
-    Selector_List* pNewSelectors = SASS_MEMORY_NEW(ctx.mem, Selector_List, pSelectorList->pstate(), pSelectorList->length());
+    Selector_List_Obj pNewSelectors = SASS_MEMORY_NEW(Selector_List, pSelectorList->pstate(), pSelectorList->length());
 
     extendedSomething = false;
 
     for (size_t index = 0, length = pSelectorList->length(); index < length; index++) {
-      Complex_Selector* pSelector = (*pSelectorList)[index];
+      Complex_Selector_Obj pSelector = (*pSelectorList)[index];
 
       // ruby sass seems to keep a list of things that have extensions and then only extend those. We don't currently do that.
       // Since it's not that expensive to check if an extension exists in the subset map and since it can be relatively expensive to
       // 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)) {
-        *pNewSelectors << pSelector;
+      if (!complexSelectorHasExtension(&pSelector, ctx, subset_map, seen)) {
+        pNewSelectors->append(&pSelector);
         continue;
       }
 
       extendedSomething = true;
 
-      std::set<Compound_Selector> seen;
-
-      Node extendedSelectors = extendComplexSelector(pSelector, ctx, subset_map, seen, isReplace, true);
+      Node extendedSelectors = extendComplexSelector(&pSelector, ctx, subset_map, seen, isReplace, true);
       if (!pSelector->has_placeholder()) {
-        if (!extendedSelectors.contains(complexSelectorToNode(pSelector, ctx), true /*simpleSelectorOrderDependent*/)) {
-          *pNewSelectors << pSelector;
+        if (!extendedSelectors.contains(complexSelectorToNode(&pSelector, ctx), true /*simpleSelectorOrderDependent*/)) {
+          pNewSelectors->append(pSelector);
+          continue;
         }
       }
 
@@ -1963,16 +1929,84 @@
         if(isReplace && iterator == iteratorBegin && extendedSelectors.collection()->size() > 1 ) continue;
 
         Node& childNode = *iterator;
-        *pNewSelectors << nodeToComplexSelector(childNode, ctx);
+        pNewSelectors->append(nodeToComplexSelector(childNode, ctx));
       }
     }
 
-    return pNewSelectors;
+    Remove_Placeholders remove_placeholders(ctx);
+    // 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);
 
+    // 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());
+          // 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)) {
+              ws->selector(SASS_MEMORY_CLONE(ws->selector()));
+              if (Selector_List_Obj sl = SASS_MEMORY_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 {
+                  // extend the inner list of wrapped selector
+                  Selector_List_Obj ext_sl = extendSelectorList(sl, ctx, subset_map, 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);
+                      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;
+                        }
+                        cpy_ws_sl->append(ext_cs->first());
+                      }
+                      // assign list to clone
+                      cpy_ws->selector(&cpy_ws_sl);
+                      // append the clone
+                      cpy_head->append(&cpy_ws);
+                    }
+                  }
+                }
+              } else {
+                cpy_head->append(&hs);
+              }
+            } else {
+              cpy_head->append(&hs);
+            }
+          }
+          // replace header
+          cur->head(cpy_head);
+        }
+        // process tail
+        cur = cur->tail();
+      }
+    }
+    return pNewSelectors.detach();
+
   }
 
 
-  bool shouldExtendBlock(Block* b) {
+  bool shouldExtendBlock(Block_Obj b) {
 
     // If a block is empty, there's no reason to extend it since any rules placed on this block
     // won't have any output. The main benefit of this is for structures like:
@@ -1988,9 +2022,9 @@
     // there are no child statements. However .a .b should have extensions applied.
 
     for (size_t i = 0, L = b->length(); i < L; ++i) {
-      Statement* stm = (*b)[i];
+      Statement_Obj stm = b->at(i);
 
-      if (typeid(*stm) == typeid(Ruleset)) {
+      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.
       }
       else {
@@ -2005,10 +2039,9 @@
 
   // Extend a ruleset by extending the selectors and updating them on the ruleset. The block's rules don't need to change.
   template <typename ObjectType>
-  static void extendObjectWithSelectorAndBlock(ObjectType* pObject, Context& ctx, ExtensionSubsetMap& subset_map) {
-    To_String to_string(&ctx);
+  static void extendObjectWithSelectorAndBlock(ObjectType* pObject, Context& ctx, Subset_Map& subset_map) {
 
-    DEBUG_PRINTLN(EXTEND_OBJECT, "FOUND SELECTOR: " << static_cast<Selector_List*>(pObject->selector())->perform(&to_string))
+    DEBUG_PRINTLN(EXTEND_OBJECT, "FOUND SELECTOR: " << static_cast<Selector_List_Ptr>(pObject->selector())->to_string(ctx.c_options))
 
     // 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.
@@ -2018,13 +2051,13 @@
     }
 
     bool extendedSomething = false;
-    Selector_List* pNewSelectorList = Extend::extendSelectorList(static_cast<Selector_List*>(pObject->selector()), ctx, subset_map, false, extendedSomething);
+    Selector_List_Obj pNewSelectorList = Extend::extendSelectorList(SASS_MEMORY_CAST(Selector_List, pObject->selector()), ctx, subset_map, false, extendedSomething);
 
     if (extendedSomething && pNewSelectorList) {
-      DEBUG_PRINTLN(EXTEND_OBJECT, "EXTEND ORIGINAL SELECTORS: " << static_cast<Selector_List*>(pObject->selector())->perform(&to_string))
-      DEBUG_PRINTLN(EXTEND_OBJECT, "EXTEND SETTING NEW SELECTORS: " << pNewSelectorList->perform(&to_string))
+      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))
       pNewSelectorList->remove_parent_selectors();
-      pObject->selector(pNewSelectorList);
+      pObject->selector(&pNewSelectorList);
     } else {
       DEBUG_PRINTLN(EXTEND_OBJECT, "EXTEND DID NOT TRY TO EXTEND ANYTHING")
     }
@@ -2032,36 +2065,56 @@
 
 
 
-  Extend::Extend(Context& ctx, ExtensionSubsetMap& ssm)
+  Extend::Extend(Context& ctx, Subset_Map& ssm)
   : ctx(ctx), subset_map(ssm)
   { }
 
-  void Extend::operator()(Block* b)
+  void Extend::operator()(Block_Ptr b)
   {
     for (size_t i = 0, L = b->length(); i < L; ++i) {
-      (*b)[i]->perform(this);
+      Statement_Obj stm = b->at(i);
+      stm->perform(this);
     }
+    // do final check if everything was extended
+    // we set `extended` flag on extended selectors
+    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;
+        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 }));
+        // 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());
+      }
+    }
+
   }
 
-  void Extend::operator()(Ruleset* pRuleset)
+  void Extend::operator()(Ruleset_Ptr pRuleset)
   {
-    extendObjectWithSelectorAndBlock(pRuleset, ctx, subset_map);
+    extendObjectWithSelectorAndBlock( pRuleset, ctx, subset_map);
     pRuleset->block()->perform(this);
   }
 
-  void Extend::operator()(Supports_Block* pFeatureBlock)
+  void Extend::operator()(Supports_Block_Ptr pFeatureBlock)
   {
     pFeatureBlock->block()->perform(this);
   }
 
-  void Extend::operator()(Media_Block* pMediaBlock)
+  void Extend::operator()(Media_Block_Ptr pMediaBlock)
   {
     pMediaBlock->block()->perform(this);
   }
 
-  void Extend::operator()(At_Rule* a)
+  void Extend::operator()(Directive_Ptr a)
   {
-    // Selector_List* ls = dynamic_cast<Selector_List*>(a->selector());
+    // Selector_List_Ptr ls = dynamic_cast<Selector_List_Ptr>(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
@@ -2,6 +2,7 @@
 #define SASS_EXTEND_H
 
 #include <string>
+#include <set>
 
 #include "ast.hpp"
 #include "operation.hpp"
@@ -12,28 +13,34 @@
   class Context;
   class Node;
 
-  typedef Subset_Map<std::string, std::pair<Complex_Selector*, Compound_Selector*> > ExtensionSubsetMap;
-
   class Extend : public Operation_CRTP<void, Extend> {
 
     Context&            ctx;
-    ExtensionSubsetMap& subset_map;
+    Subset_Map& subset_map;
 
-    void fallback_impl(AST_Node* n) { }
+    void fallback_impl(AST_Node_Ptr n) { }
 
   public:
     static Node subweave(Node& one, Node& two, Context& ctx);
-    static Selector_List* extendSelectorList(Selector_List* pSelectorList, Context& ctx, ExtensionSubsetMap& subset_map, bool isReplace, bool& extendedSomething);
-    Extend(Context&, ExtensionSubsetMap&);
-    virtual ~Extend() { }
-
-    using Operation<void>::operator();
+    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) {
+      bool extendedSomething = false;
+      return extendSelectorList(pSelectorList, ctx, subset_map, isReplace, extendedSomething);
+    }
+    static Selector_List_Ptr extendSelectorList(Selector_List_Obj pSelectorList, Context& ctx, Subset_Map& subset_map, std::set<Compound_Selector>& seen) {
+      bool isReplace = false;
+      bool extendedSomething = false;
+      return extendSelectorList(pSelectorList, ctx, subset_map, isReplace, extendedSomething, seen);
+    }
+    Extend(Context&, Subset_Map&);
+    ~Extend() { }
 
-    void operator()(Block*);
-    void operator()(Ruleset*);
-    void operator()(Supports_Block*);
-    void operator()(Media_Block*);
-    void operator()(At_Rule*);
+    void operator()(Block_Ptr);
+    void operator()(Ruleset_Ptr);
+    void operator()(Supports_Block_Ptr);
+    void operator()(Media_Block_Ptr);
+    void operator()(Directive_Ptr);
 
     template <typename U>
     void fallback(U x) { return fallback_impl(x); }
diff --git a/libsass/src/file.cpp b/libsass/src/file.cpp
--- a/libsass/src/file.cpp
+++ b/libsass/src/file.cpp
@@ -1,19 +1,15 @@
 #ifdef _WIN32
-#ifdef __MINGW32__
-#ifndef off64_t
-#define off64_t _off64_t    /* Workaround for http://sourceforge.net/p/mingw/bugs/2024/ */
-#endif
-#endif
-#include <direct.h>
-#define getcwd _getcwd
-#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
+# ifdef __MINGW32__
+#  ifndef off64_t
+#   define off64_t _off64_t    /* Workaround for http://sourceforge.net/p/mingw/bugs/2024/ */
+#  endif
+# endif
+# include <direct.h>
+# define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
 #else
-#include <unistd.h>
-#endif
-#ifdef _MSC_VER
-#define NOMINMAX
+# include <unistd.h>
 #endif
-
+#include "sass.hpp"
 #include <iostream>
 #include <fstream>
 #include <cctype>
@@ -27,15 +23,24 @@
 #include "sass2scss.h"
 
 #ifdef _WIN32
-#include <windows.h>
-#endif
+# include <windows.h>
 
-#ifndef FS_CASE_SENSITIVE
-#ifdef _WIN32
-#define FS_CASE_SENSITIVE 0
-#else
-#define FS_CASE_SENSITIVE 1
-#endif
+# ifdef _MSC_VER
+# include <codecvt>
+inline static std::string wstring_to_string(const std::wstring& wstr)
+{
+    std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> wchar_converter;
+    return wchar_converter.to_bytes(wstr);
+}
+# else // mingw(/gcc) does not support C++11's codecvt yet.
+inline static std::string wstring_to_string(const std::wstring &wstr)
+{
+    int size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL);
+    std::string strTo(size_needed, 0);
+    WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), &strTo[0], size_needed, NULL, NULL);
+    return strTo;
+}
+# endif
 #endif
 
 namespace Sass {
@@ -46,9 +51,12 @@
     std::string get_cwd()
     {
       const size_t wd_len = 1024;
-      char wd[wd_len];
-      std::string cwd = getcwd(wd, wd_len);
-      #ifdef _WIN32
+      #ifndef _WIN32
+        char wd[wd_len];
+        std::string cwd = getcwd(wd, wd_len);
+      #else
+        wchar_t wd[wd_len];
+        std::string cwd = wstring_to_string(_wgetcwd(wd, wd_len));
         //convert backslashes to forward slashes
         replace(cwd.begin(), cwd.end(), '\\', '/');
       #endif
@@ -184,8 +192,11 @@
       if (l[l.length()-1] != '/') l += '/';
 
       while ((r.length() > 3) && ((r.substr(0, 3) == "../") || (r.substr(0, 3)) == "..\\")) {
-        r = r.substr(3);
-        size_t pos = find_last_folder_separator(l, l.length() - 2);
+        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] == '\\');
+        bool is_self = pos + 3 == L && (l[pos+1] == '.');
+        if (!is_self && !is_slash) r = r.substr(3);
+        else if (pos == std::string::npos) break;
         l = l.substr(0, pos == std::string::npos ? pos : pos + 1);
       }
 
@@ -207,7 +218,7 @@
     // create an absolute path by resolving relative paths with cwd
     std::string rel2abs(const std::string& path, const std::string& base, const std::string& cwd)
     {
-      return make_canonical_path(join_paths(join_paths(cwd, base), path));
+      return make_canonical_path(join_paths(join_paths(cwd + "/", base + "/"), path));
     }
 
     // create a path that is relative to the given base directory
diff --git a/libsass/src/file.hpp b/libsass/src/file.hpp
--- a/libsass/src/file.hpp
+++ b/libsass/src/file.hpp
@@ -4,10 +4,9 @@
 #include <string>
 #include <vector>
 
-namespace Sass {
+#include "ast_fwd_decl.hpp"
 
-  class Block;
-  class Context;
+namespace Sass {
 
   namespace File {
 
@@ -105,9 +104,9 @@
   class StyleSheet : public Resource {
     public:
       // parsed root block
-      Block* root;
+      Block_Obj root;
     public:
-      StyleSheet(const Resource& res, Block* root)
+      StyleSheet(const Resource& res, Block_Obj root)
       : Resource(res), root(root)
       { }
   };
diff --git a/libsass/src/functions.cpp b/libsass/src/functions.cpp
--- a/libsass/src/functions.cpp
+++ b/libsass/src/functions.cpp
@@ -1,10 +1,10 @@
+#include "sass.hpp"
 #include "functions.hpp"
 #include "ast.hpp"
 #include "context.hpp"
 #include "backtrace.hpp"
 #include "parser.hpp"
 #include "constants.hpp"
-#include "to_string.hpp"
 #include "inspect.hpp"
 #include "extend.hpp"
 #include "eval.hpp"
@@ -14,6 +14,7 @@
 #include "sass/base.h"
 #include "utf8.h"
 
+#include <cstdint>
 #include <cstdlib>
 #include <cmath>
 #include <cctype>
@@ -37,13 +38,13 @@
   using std::stringstream;
   using std::endl;
 
-  Definition* make_native_function(Signature sig, Native_Function func, Context& ctx)
+  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]"));
     sig_parser.lex<Prelexer::identifier>();
     std::string name(Util::normalize_underscores(sig_parser.lexed));
-    Parameters* params = sig_parser.parse_parameters();
-    return SASS_MEMORY_NEW(ctx.mem, Definition,
+    Parameters_Obj params = sig_parser.parse_parameters();
+    return SASS_MEMORY_NEW(Definition,
                            ParserState("[built-in function]"),
                            sig,
                            name,
@@ -52,7 +53,7 @@
                            false);
   }
 
-  Definition* make_c_function(Sass_Function_Entry c_func, Context& ctx)
+  Definition_Ptr make_c_function(Sass_Function_Entry c_func, Context& ctx)
   {
     using namespace Prelexer;
 
@@ -65,8 +66,8 @@
                                     exactly < Constants::debug_kwd >
                    >              >();
     std::string name(Util::normalize_underscores(sig_parser.lexed));
-    Parameters* params = sig_parser.parse_parameters();
-    return SASS_MEMORY_NEW(ctx.mem, Definition,
+    Parameters_Obj params = sig_parser.parse_parameters();
+    return SASS_MEMORY_NEW(Definition,
                            ParserState("[c function]"),
                            sig,
                            name,
@@ -107,7 +108,7 @@
     T* get_arg(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtrace* backtrace)
     {
       // Minimal error handling -- the expectation is that built-ins will be written correctly!
-      T* val = dynamic_cast<T*>(env[argname]);
+      T* val = dynamic_cast<T*>(&env[argname]);
       if (!val) {
         std::string msg("argument `");
         msg += argname;
@@ -120,24 +121,24 @@
       return val;
     }
 
-    Map* 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, Backtrace* backtrace, Context& ctx)
     {
       // Minimal error handling -- the expectation is that built-ins will be written correctly!
-      Map* val = dynamic_cast<Map*>(env[argname]);
+      Map_Ptr val = SASS_MEMORY_CAST(Map, env[argname]);
       if (val) return val;
 
-      List* lval = dynamic_cast<List*>(env[argname]);
-      if (lval && lval->length() == 0) return SASS_MEMORY_NEW(ctx.mem, Map, pstate, 0);
+      List_Ptr lval = SASS_MEMORY_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);
       return val;
     }
 
-    Number* get_arg_r(const std::string& argname, Env& env, Signature sig, ParserState pstate, double lo, double hi, Backtrace* backtrace)
+    Number_Ptr get_arg_r(const std::string& argname, Env& env, Signature sig, ParserState pstate, double lo, double hi, Backtrace* backtrace)
     {
       // Minimal error handling -- the expectation is that built-ins will be written correctly!
-      Number* val = get_arg<Number>(argname, env, sig, pstate, backtrace);
+      Number_Ptr val = get_arg<Number>(argname, env, sig, pstate, backtrace);
       double v = val->value();
       if (!(lo <= v && v <= hi)) {
         std::stringstream msg;
@@ -151,49 +152,38 @@
     #define ARGSEL(argname, seltype, contextualize) get_arg_sel<seltype>(argname, env, sig, pstate, backtrace, 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, Backtrace* backtrace, Context& ctx);
 
     template <>
-    Selector_List* get_arg_sel(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtrace* backtrace, Context& ctx) {
-      To_String to_string(&ctx, false);
-      Expression* exp = ARG(argname, Expression);
+    Selector_List_Obj get_arg_sel(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtrace* backtrace, 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);
       }
-      std::string exp_src = exp->perform(&to_string) + "{";
-      return Parser::parse_selector(exp_src.c_str(), ctx);
-    }
-
-    template <>
-    Complex_Selector* get_arg_sel(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtrace* backtrace, Context& ctx) {
-      To_String to_string(&ctx, false);
-      Expression* 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);
+      if (String_Constant_Ptr str = SASS_MEMORY_CAST(String_Constant, exp)) {
+        str->quote_mark(0);
       }
-      std::string exp_src = exp->perform(&to_string) + "{";
-      Selector_List* sel_list = Parser::parse_selector(exp_src.c_str(), ctx);
-      return (sel_list->length() > 0) ? sel_list->first() : 0;
+      std::string exp_src = exp->to_string(ctx.c_options) + "{";
+      return Parser::parse_selector(exp_src.c_str(), ctx);
     }
 
     template <>
-    Compound_Selector* get_arg_sel(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtrace* backtrace, Context& ctx) {
-      To_String to_string(&ctx, false);
-      Expression* exp = ARG(argname, Expression);
+    Compound_Selector_Obj get_arg_sel(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtrace* backtrace, 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);
       }
-      std::string exp_src = exp->perform(&to_string) + "{";
-      Selector_List* sel_list = Parser::parse_selector(exp_src.c_str(), ctx);
-      return (sel_list->length() > 0) ? sel_list->first()->tail()->head() : 0;
+      if (String_Constant_Ptr str = SASS_MEMORY_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;
     }
 
     #ifdef __MINGW32__
@@ -211,9 +201,9 @@
       return seed;
     }
     #else
-    static std::random_device rd;
     uint64_t GetSeed()
     {
+      std::random_device rd;
       return rd();
     }
     #endif
@@ -236,7 +226,7 @@
     // RGB FUNCTIONS
     ////////////////
 
-    inline double color_num(Number* n) {
+    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 {
@@ -244,7 +234,7 @@
       }
     }
 
-    inline double alpha_num(Number* n) {
+    inline double alpha_num(Number_Ptr n) {
       if (n->unit() == "%") {
         return std::min(std::max(n->value(), 0.0), 100.0);
       } else {
@@ -255,7 +245,7 @@
     Signature rgb_sig = "rgb($red, $green, $blue)";
     BUILT_IN(rgb)
     {
-      return SASS_MEMORY_NEW(ctx.mem, Color,
+      return SASS_MEMORY_NEW(Color,
                              pstate,
                              color_num(ARG("$red",   Number)),
                              color_num(ARG("$green", Number)),
@@ -265,7 +255,7 @@
     Signature rgba_4_sig = "rgba($red, $green, $blue, $alpha)";
     BUILT_IN(rgba_4)
     {
-      return SASS_MEMORY_NEW(ctx.mem, Color,
+      return SASS_MEMORY_NEW(Color,
                              pstate,
                              color_num(ARG("$red",   Number)),
                              color_num(ARG("$green", Number)),
@@ -276,8 +266,8 @@
     Signature rgba_2_sig = "rgba($color, $alpha)";
     BUILT_IN(rgba_2)
     {
-      Color* c_arg = ARG("$color", Color);
-      Color* new_c = SASS_MEMORY_NEW(ctx.mem, Color, *c_arg);
+      Color_Ptr c_arg = ARG("$color", Color);
+      Color_Ptr new_c = SASS_MEMORY_COPY(c_arg);
       new_c->a(alpha_num(ARG("$alpha", Number)));
       new_c->disp("");
       return new_c;
@@ -285,22 +275,22 @@
 
     Signature red_sig = "red($color)";
     BUILT_IN(red)
-    { return SASS_MEMORY_NEW(ctx.mem, Number, pstate, ARG("$color", Color)->r()); }
+    { return SASS_MEMORY_NEW(Number, pstate, ARG("$color", Color)->r()); }
 
     Signature green_sig = "green($color)";
     BUILT_IN(green)
-    { return SASS_MEMORY_NEW(ctx.mem, Number, pstate, ARG("$color", Color)->g()); }
+    { return SASS_MEMORY_NEW(Number, pstate, ARG("$color", Color)->g()); }
 
     Signature blue_sig = "blue($color)";
     BUILT_IN(blue)
-    { return SASS_MEMORY_NEW(ctx.mem, Number, pstate, ARG("$color", Color)->b()); }
+    { return SASS_MEMORY_NEW(Number, pstate, ARG("$color", Color)->b()); }
 
     Signature mix_sig = "mix($color-1, $color-2, $weight: 50%)";
     BUILT_IN(mix)
     {
-      Color*  color1 = ARG("$color-1", Color);
-      Color*  color2 = ARG("$color-2", Color);
-      Number* weight = ARGR("$weight", Number, 0, 100);
+      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;
       double w = 2*p - 1;
@@ -309,11 +299,11 @@
       double w1 = (((w * a == -1) ? w : (w + a)/(1 + w*a)) + 1)/2.0;
       double w2 = 1 - w1;
 
-      return SASS_MEMORY_NEW(ctx.mem, Color,
+      return SASS_MEMORY_NEW(Color,
                              pstate,
-                             Sass::round(w1*color1->r() + w2*color2->r()),
-                             Sass::round(w1*color1->g() + w2*color2->g()),
-                             Sass::round(w1*color1->b() + w2*color2->b()),
+                             Sass::round(w1*color1->r() + w2*color2->r(), ctx.c_options.precision),
+                             Sass::round(w1*color1->g() + w2*color2->g(), ctx.c_options.precision),
+                             Sass::round(w1*color1->b() + w2*color2->b(), ctx.c_options.precision),
                              color1->a()*p + color2->a()*(1-p));
     }
 
@@ -365,7 +355,7 @@
       return m1;
     }
 
-    Color* hsla_impl(double h, double s, double l, double a, Context& ctx, ParserState pstate)
+    Color_Ptr hsla_impl(double h, double s, double l, double a, Context& ctx, ParserState pstate)
     {
       h /= 360.0;
       s /= 100.0;
@@ -378,6 +368,12 @@
       while (h < 0) h += 1;
       while (h > 1) h -= 1;
 
+      // if saturation is exacly zero, we loose
+      // information for hue, since it will evaluate
+      // to zero if converted back from rgb. Setting
+      // saturation to a very tiny number solves this.
+      if (s == 0) s = 1e-10;
+
       // Algorithm from the CSS3 spec: http://www.w3.org/TR/css3-color/#hsl-color.
       double m2;
       if (l <= 0.5) m2 = l*(s+1.0);
@@ -388,7 +384,7 @@
       double g = (h_to_rgb(m1, m2, h) * 255.0);
       double b = (h_to_rgb(m1, m2, h - 1.0/3.0) * 255.0);
 
-      return SASS_MEMORY_NEW(ctx.mem, Color, pstate, r, g, b, a);
+      return SASS_MEMORY_NEW(Color, pstate, r, g, b, a);
     }
 
     Signature hsl_sig = "hsl($hue, $saturation, $lightness)";
@@ -416,38 +412,38 @@
     Signature hue_sig = "hue($color)";
     BUILT_IN(hue)
     {
-      Color* rgb_color = ARG("$color", Color);
+      Color_Ptr rgb_color = ARG("$color", Color);
       HSL hsl_color = rgb_to_hsl(rgb_color->r(),
                                  rgb_color->g(),
                                  rgb_color->b());
-      return SASS_MEMORY_NEW(ctx.mem, Number, pstate, hsl_color.h, "deg");
+      return SASS_MEMORY_NEW(Number, pstate, hsl_color.h, "deg");
     }
 
     Signature saturation_sig = "saturation($color)";
     BUILT_IN(saturation)
     {
-      Color* rgb_color = ARG("$color", Color);
+      Color_Ptr rgb_color = ARG("$color", Color);
       HSL hsl_color = rgb_to_hsl(rgb_color->r(),
                                  rgb_color->g(),
                                  rgb_color->b());
-      return SASS_MEMORY_NEW(ctx.mem, Number, pstate, hsl_color.s, "%");
+      return SASS_MEMORY_NEW(Number, pstate, hsl_color.s, "%");
     }
 
     Signature lightness_sig = "lightness($color)";
     BUILT_IN(lightness)
     {
-      Color* rgb_color = ARG("$color", Color);
+      Color_Ptr rgb_color = ARG("$color", Color);
       HSL hsl_color = rgb_to_hsl(rgb_color->r(),
                                  rgb_color->g(),
                                  rgb_color->b());
-      return SASS_MEMORY_NEW(ctx.mem, Number, pstate, hsl_color.l, "%");
+      return SASS_MEMORY_NEW(Number, pstate, hsl_color.l, "%");
     }
 
     Signature adjust_hue_sig = "adjust-hue($color, $degrees)";
     BUILT_IN(adjust_hue)
     {
-      Color* rgb_color = ARG("$color", Color);
-      Number* degrees = ARG("$degrees", Number);
+      Color_Ptr rgb_color = ARG("$color", Color);
+      Number_Ptr degrees = ARG("$degrees", Number);
       HSL hsl_color = rgb_to_hsl(rgb_color->r(),
                                  rgb_color->g(),
                                  rgb_color->b());
@@ -462,8 +458,8 @@
     Signature lighten_sig = "lighten($color, $amount)";
     BUILT_IN(lighten)
     {
-      Color* rgb_color = ARG("$color", Color);
-      Number* amount = ARGR("$amount", Number, 0, 100);
+      Color_Ptr rgb_color = ARG("$color", Color);
+      Number_Ptr amount = ARGR("$amount", Number, 0, 100);
       HSL hsl_color = rgb_to_hsl(rgb_color->r(),
                                  rgb_color->g(),
                                  rgb_color->b());
@@ -484,8 +480,8 @@
     Signature darken_sig = "darken($color, $amount)";
     BUILT_IN(darken)
     {
-      Color* rgb_color = ARG("$color", Color);
-      Number* amount = ARGR("$amount", Number, 0, 100);
+      Color_Ptr rgb_color = ARG("$color", Color);
+      Number_Ptr amount = ARGR("$amount", Number, 0, 100);
       HSL hsl_color = rgb_to_hsl(rgb_color->r(),
                                  rgb_color->g(),
                                  rgb_color->b());
@@ -508,14 +504,13 @@
     BUILT_IN(saturate)
     {
       // CSS3 filter function overload: pass literal through directly
-      Number* amount = dynamic_cast<Number*>(env["$amount"]);
+      Number_Ptr amount = SASS_MEMORY_CAST(Number, env["$amount"]);
       if (!amount) {
-        To_String to_string(&ctx);
-        return SASS_MEMORY_NEW(ctx.mem, String_Quoted, pstate, "saturate(" + env["$color"]->perform(&to_string) + ")");
+        return SASS_MEMORY_NEW(String_Quoted, pstate, "saturate(" + env["$color"]->to_string(ctx.c_options) + ")");
       }
 
       ARGR("$amount", Number, 0, 100);
-      Color* rgb_color = ARG("$color", Color);
+      Color_Ptr rgb_color = ARG("$color", Color);
       HSL hsl_color = rgb_to_hsl(rgb_color->r(),
                                  rgb_color->g(),
                                  rgb_color->b());
@@ -541,8 +536,8 @@
     Signature desaturate_sig = "desaturate($color, $amount)";
     BUILT_IN(desaturate)
     {
-      Color* rgb_color = ARG("$color", Color);
-      Number* amount = ARGR("$amount", Number, 0, 100);
+      Color_Ptr rgb_color = ARG("$color", Color);
+      Number_Ptr amount = ARGR("$amount", Number, 0, 100);
       HSL hsl_color = rgb_to_hsl(rgb_color->r(),
                                  rgb_color->g(),
                                  rgb_color->b());
@@ -569,13 +564,12 @@
     BUILT_IN(grayscale)
     {
       // CSS3 filter function overload: pass literal through directly
-      Number* amount = dynamic_cast<Number*>(env["$color"]);
+      Number_Ptr amount = SASS_MEMORY_CAST(Number, env["$color"]);
       if (amount) {
-        To_String to_string(&ctx);
-        return SASS_MEMORY_NEW(ctx.mem, String_Quoted, pstate, "grayscale(" + amount->perform(&to_string) + ")");
+        return SASS_MEMORY_NEW(String_Quoted, pstate, "grayscale(" + amount->to_string(ctx.c_options) + ")");
       }
 
-      Color* rgb_color = ARG("$color", Color);
+      Color_Ptr rgb_color = ARG("$color", Color);
       HSL hsl_color = rgb_to_hsl(rgb_color->r(),
                                  rgb_color->g(),
                                  rgb_color->b());
@@ -590,7 +584,7 @@
     Signature complement_sig = "complement($color)";
     BUILT_IN(complement)
     {
-      Color* rgb_color = ARG("$color", Color);
+      Color_Ptr rgb_color = ARG("$color", Color);
       HSL hsl_color = rgb_to_hsl(rgb_color->r(),
                                  rgb_color->g(),
                                  rgb_color->b());
@@ -606,14 +600,13 @@
     BUILT_IN(invert)
     {
       // CSS3 filter function overload: pass literal through directly
-      Number* amount = dynamic_cast<Number*>(env["$color"]);
+      Number_Ptr amount = SASS_MEMORY_CAST(Number, env["$color"]);
       if (amount) {
-        To_String to_string(&ctx);
-        return SASS_MEMORY_NEW(ctx.mem, String_Quoted, pstate, "invert(" + amount->perform(&to_string) + ")");
+        return SASS_MEMORY_NEW(String_Quoted, pstate, "invert(" + amount->to_string(ctx.c_options) + ")");
       }
 
-      Color* rgb_color = ARG("$color", Color);
-      return SASS_MEMORY_NEW(ctx.mem, Color,
+      Color_Ptr rgb_color = ARG("$color", Color);
+      return SASS_MEMORY_NEW(Color,
                              pstate,
                              255 - rgb_color->r(),
                              255 - rgb_color->g(),
@@ -628,29 +621,28 @@
     Signature opacity_sig = "opacity($color)";
     BUILT_IN(alpha)
     {
-      String_Constant* ie_kwd = dynamic_cast<String_Constant*>(env["$color"]);
+      String_Constant_Ptr ie_kwd = SASS_MEMORY_CAST(String_Constant, env["$color"]);
       if (ie_kwd) {
-        return SASS_MEMORY_NEW(ctx.mem, String_Quoted, pstate, "alpha(" + ie_kwd->value() + ")");
+        return SASS_MEMORY_NEW(String_Quoted, pstate, "alpha(" + ie_kwd->value() + ")");
       }
 
       // CSS3 filter function overload: pass literal through directly
-      Number* amount = dynamic_cast<Number*>(env["$color"]);
+      Number_Ptr amount = SASS_MEMORY_CAST(Number, env["$color"]);
       if (amount) {
-        To_String to_string(&ctx);
-        return SASS_MEMORY_NEW(ctx.mem, String_Quoted, pstate, "opacity(" + amount->perform(&to_string) + ")");
+        return SASS_MEMORY_NEW(String_Quoted, pstate, "opacity(" + amount->to_string(ctx.c_options) + ")");
       }
 
-      return SASS_MEMORY_NEW(ctx.mem, Number, pstate, ARG("$color", Color)->a());
+      return SASS_MEMORY_NEW(Number, pstate, ARG("$color", Color)->a());
     }
 
     Signature opacify_sig = "opacify($color, $amount)";
     Signature fade_in_sig = "fade-in($color, $amount)";
     BUILT_IN(opacify)
     {
-      Color* color = ARG("$color", Color);
+      Color_Ptr color = ARG("$color", Color);
       double amount = ARGR("$amount", Number, 0, 1)->value();
       double alpha = std::min(color->a() + amount, 1.0);
-      return SASS_MEMORY_NEW(ctx.mem, Color,
+      return SASS_MEMORY_NEW(Color,
                              pstate,
                              color->r(),
                              color->g(),
@@ -662,10 +654,10 @@
     Signature fade_out_sig = "fade-out($color, $amount)";
     BUILT_IN(transparentize)
     {
-      Color* color = ARG("$color", Color);
+      Color_Ptr color = ARG("$color", Color);
       double amount = ARGR("$amount", Number, 0, 1)->value();
       double alpha = std::max(color->a() - amount, 0.0);
-      return SASS_MEMORY_NEW(ctx.mem, Color,
+      return SASS_MEMORY_NEW(Color,
                              pstate,
                              color->r(),
                              color->g(),
@@ -680,27 +672,27 @@
     Signature adjust_color_sig = "adjust-color($color, $red: false, $green: false, $blue: false, $hue: false, $saturation: false, $lightness: false, $alpha: false)";
     BUILT_IN(adjust_color)
     {
-      Color* color = ARG("$color", Color);
-      Number* r = dynamic_cast<Number*>(env["$red"]);
-      Number* g = dynamic_cast<Number*>(env["$green"]);
-      Number* b = dynamic_cast<Number*>(env["$blue"]);
-      Number* h = dynamic_cast<Number*>(env["$hue"]);
-      Number* s = dynamic_cast<Number*>(env["$saturation"]);
-      Number* l = dynamic_cast<Number*>(env["$lightness"]);
-      Number* a = dynamic_cast<Number*>(env["$alpha"]);
+      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"]);
 
       bool rgb = r || g || b;
       bool hsl = h || s || l;
 
       if (rgb && hsl) {
-        error("cannot specify both RGB and HSL values for `adjust-color`", pstate);
+        error("Cannot specify HSL and RGB values for a color at the same time for `adjust-color'", pstate);
       }
       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;
-        return SASS_MEMORY_NEW(ctx.mem, Color,
+        return SASS_MEMORY_NEW(Color,
                                pstate,
                                color->r() + rr,
                                color->g() + gg,
@@ -720,14 +712,14 @@
                          pstate);
       }
       if (a) {
-        return SASS_MEMORY_NEW(ctx.mem, Color,
+        return SASS_MEMORY_NEW(Color,
                                pstate,
                                color->r(),
                                color->g(),
                                color->b(),
                                color->a() + (a ? a->value() : 0));
       }
-      error("not enough arguments for `adjust-color`", pstate);
+      error("not enough arguments for `adjust-color'", pstate);
       // unreachable
       return color;
     }
@@ -735,27 +727,27 @@
     Signature scale_color_sig = "scale-color($color, $red: false, $green: false, $blue: false, $hue: false, $saturation: false, $lightness: false, $alpha: false)";
     BUILT_IN(scale_color)
     {
-      Color* color = ARG("$color", Color);
-      Number* r = dynamic_cast<Number*>(env["$red"]);
-      Number* g = dynamic_cast<Number*>(env["$green"]);
-      Number* b = dynamic_cast<Number*>(env["$blue"]);
-      Number* h = dynamic_cast<Number*>(env["$hue"]);
-      Number* s = dynamic_cast<Number*>(env["$saturation"]);
-      Number* l = dynamic_cast<Number*>(env["$lightness"]);
-      Number* a = dynamic_cast<Number*>(env["$alpha"]);
+      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"]);
 
       bool rgb = r || g || b;
       bool hsl = h || s || l;
 
       if (rgb && hsl) {
-        error("cannot specify both RGB and HSL values for `scale-color`", pstate);
+        error("Cannot specify HSL and RGB values for a color at the same time for `scale-color'", pstate);
       }
       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;
-        return SASS_MEMORY_NEW(ctx.mem, Color,
+        return SASS_MEMORY_NEW(Color,
                                pstate,
                                color->r() + rscale * (rscale > 0.0 ? 255 - color->r() : color->r()),
                                color->g() + gscale * (gscale > 0.0 ? 255 - color->g() : color->g()),
@@ -776,14 +768,14 @@
       }
       if (a) {
         double ascale = (a ? ARGR("$alpha", Number, -100.0, 100.0)->value() : 0.0) / 100.0;
-        return SASS_MEMORY_NEW(ctx.mem, Color,
+        return SASS_MEMORY_NEW(Color,
                                pstate,
                                color->r(),
                                color->g(),
                                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);
       // unreachable
       return color;
     }
@@ -791,23 +783,23 @@
     Signature change_color_sig = "change-color($color, $red: false, $green: false, $blue: false, $hue: false, $saturation: false, $lightness: false, $alpha: false)";
     BUILT_IN(change_color)
     {
-      Color* color = ARG("$color", Color);
-      Number* r = dynamic_cast<Number*>(env["$red"]);
-      Number* g = dynamic_cast<Number*>(env["$green"]);
-      Number* b = dynamic_cast<Number*>(env["$blue"]);
-      Number* h = dynamic_cast<Number*>(env["$hue"]);
-      Number* s = dynamic_cast<Number*>(env["$saturation"]);
-      Number* l = dynamic_cast<Number*>(env["$lightness"]);
-      Number* a = dynamic_cast<Number*>(env["$alpha"]);
+      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"]);
 
       bool rgb = r || g || b;
       bool hsl = h || s || l;
 
       if (rgb && hsl) {
-        error("cannot specify both RGB and HSL values for `change-color`", pstate);
+        error("Cannot specify HSL and RGB values for a color at the same time for `change-color'", pstate);
       }
       if (rgb) {
-        return SASS_MEMORY_NEW(ctx.mem, Color,
+        return SASS_MEMORY_NEW(Color,
                                pstate,
                                r ? ARGR("$red",   Number, 0, 255)->value() : color->r(),
                                g ? ARGR("$green", Number, 0, 255)->value() : color->g(),
@@ -816,7 +808,7 @@
       }
       if (hsl) {
         HSL hsl_struct = rgb_to_hsl(color->r(), color->g(), color->b());
-        if (h) hsl_struct.h = static_cast<double>(((static_cast<int>(h->value()) % 360) + 360) % 360) / 360.0;
+        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();
@@ -824,14 +816,14 @@
       }
       if (a) {
         double alpha = a ? ARGR("$alpha", Number, 0, 1.0)->value() : color->a();
-        return SASS_MEMORY_NEW(ctx.mem, Color,
+        return SASS_MEMORY_NEW(Color,
                                pstate,
                                color->r(),
                                color->g(),
                                color->b(),
                                alpha);
       }
-      error("not enough arguments for `change-color`", pstate);
+      error("not enough arguments for `change-color'", pstate);
       // unreachable
       return color;
     }
@@ -846,7 +838,7 @@
     Signature ie_hex_str_sig = "ie-hex-str($color)";
     BUILT_IN(ie_hex_str)
     {
-      Color* c = ARG("$color", Color);
+      Color_Ptr c = ARG("$color", Color);
       double r = cap_channel<0xff>(c->r());
       double g = cap_channel<0xff>(c->g());
       double b = cap_channel<0xff>(c->b());
@@ -854,16 +846,16 @@
 
       std::stringstream ss;
       ss << '#' << std::setw(2) << std::setfill('0');
-      ss << std::hex << std::setw(2) << static_cast<unsigned long>(Sass::round(a));
-      ss << std::hex << std::setw(2) << static_cast<unsigned long>(Sass::round(r));
-      ss << std::hex << std::setw(2) << static_cast<unsigned long>(Sass::round(g));
-      ss << std::hex << std::setw(2) << static_cast<unsigned long>(Sass::round(b));
+      ss << std::hex << std::setw(2) << static_cast<unsigned long>(Sass::round(a, ctx.c_options.precision));
+      ss << std::hex << std::setw(2) << static_cast<unsigned long>(Sass::round(r, ctx.c_options.precision));
+      ss << std::hex << std::setw(2) << static_cast<unsigned long>(Sass::round(g, ctx.c_options.precision));
+      ss << std::hex << std::setw(2) << static_cast<unsigned long>(Sass::round(b, ctx.c_options.precision));
 
       std::string result(ss.str());
       for (size_t i = 0, L = result.length(); i < L; ++i) {
         result[i] = std::toupper(result[i]);
       }
-      return SASS_MEMORY_NEW(ctx.mem, String_Quoted, pstate, result);
+      return SASS_MEMORY_NEW(String_Quoted, pstate, result);
     }
 
     ///////////////////
@@ -873,34 +865,41 @@
     Signature unquote_sig = "unquote($string)";
     BUILT_IN(sass_unquote)
     {
-      AST_Node* arg = env["$string"];
-      if (String_Quoted* string_quoted = dynamic_cast<String_Quoted*>(arg)) {
-        String_Constant* result = SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, string_quoted->value());
+      AST_Node_Obj arg = env["$string"];
+      if (String_Quoted_Ptr string_quoted = SASS_MEMORY_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->sass_fix_1291(string_quoted->quote_mark() != 0);
+        result->is_delayed(true); // delay colors
         return result;
       }
-      else if (dynamic_cast<String_Constant*>(arg)) {
-        return (Expression*) arg;
+      else if (SASS_MEMORY_CAST(String_Constant, arg)) {
+        return (Expression_Ptr) &arg;
       }
       else {
-        To_String to_string(&ctx, false, true);
-        std::string val(arg->perform(&to_string));
-        val = dynamic_cast<Null*>(arg) ? "null" : val;
+        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;
+        ctx.c_options.output_style = oldstyle;
 
         deprecated_function("Passing " + val + ", a non-string value, to unquote()", pstate);
-        return (Expression*) arg;
+        return (Expression_Ptr) &arg;
       }
     }
 
     Signature quote_sig = "quote($string)";
     BUILT_IN(sass_quote)
     {
-      To_String to_string(&ctx);
-      AST_Node* arg = env["$string"];
-      std::string str(quote(arg->perform(&to_string), String_Constant::double_quote()));
-      String_Quoted* result = SASS_MEMORY_NEW(ctx.mem, String_Quoted, pstate, str);
-      result->is_delayed(true);
+      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)) {
+        qstr->quote_mark('*');
+        return qstr;
+      }
+      // all other nodes must be converted to a string node
+      std::string str(quote(arg->to_string(ctx.c_options), String_Constant::double_quote()));
+      String_Quoted_Ptr result = SASS_MEMORY_NEW(String_Quoted, pstate, str);
+      result->quote_mark('*');
       return result;
     }
 
@@ -910,7 +909,7 @@
     {
       size_t len = std::string::npos;
       try {
-        String_Constant* s = ARG("$string", String_Constant);
+        String_Constant_Ptr s = ARG("$string", String_Constant);
         len = UTF_8::code_point_count(s->value(), 0, s->value().size());
 
       }
@@ -918,7 +917,7 @@
       // other errors will be re-thrown
       catch (...) { handle_utf8_error(pstate, backtrace); }
       // return something even if we had an error (-1)
-      return SASS_MEMORY_NEW(ctx.mem, Number, pstate, (double)len);
+      return SASS_MEMORY_NEW(Number, pstate, (double)len);
     }
 
     Signature str_insert_sig = "str-insert($string, $insert, $index)";
@@ -926,13 +925,13 @@
     {
       std::string str;
       try {
-        String_Constant* s = ARG("$string", String_Constant);
+        String_Constant_Ptr s = ARG("$string", String_Constant);
         str = s->value();
         str = unquote(str);
-        String_Constant* i = ARG("$insert", String_Constant);
+        String_Constant_Ptr i = ARG("$insert", String_Constant);
         std::string ins = i->value();
         ins = unquote(ins);
-        Number* ind = ARG("$index", Number);
+        Number_Ptr ind = ARG("$index", Number);
         double index = ind->value();
         size_t len = UTF_8::code_point_count(str, 0, str.size());
 
@@ -957,14 +956,14 @@
           str = ins + str;
         }
 
-        if (String_Quoted* ss = dynamic_cast<String_Quoted*>(s)) {
+        if (String_Quoted_Ptr ss = SASS_MEMORY_CAST_PTR(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); }
-      return SASS_MEMORY_NEW(ctx.mem, String_Quoted, pstate, str);
+      return SASS_MEMORY_NEW(String_Quoted, pstate, str);
     }
 
     Signature str_index_sig = "str-index($string, $substring)";
@@ -972,8 +971,8 @@
     {
       size_t index = std::string::npos;
       try {
-        String_Constant* s = ARG("$string", String_Constant);
-        String_Constant* t = ARG("$substring", String_Constant);
+        String_Constant_Ptr s = ARG("$string", String_Constant);
+        String_Constant_Ptr t = ARG("$substring", String_Constant);
         std::string str = s->value();
         str = unquote(str);
         std::string substr = t->value();
@@ -981,7 +980,7 @@
 
         size_t c_index = str.find(substr);
         if(c_index == std::string::npos) {
-          return SASS_MEMORY_NEW(ctx.mem, Null, pstate);
+          return SASS_MEMORY_NEW(Null, pstate);
         }
         index = UTF_8::code_point_count(str, 0, c_index) + 1;
       }
@@ -989,7 +988,7 @@
       // other errors will be re-thrown
       catch (...) { handle_utf8_error(pstate, backtrace); }
       // return something even if we had an error (-1)
-      return SASS_MEMORY_NEW(ctx.mem, Number, pstate, (double)index);
+      return SASS_MEMORY_NEW(Number, pstate, (double)index);
     }
 
     Signature str_slice_sig = "str-slice($string, $start-at, $end-at:-1)";
@@ -997,17 +996,33 @@
     {
       std::string newstr;
       try {
-        String_Constant* s = ARG("$string", String_Constant);
+        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);
 
         std::string str = unquote(s->value());
 
         size_t size = utf8::distance(str.begin(), str.end());
-        if (end_at <= size * -1.0) { end_at += size; }
-        if (end_at < 0) { end_at += size + 1; }
+
+        if (!SASS_MEMORY_CAST(Number, env["$end-at"])) {
+          end_at = -1;
+        }
+
+        if (end_at == 0 || (end_at + size) < 0) {
+          if (ss && ss->quote_mark()) newstr = quote("");
+          return SASS_MEMORY_NEW(String_Quoted, pstate, newstr);
+        }
+
+        if (end_at < 0) {
+          end_at += size + 1;
+          if (end_at == 0) end_at = 1;
+        }
         if (end_at > size) { end_at = (double)size; }
-        if (start_at < 0) { start_at += size + 1; }
+        if (start_at < 0) {
+          start_at += size + 1;
+          if (start_at < 0)  start_at = 0;
+        }
         else if (start_at == 0) { ++ start_at; }
 
         if (start_at <= end_at)
@@ -1018,20 +1033,20 @@
           utf8::advance(end, end_at - start_at + 1, str.end());
           newstr = std::string(start, end);
         }
-        if (String_Quoted* ss = dynamic_cast<String_Quoted*>(s)) {
+        if (ss) {
           if(ss->quote_mark()) newstr = quote(newstr);
         }
       }
       // handle any invalid utf8 errors
       // other errors will be re-thrown
       catch (...) { handle_utf8_error(pstate, backtrace); }
-      return SASS_MEMORY_NEW(ctx.mem, String_Quoted, pstate, newstr);
+      return SASS_MEMORY_NEW(String_Quoted, pstate, newstr);
     }
 
     Signature to_upper_case_sig = "to-upper-case($string)";
     BUILT_IN(to_upper_case)
     {
-      String_Constant* s = ARG("$string", String_Constant);
+      String_Constant_Ptr s = ARG("$string", String_Constant);
       std::string str = s->value();
 
       for (size_t i = 0, L = str.length(); i < L; ++i) {
@@ -1040,19 +1055,19 @@
         }
       }
 
-      if (String_Quoted* ss = dynamic_cast<String_Quoted*>(s)) {
-        String_Quoted* cpy = SASS_MEMORY_NEW(ctx.mem, String_Quoted, *ss);
+      if (String_Quoted_Ptr ss = SASS_MEMORY_CAST_PTR(String_Quoted, s)) {
+        String_Quoted_Ptr cpy = SASS_MEMORY_COPY(ss);
         cpy->value(str);
         return cpy;
       } else {
-        return SASS_MEMORY_NEW(ctx.mem, String_Quoted, pstate, str);
+        return SASS_MEMORY_NEW(String_Quoted, pstate, str);
       }
     }
 
     Signature to_lower_case_sig = "to-lower-case($string)";
     BUILT_IN(to_lower_case)
     {
-      String_Constant* s = ARG("$string", String_Constant);
+      String_Constant_Ptr s = ARG("$string", String_Constant);
       std::string str = s->value();
 
       for (size_t i = 0, L = str.length(); i < L; ++i) {
@@ -1061,12 +1076,12 @@
         }
       }
 
-      if (String_Quoted* ss = dynamic_cast<String_Quoted*>(s)) {
-        String_Quoted* cpy = SASS_MEMORY_NEW(ctx.mem, String_Quoted, *ss);
+      if (String_Quoted_Ptr ss = SASS_MEMORY_CAST_PTR(String_Quoted, s)) {
+        String_Quoted_Ptr cpy = SASS_MEMORY_COPY(ss);
         cpy->value(str);
         return cpy;
       } else {
-        return SASS_MEMORY_NEW(ctx.mem, String_Quoted, pstate, str);
+        return SASS_MEMORY_NEW(String_Quoted, pstate, str);
       }
     }
 
@@ -1077,26 +1092,26 @@
     Signature percentage_sig = "percentage($number)";
     BUILT_IN(percentage)
     {
-      Number* n = ARG("$number", Number);
+      Number_Ptr n = ARG("$number", Number);
       if (!n->is_unitless()) error("argument $number of `" + std::string(sig) + "` must be unitless", pstate);
-      return SASS_MEMORY_NEW(ctx.mem, Number, pstate, n->value() * 100, "%");
+      return SASS_MEMORY_NEW(Number, pstate, n->value() * 100, "%");
     }
 
     Signature round_sig = "round($number)";
     BUILT_IN(round)
     {
-      Number* n = ARG("$number", Number);
-      Number* r = SASS_MEMORY_NEW(ctx.mem, Number, *n);
+      Number_Ptr n = ARG("$number", Number);
+      Number_Ptr r = SASS_MEMORY_COPY(n);
       r->pstate(pstate);
-      r->value(Sass::round(r->value()));
+      r->value(Sass::round(r->value(), ctx.c_options.precision));
       return r;
     }
 
     Signature ceil_sig = "ceil($number)";
     BUILT_IN(ceil)
     {
-      Number* n = ARG("$number", Number);
-      Number* r = SASS_MEMORY_NEW(ctx.mem, Number, *n);
+      Number_Ptr n = ARG("$number", Number);
+      Number_Ptr r = SASS_MEMORY_COPY(n);
       r->pstate(pstate);
       r->value(std::ceil(r->value()));
       return r;
@@ -1105,8 +1120,8 @@
     Signature floor_sig = "floor($number)";
     BUILT_IN(floor)
     {
-      Number* n = ARG("$number", Number);
-      Number* r = SASS_MEMORY_NEW(ctx.mem, Number, *n);
+      Number_Ptr n = ARG("$number", Number);
+      Number_Ptr r = SASS_MEMORY_COPY(n);
       r->pstate(pstate);
       r->value(std::floor(r->value()));
       return r;
@@ -1115,8 +1130,8 @@
     Signature abs_sig = "abs($number)";
     BUILT_IN(abs)
     {
-      Number* n = ARG("$number", Number);
-      Number* r = SASS_MEMORY_NEW(ctx.mem, Number, *n);
+      Number_Ptr n = ARG("$number", Number);
+      Number_Ptr r = SASS_MEMORY_COPY(n);
       r->pstate(pstate);
       r->value(std::abs(r->value()));
       return r;
@@ -1125,61 +1140,67 @@
     Signature min_sig = "min($numbers...)";
     BUILT_IN(min)
     {
-      List* arglist = ARG("$numbers", List);
-      Number* least = 0;
+      List_Ptr arglist = ARG("$numbers", List);
+      Number_Obj least = NULL;
       for (size_t i = 0, L = arglist->length(); i < L; ++i) {
-        Number* xi = dynamic_cast<Number*>(arglist->value_at_index(i));
-        if (!xi) error("`" + std::string(sig) + "` only takes numeric arguments", pstate);
+        Expression_Obj val = arglist->value_at_index(i);
+        Number_Obj xi = SASS_MEMORY_CAST(Number, val);
+        if (!xi) {
+          error("\"" + val->to_string(ctx.c_options) + "\" is not a number for `min'", pstate);
+        }
         if (least) {
-          if (Eval::lt(xi, least)) least = xi;
+          if (*xi < *least) least = xi;
         } else least = xi;
       }
-      return least;
+      return least.detach();
     }
 
     Signature max_sig = "max($numbers...)";
     BUILT_IN(max)
     {
-      List* arglist = ARG("$numbers", List);
-      Number* greatest = 0;
+      List_Ptr arglist = ARG("$numbers", List);
+      Number_Obj greatest = NULL;
       for (size_t i = 0, L = arglist->length(); i < L; ++i) {
-        Number* xi = dynamic_cast<Number*>(arglist->value_at_index(i));
-        if (!xi) error("`" + std::string(sig) + "` only takes numeric arguments", pstate);
+        Expression_Obj val = arglist->value_at_index(i);
+        Number_Obj xi = SASS_MEMORY_CAST(Number, val);
+        if (!xi) {
+          error("\"" + val->to_string(ctx.c_options) + "\" is not a number for `max'", pstate);
+        }
         if (greatest) {
-          if (Eval::lt(greatest, xi)) greatest = xi;
+          if (*greatest < *xi) greatest = xi;
         } else greatest = xi;
       }
-      return greatest;
+      return greatest.detach();
     }
 
     Signature random_sig = "random($limit:false)";
     BUILT_IN(random)
     {
-      AST_Node* arg = env["$limit"];
-      Value* v = dynamic_cast<Value*>(arg);
-      Number* l = dynamic_cast<Number*>(arg);
-      Boolean* b = dynamic_cast<Boolean*>(arg);
+      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);
       if (l) {
         double v = l->value();
         if (v < 1) {
           stringstream err;
-          err << "$limit " << v << " must be greater than or equal to 1 for `random`";
+          err << "$limit " << v << " must be greater than or equal to 1 for `random'";
           error(err.str(), pstate);
         }
         bool eq_int = std::fabs(trunc(v) - v) < NUMBER_EPSILON;
         if (!eq_int) {
           stringstream err;
-          err << "Expected $limit to be an integer but got `" << v << "` for `random`";
+          err << "Expected $limit to be an integer but got " << v << " for `random'";
           error(err.str(), pstate);
         }
         std::uniform_real_distribution<> distributor(1, v + 1);
         uint_fast32_t distributed = static_cast<uint_fast32_t>(distributor(rand));
-        return SASS_MEMORY_NEW(ctx.mem, Number, pstate, (double)distributed);
+        return SASS_MEMORY_NEW(Number, pstate, (double)distributed);
       }
       else if (b) {
         std::uniform_real_distribution<> distributor(0, 1);
         double distributed = static_cast<double>(distributor(rand));
-        return SASS_MEMORY_NEW(ctx.mem, Number, pstate, distributed);
+        return SASS_MEMORY_NEW(Number, pstate, distributed);
       } else if (v) {
         throw Exception::InvalidArgumentType(pstate, "random", "$limit", "number", v);
       } else {
@@ -1195,26 +1216,26 @@
     Signature length_sig = "length($list)";
     BUILT_IN(length)
     {
-      if (Selector_List* sl = dynamic_cast<Selector_List*>(env["$list"])) {
-        return SASS_MEMORY_NEW(ctx.mem, Number, pstate, (double)sl->length());
+      if (Selector_List_Ptr sl = SASS_MEMORY_CAST(Selector_List, env["$list"])) {
+        return SASS_MEMORY_NEW(Number, pstate, (double)sl->length());
       }
-      Expression* v = ARG("$list", Expression);
+      Expression_Ptr v = ARG("$list", Expression);
       if (v->concrete_type() == Expression::MAP) {
-        Map* map = dynamic_cast<Map*>(env["$list"]);
-        return SASS_MEMORY_NEW(ctx.mem, Number, pstate, (double)(map ? map->length() : 1));
+        Map_Ptr map = SASS_MEMORY_CAST(Map, env["$list"]);
+        return SASS_MEMORY_NEW(Number, pstate, (double)(map ? map->length() : 1));
       }
       if (v->concrete_type() == Expression::SELECTOR) {
-        if (Compound_Selector* h = dynamic_cast<Compound_Selector*>(v)) {
-          return SASS_MEMORY_NEW(ctx.mem, Number, pstate, (double)h->length());
-        } else if (Selector_List* ls = dynamic_cast<Selector_List*>(v)) {
-          return SASS_MEMORY_NEW(ctx.mem, Number, pstate, (double)ls->length());
+        if (Compound_Selector_Ptr h = dynamic_cast<Compound_Selector_Ptr>(v)) {
+          return SASS_MEMORY_NEW(Number, pstate, (double)h->length());
+        } else if (Selector_List_Ptr ls = SASS_MEMORY_CAST_PTR(Selector_List, v)) {
+          return SASS_MEMORY_NEW(Number, pstate, (double)ls->length());
         } else {
-          return SASS_MEMORY_NEW(ctx.mem, Number, pstate, 1);
+          return SASS_MEMORY_NEW(Number, pstate, 1);
         }
       }
 
-      List* list = dynamic_cast<List*>(env["$list"]);
-      return SASS_MEMORY_NEW(ctx.mem, Number,
+      List_Ptr list = SASS_MEMORY_CAST(List, env["$list"]);
+      return SASS_MEMORY_NEW(Number,
                              pstate,
                              (double)(list ? list->size() : 1));
     }
@@ -1222,24 +1243,24 @@
     Signature nth_sig = "nth($list, $n)";
     BUILT_IN(nth)
     {
-      Number* n = ARG("$n", Number);
-      Map* m = dynamic_cast<Map*>(env["$list"]);
-      if (Selector_List* sl = dynamic_cast<Selector_List*>(env["$list"])) {
+      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"])) {
         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);
         // return (*sl)[static_cast<int>(index)];
-        Listize listize(ctx);
+        Listize listize;
         return (*sl)[static_cast<int>(index)]->perform(&listize);
       }
-      List* l = dynamic_cast<List*>(env["$list"]);
+      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);
       // if the argument isn't a list, then wrap it in a singleton list
       if (!m && !l) {
-        l = SASS_MEMORY_NEW(ctx.mem, List, pstate, 1);
-        *l << ARG("$list", Expression);
+        l = SASS_MEMORY_NEW(List, pstate, 1);
+        l->append(ARG("$list", Expression));
       }
       size_t len = m ? m->length() : l->length();
       bool empty = m ? m->empty() : l->empty();
@@ -1248,32 +1269,38 @@
       if (index < 0 || index > len - 1) error("index out of bounds for `" + std::string(sig) + "`", pstate);
 
       if (m) {
-        l = SASS_MEMORY_NEW(ctx.mem, List, pstate, 1);
-        *l << m->keys()[static_cast<unsigned int>(index)];
-        *l << m->at(m->keys()[static_cast<unsigned int>(index)]);
-        return l;
+        l = SASS_MEMORY_NEW(List, pstate, 1);
+        l->append(m->keys()[static_cast<unsigned int>(index)]);
+        l->append(m->at(m->keys()[static_cast<unsigned int>(index)]));
+        return l.detach();
       }
       else {
-        return l->value_at_index(static_cast<int>(index));
+        Expression_Obj rv = l->value_at_index(static_cast<int>(index));
+        rv->set_delayed(false);
+        return rv.detach();
       }
     }
 
     Signature set_nth_sig = "set-nth($list, $n, $value)";
     BUILT_IN(set_nth)
     {
-      List* l = dynamic_cast<List*>(env["$list"]);
-      Number* n = ARG("$n", Number);
-      Expression* v = ARG("$value", Expression);
+      Map_Obj m = SASS_MEMORY_CAST(Map, env["$list"]);
+      List_Obj l = SASS_MEMORY_CAST(List, env["$list"]);
+      Number_Obj n = ARG("$n", Number);
+      Expression_Obj v = ARG("$value", Expression);
       if (!l) {
-        l = SASS_MEMORY_NEW(ctx.mem, List, pstate, 1);
-        *l << ARG("$list", Expression);
+        l = SASS_MEMORY_NEW(List, pstate, 1);
+        l->append(ARG("$list", Expression));
       }
+      if (m) {
+        l = m->to_list(ctx, pstate);
+      }
       if (l->empty()) error("argument `$list` of `" + std::string(sig) + "` must not be empty", pstate);
       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* result = SASS_MEMORY_NEW(ctx.mem, List, pstate, l->length(), l->separator());
+      List_Ptr result = SASS_MEMORY_NEW(List, pstate, l->length(), l->separator());
       for (size_t i = 0, L = l->length(); i < L; ++i) {
-        *result << ((i == index) ? v : (*l)[i]);
+        result->append(((i == index) ? v : (*l)[i]));
       }
       return result;
     }
@@ -1281,77 +1308,93 @@
     Signature index_sig = "index($list, $value)";
     BUILT_IN(index)
     {
-      List* l = dynamic_cast<List*>(env["$list"]);
-      Expression* v = ARG("$value", Expression);
+      Map_Obj m = SASS_MEMORY_CAST(Map, env["$list"]);
+      List_Obj l = SASS_MEMORY_CAST(List, env["$list"]);
+      Expression_Obj v = ARG("$value", Expression);
       if (!l) {
-        l = SASS_MEMORY_NEW(ctx.mem, List, pstate, 1);
-        *l << ARG("$list", Expression);
+        l = SASS_MEMORY_NEW(List, pstate, 1);
+        l->append(ARG("$list", Expression));
       }
+      if (m) {
+        l = m->to_list(ctx, 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(ctx.mem, Number, pstate, (double)(i+1));
+        if (Eval::eq(l->value_at_index(i), v)) return SASS_MEMORY_NEW(Number, pstate, (double)(i+1));
       }
-      return SASS_MEMORY_NEW(ctx.mem, Null, pstate);
+      return SASS_MEMORY_NEW(Null, pstate);
     }
 
     Signature join_sig = "join($list1, $list2, $separator: auto)";
     BUILT_IN(join)
     {
-      List* l1 = dynamic_cast<List*>(env["$list1"]);
-      List* l2 = dynamic_cast<List*>(env["$list2"]);
-      String_Constant* sep = ARG("$separator", String_Constant);
+      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"]);
+      String_Constant_Obj sep = ARG("$separator", String_Constant);
       enum Sass_Separator sep_val = (l1 ? l1->separator() : SASS_SPACE);
       if (!l1) {
-        l1 = SASS_MEMORY_NEW(ctx.mem, List, pstate, 1);
-        *l1 << ARG("$list1", Expression);
+        l1 = SASS_MEMORY_NEW(List, pstate, 1);
+        l1->append(ARG("$list1", Expression));
         sep_val = (l2 ? l2->separator() : SASS_SPACE);
       }
       if (!l2) {
-        l2 = SASS_MEMORY_NEW(ctx.mem, List, pstate, 1);
-        *l2 << ARG("$list2", Expression);
+        l2 = SASS_MEMORY_NEW(List, pstate, 1);
+        l2->append(ARG("$list2", Expression));
       }
+      if (m1) {
+        l1 = m1->to_list(ctx, pstate);
+        sep_val = SASS_COMMA;
+      }
+      if (m2) {
+        l2 = m2->to_list(ctx, 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* result = SASS_MEMORY_NEW(ctx.mem, List, pstate, len, sep_val);
-      *result += l1;
-      *result += l2;
-      return result;
+      List_Obj result = SASS_MEMORY_NEW(List, pstate, len, sep_val);
+      result->concat(&l1);
+      result->concat(&l2);
+      return result.detach();
     }
 
     Signature append_sig = "append($list, $val, $separator: auto)";
     BUILT_IN(append)
     {
-      List* l = dynamic_cast<List*>(env["$list"]);
-      Expression* v = ARG("$val", Expression);
-      if (Selector_List* sl = dynamic_cast<Selector_List*>(env["$list"])) {
-        Listize listize(ctx);
-        l = dynamic_cast<List*>(sl->perform(&listize));
+      Map_Obj m = SASS_MEMORY_CAST(Map, env["$list"]);
+      List_Obj l = SASS_MEMORY_CAST(List, env["$list"]);
+      Expression_Obj v = ARG("$val", Expression);
+      if (Selector_List_Ptr sl = SASS_MEMORY_CAST(Selector_List, env["$list"])) {
+        Listize listize;
+        l = SASS_MEMORY_CAST_PTR(List, sl->perform(&listize));
       }
-      String_Constant* sep = ARG("$separator", String_Constant);
+      String_Constant_Obj sep = ARG("$separator", String_Constant);
       if (!l) {
-        l = SASS_MEMORY_NEW(ctx.mem, List, pstate, 1);
-        *l << ARG("$list", Expression);
+        l = SASS_MEMORY_NEW(List, pstate, 1);
+        l->append(ARG("$list", Expression));
       }
-      List* result = SASS_MEMORY_NEW(ctx.mem, List, pstate, l->length() + 1, l->separator());
+      if (m) {
+        l = m->to_list(ctx, pstate);
+      }
+      List_Ptr result = SASS_MEMORY_COPY(l);
       std::string sep_str(unquote(sep->value()));
-      if (sep_str == "space") result->separator(SASS_SPACE);
-      else if (sep_str == "comma") result->separator(SASS_COMMA);
-      else if (sep_str != "auto") error("argument `$separator` of `" + std::string(sig) + "` must be `space`, `comma`, or `auto`", pstate);
-      *result += l;
-      bool is_arglist = l->is_arglist();
-      result->is_arglist(is_arglist);
-      if (is_arglist) {
-        *result << SASS_MEMORY_NEW(ctx.mem, Argument,
-                                   v->pstate(),
-                                   v,
-                                   "",
-                                   false,
-                                   false);
+      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);
+      }
+      if (l->is_arglist()) {
+        result->append(SASS_MEMORY_NEW(Argument,
+                                       v->pstate(),
+                                       v,
+                                       "",
+                                       false,
+                                       false));
 
       } else {
-        *result << v;
+        result->append(v);
       }
       return result;
     }
@@ -1359,29 +1402,35 @@
     Signature zip_sig = "zip($lists...)";
     BUILT_IN(zip)
     {
-      List* arglist = SASS_MEMORY_NEW(ctx.mem, List, *ARG("$lists", List));
+      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* ith = dynamic_cast<List*>(arglist->value_at_index(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));
         if (!ith) {
-          ith = SASS_MEMORY_NEW(ctx.mem, List, pstate, 1);
-          *ith << arglist->value_at_index(i);
+          if (mith) {
+            ith = mith->to_list(ctx, pstate);
+          } else {
+            ith = SASS_MEMORY_NEW(List, pstate, 1);
+            ith->append(arglist->value_at_index(i));
+          }
           if (arglist->is_arglist()) {
-            ((Argument*)(*arglist)[i])->value(ith);
+            Argument_Obj arg = (Argument_Ptr)(&arglist->at(i));
+            arg->value(&ith);
           } else {
-            (*arglist)[i] = ith;
+            (*arglist)[i] = &ith;
           }
         }
         shortest = (i ? std::min(shortest, ith->length()) : ith->length());
       }
-      List* zippers = SASS_MEMORY_NEW(ctx.mem, List, pstate, shortest, SASS_COMMA);
+      List_Ptr zippers = SASS_MEMORY_NEW(List, pstate, shortest, SASS_COMMA);
       size_t L = arglist->length();
       for (size_t i = 0; i < shortest; ++i) {
-        List* zipper = SASS_MEMORY_NEW(ctx.mem, List, pstate, L);
+        List_Ptr zipper = SASS_MEMORY_NEW(List, pstate, L);
         for (size_t j = 0; j < L; ++j) {
-          *zipper << (*static_cast<List*>(arglist->value_at_index(j)))[i];
+          zipper->append(SASS_MEMORY_CAST(List, arglist->value_at_index(j))->at(i));
         }
-        *zippers << zipper;
+        zippers->append(zipper);
       }
       return zippers;
     }
@@ -1389,12 +1438,12 @@
     Signature list_separator_sig = "list_separator($list)";
     BUILT_IN(list_separator)
     {
-      List* l = dynamic_cast<List*>(env["$list"]);
+      List_Obj l = SASS_MEMORY_CAST(List, env["$list"]);
       if (!l) {
-        l = SASS_MEMORY_NEW(ctx.mem, List, pstate, 1);
-        *l << ARG("$list", Expression);
+        l = SASS_MEMORY_NEW(List, pstate, 1);
+        l->append(ARG("$list", Expression));
       }
-      return SASS_MEMORY_NEW(ctx.mem, String_Quoted,
+      return SASS_MEMORY_NEW(String_Quoted,
                                pstate,
                                l->separator() == SASS_COMMA ? "comma" : "space");
     }
@@ -1406,12 +1455,15 @@
     Signature map_get_sig = "map-get($map, $key)";
     BUILT_IN(map_get)
     {
-      Map* m = ARGM("$map", Map, ctx);
-      Expression* v = ARG("$key", Expression);
+      // leaks for "map-get((), foo)" if not Obj
+      // investigate why this is (unexpected)
+      Map_Obj m = ARGM("$map", Map, ctx);
+      Expression_Obj v = ARG("$key", Expression);
       try {
-        return m->at(v);
+        Expression_Obj val = m->at(v); // XXX
+        return val ? val.detach() : SASS_MEMORY_NEW(Null, pstate);
       } catch (const std::out_of_range&) {
-        return SASS_MEMORY_NEW(ctx.mem, Null, pstate);
+        return SASS_MEMORY_NEW(Null, pstate);
       }
       catch (...) { throw; }
     }
@@ -1419,18 +1471,18 @@
     Signature map_has_key_sig = "map-has-key($map, $key)";
     BUILT_IN(map_has_key)
     {
-      Map* m = ARGM("$map", Map, ctx);
-      Expression* v = ARG("$key", Expression);
-      return SASS_MEMORY_NEW(ctx.mem, Boolean, pstate, m->has(v));
+      Map_Obj m = ARGM("$map", Map, ctx);
+      Expression_Obj v = ARG("$key", Expression);
+      return SASS_MEMORY_NEW(Boolean, pstate, m->has(v));
     }
 
     Signature map_keys_sig = "map-keys($map)";
     BUILT_IN(map_keys)
     {
-      Map* m = ARGM("$map", Map, ctx);
-      List* result = SASS_MEMORY_NEW(ctx.mem, List, pstate, m->length(), SASS_COMMA);
+      Map_Obj m = ARGM("$map", Map, ctx);
+      List_Ptr result = SASS_MEMORY_NEW(List, pstate, m->length(), SASS_COMMA);
       for ( auto key : m->keys()) {
-        *result << key;
+        result->append(key);
       }
       return result;
     }
@@ -1438,10 +1490,10 @@
     Signature map_values_sig = "map-values($map)";
     BUILT_IN(map_values)
     {
-      Map* m = ARGM("$map", Map, ctx);
-      List* result = SASS_MEMORY_NEW(ctx.mem, List, pstate, m->length(), SASS_COMMA);
+      Map_Obj m = ARGM("$map", Map, ctx);
+      List_Ptr result = SASS_MEMORY_NEW(List, pstate, m->length(), SASS_COMMA);
       for ( auto key : m->keys()) {
-        *result << m->at(key);
+        result->append(m->at(key));
       }
       return result;
     }
@@ -1449,13 +1501,14 @@
     Signature map_merge_sig = "map-merge($map1, $map2)";
     BUILT_IN(map_merge)
     {
-      Map* m1 = ARGM("$map1", Map, ctx);
-      Map* m2 = ARGM("$map2", Map, ctx);
+      Map_Obj m1 = ARGM("$map1", Map, ctx);
+      Map_Obj m2 = ARGM("$map2", Map, ctx);
 
       size_t len = m1->length() + m2->length();
-      Map* result = SASS_MEMORY_NEW(ctx.mem, Map, pstate, len);
-      *result += m1;
-      *result += m2;
+      Map_Ptr result = SASS_MEMORY_NEW(Map, pstate, len);
+      // concat not implemented for maps
+      *result += &m1;
+      *result += &m2;
       return result;
     }
 
@@ -1463,9 +1516,9 @@
     BUILT_IN(map_remove)
     {
       bool remove;
-      Map* m = ARGM("$map", Map, ctx);
-      List* arglist = ARG("$keys", List);
-      Map* result = SASS_MEMORY_NEW(ctx.mem, Map, pstate, 1);
+      Map_Obj m = ARGM("$map", Map, ctx);
+      List_Obj arglist = ARG("$keys", List);
+      Map_Ptr result = SASS_MEMORY_NEW(Map, pstate, 1);
       for (auto key : m->keys()) {
         remove = false;
         for (size_t j = 0, K = arglist->length(); j < K && !remove; ++j) {
@@ -1479,16 +1532,18 @@
     Signature keywords_sig = "keywords($args)";
     BUILT_IN(keywords)
     {
-      List* arglist = SASS_MEMORY_NEW(ctx.mem, List, *ARG("$args", List));
-      Map* result = SASS_MEMORY_NEW(ctx.mem, Map, pstate, 1);
+      List_Obj arglist = SASS_MEMORY_COPY(ARG("$args", List)); // copy
+      Map_Obj result = SASS_MEMORY_NEW(Map, pstate, 1);
       for (size_t i = arglist->size(), L = arglist->length(); i < L; ++i) {
-        std::string name = std::string(((Argument*)(*arglist)[i])->name());
+        Expression_Obj obj = arglist->at(i);
+        Argument_Obj arg = (Argument_Ptr)&obj;
+        std::string name = std::string(arg->name());
         name = name.erase(0, 1); // sanitize name (remove dollar sign)
-        *result << std::make_pair(SASS_MEMORY_NEW(ctx.mem, String_Quoted,
+        *result << std::make_pair(SASS_MEMORY_NEW(String_Quoted,
                  pstate, name),
-                 ((Argument*)(*arglist)[i])->value());
+                 arg->value());
       }
-      return result;
+      return result.detach();
     }
 
     //////////////////////////
@@ -1498,29 +1553,29 @@
     Signature type_of_sig = "type-of($value)";
     BUILT_IN(type_of)
     {
-      Expression* v = ARG("$value", Expression);
-      return SASS_MEMORY_NEW(ctx.mem, String_Quoted, pstate, v->type());
+      Expression_Ptr v = ARG("$value", Expression);
+      return SASS_MEMORY_NEW(String_Quoted, pstate, v->type());
     }
 
     Signature unit_sig = "unit($number)";
     BUILT_IN(unit)
-    { return SASS_MEMORY_NEW(ctx.mem, String_Quoted, pstate, quote(ARG("$number", Number)->unit(), '"')); }
+    { return SASS_MEMORY_NEW(String_Quoted, pstate, quote(ARG("$number", Number)->unit(), '"')); }
 
     Signature unitless_sig = "unitless($number)";
     BUILT_IN(unitless)
-    { return SASS_MEMORY_NEW(ctx.mem, Boolean, pstate, ARG("$number", Number)->is_unitless()); }
+    { return SASS_MEMORY_NEW(Boolean, pstate, ARG("$number", Number)->is_unitless()); }
 
     Signature comparable_sig = "comparable($number-1, $number-2)";
     BUILT_IN(comparable)
     {
-      Number* n1 = ARG("$number-1", Number);
-      Number* n2 = ARG("$number-2", Number);
+      Number_Ptr n1 = ARG("$number-1", Number);
+      Number_Ptr n2 = ARG("$number-2", Number);
       if (n1->is_unitless() || n2->is_unitless()) {
-        return SASS_MEMORY_NEW(ctx.mem, Boolean, pstate, true);
+        return SASS_MEMORY_NEW(Boolean, pstate, true);
       }
-      Number tmp_n2(*n2);
+      Number tmp_n2(n2); // copy
       tmp_n2.normalize(n1->find_convertible_unit());
-      return SASS_MEMORY_NEW(ctx.mem, Boolean, pstate, n1->unit() == tmp_n2.unit());
+      return SASS_MEMORY_NEW(Boolean, pstate, n1->unit() == tmp_n2.unit());
     }
 
     Signature variable_exists_sig = "variable-exists($name)";
@@ -1529,10 +1584,10 @@
       std::string s = Util::normalize_underscores(unquote(ARG("$name", String_Constant)->value()));
 
       if(d_env.has("$"+s)) {
-        return SASS_MEMORY_NEW(ctx.mem, Boolean, pstate, true);
+        return SASS_MEMORY_NEW(Boolean, pstate, true);
       }
       else {
-        return SASS_MEMORY_NEW(ctx.mem, Boolean, pstate, false);
+        return SASS_MEMORY_NEW(Boolean, pstate, false);
       }
     }
 
@@ -1542,10 +1597,10 @@
       std::string s = Util::normalize_underscores(unquote(ARG("$name", String_Constant)->value()));
 
       if(d_env.has_global("$"+s)) {
-        return SASS_MEMORY_NEW(ctx.mem, Boolean, pstate, true);
+        return SASS_MEMORY_NEW(Boolean, pstate, true);
       }
       else {
-        return SASS_MEMORY_NEW(ctx.mem, Boolean, pstate, false);
+        return SASS_MEMORY_NEW(Boolean, pstate, false);
       }
     }
 
@@ -1555,10 +1610,10 @@
       std::string s = Util::normalize_underscores(unquote(ARG("$name", String_Constant)->value()));
 
       if(d_env.has_global(s+"[f]")) {
-        return SASS_MEMORY_NEW(ctx.mem, Boolean, pstate, true);
+        return SASS_MEMORY_NEW(Boolean, pstate, true);
       }
       else {
-        return SASS_MEMORY_NEW(ctx.mem, Boolean, pstate, false);
+        return SASS_MEMORY_NEW(Boolean, pstate, false);
       }
     }
 
@@ -1568,10 +1623,10 @@
       std::string s = Util::normalize_underscores(unquote(ARG("$name", String_Constant)->value()));
 
       if(d_env.has_global(s+"[m]")) {
-        return SASS_MEMORY_NEW(ctx.mem, Boolean, pstate, true);
+        return SASS_MEMORY_NEW(Boolean, pstate, true);
       }
       else {
-        return SASS_MEMORY_NEW(ctx.mem, Boolean, pstate, false);
+        return SASS_MEMORY_NEW(Boolean, pstate, false);
       }
     }
 
@@ -1581,10 +1636,10 @@
       std::string s = unquote(ARG("$name", String_Constant)->value());
 
       if(features.find(s) == features.end()) {
-        return SASS_MEMORY_NEW(ctx.mem, Boolean, pstate, false);
+        return SASS_MEMORY_NEW(Boolean, pstate, false);
       }
       else {
-        return SASS_MEMORY_NEW(ctx.mem, Boolean, pstate, true);
+        return SASS_MEMORY_NEW(Boolean, pstate, true);
       }
     }
 
@@ -1592,34 +1647,36 @@
     BUILT_IN(call)
     {
       std::string name = Util::normalize_underscores(unquote(ARG("$name", String_Constant)->value()));
-      List* arglist = SASS_MEMORY_NEW(ctx.mem, List, *ARG("$args", List));
+      List_Obj arglist = SASS_MEMORY_COPY(ARG("$args", List));
 
-      Arguments* args = SASS_MEMORY_NEW(ctx.mem, Arguments, pstate);
+      Arguments_Obj args = SASS_MEMORY_NEW(Arguments, pstate);
       // std::string full_name(name + "[f]");
-      // Definition* def = d_env.has(full_name) ? static_cast<Definition*>((d_env)[full_name]) : 0;
-      // Parameters* params = def ? def->parameters() : 0;
+      // Definition_Ptr def = d_env.has(full_name) ? static_cast<Definition_Ptr>((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* expr = arglist->value_at_index(i);
+        Expression_Obj expr = arglist->value_at_index(i);
         // if (params && params->has_rest_parameter()) {
-        //   Parameter* p = param_size > i ? (*params)[i] : 0;
-        //   List* list = dynamic_cast<List*>(expr);
+        //   Parameter_Obj p = param_size > i ? (*params)[i] : 0;
+        //   List_Ptr list = SASS_MEMORY_CAST(List, expr);
         //   if (list && p && !p->is_rest_parameter()) expr = (*list)[0];
         // }
         if (arglist->is_arglist()) {
-          Argument* arg = dynamic_cast<Argument*>((*arglist)[i]);
-          *args << SASS_MEMORY_NEW(ctx.mem, Argument,
-                                   pstate,
-                                   expr,
-                                   arg ? arg->name() : "",
-                                   arg ? arg->is_rest_argument() : false,
-                                   arg ? arg->is_keyword_argument() : false);
+          Expression_Obj obj = arglist->at(i);
+          Argument_Obj arg = (Argument_Ptr)&obj;
+          args->append(SASS_MEMORY_NEW(Argument,
+                                       pstate,
+                                       expr,
+                                       arg ? arg->name() : "",
+                                       arg ? arg->is_rest_argument() : false,
+                                       arg ? arg->is_keyword_argument() : false));
         } else {
-          *args << SASS_MEMORY_NEW(ctx.mem, Argument, pstate, expr);
+          args->append(SASS_MEMORY_NEW(Argument, pstate, expr));
         }
       }
-      Function_Call* func = SASS_MEMORY_NEW(ctx.mem, Function_Call, pstate, name, args);
-      Expand expand(ctx, &d_env, backtrace);
+      Function_Call_Obj func = SASS_MEMORY_NEW(Function_Call, pstate, name, &args);
+      Expand expand(ctx, &d_env, backtrace, &selector_stack);
+      func->via_call(true); // calc invoke is allowed
       return func->perform(&expand.eval);
 
     }
@@ -1630,21 +1687,22 @@
 
     Signature not_sig = "not($value)";
     BUILT_IN(sass_not)
-    { return SASS_MEMORY_NEW(ctx.mem, Boolean, pstate, ARG("$value", Expression)->is_false()); }
+    {
+      return SASS_MEMORY_NEW(Boolean, pstate, ARG("$value", Expression)->is_false());
+    }
 
     Signature if_sig = "if($condition, $if-true, $if-false)";
     // BUILT_IN(sass_if)
     // { return ARG("$condition", Expression)->is_false() ? ARG("$if-false", Expression) : ARG("$if-true", Expression); }
     BUILT_IN(sass_if)
     {
-      Expand expand(ctx, &d_env, backtrace);
-      bool is_true = !ARG("$condition", Expression)->perform(&expand.eval)->is_false();
-      if (is_true) {
-        return ARG("$if-true", Expression)->perform(&expand.eval);
-      }
-      else {
-        return ARG("$if-false", Expression)->perform(&expand.eval);
-      }
+      Expand expand(ctx, &d_env, backtrace, &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);
+      res = res->perform(&expand.eval);
+      res->set_delayed(false); // clone?
+      return res;
     }
 
     ////////////////
@@ -1662,117 +1720,126 @@
     // MISCELLANEOUS FUNCTIONS
     //////////////////////////
 
+    // value.check_deprecated_interp if value.is_a?(Sass::Script::Value::String)
+    // unquoted_string(value.to_sass)
+
     Signature inspect_sig = "inspect($value)";
     BUILT_IN(inspect)
     {
-      Expression* v = ARG("$value", Expression);
+      Expression_Ptr v = ARG("$value", Expression);
       if (v->concrete_type() == Expression::NULL_VAL) {
-        return SASS_MEMORY_NEW(ctx.mem, String_Quoted, pstate, "null");
-      } else if (v->concrete_type() == Expression::BOOLEAN && *v == 0) {
-        return SASS_MEMORY_NEW(ctx.mem, String_Quoted, pstate, "false");
+        return SASS_MEMORY_NEW(String_Quoted, pstate, "null");
+      } else if (v->concrete_type() == Expression::BOOLEAN && v->is_false()) {
+        return SASS_MEMORY_NEW(String_Quoted, pstate, "false");
       } else if (v->concrete_type() == Expression::STRING) {
         return v;
       } else {
-        bool parentheses = v->concrete_type() == Expression::MAP ||
-                           v->concrete_type() == Expression::LIST;
+        // ToDo: fix to_sass for nested parentheses
         Sass_Output_Style old_style;
-        old_style = ctx.c_options->output_style;
-        ctx.c_options->output_style = SASS_STYLE_NESTED;
-        To_String to_string(&ctx, false);
-        std::string inspect = v->perform(&to_string);
-        if (inspect.empty() && parentheses) inspect = "()";
-        ctx.c_options->output_style = old_style;
-        return SASS_MEMORY_NEW(ctx.mem, String_Quoted, pstate, inspect);
+        old_style = ctx.c_options.output_style;
+        ctx.c_options.output_style = TO_SASS;
+        Emitter emitter(ctx.c_options);
+        Inspect i(emitter);
+        i.in_declaration = false;
+        v->perform(&i);
+        ctx.c_options.output_style = old_style;
+        return SASS_MEMORY_NEW(String_Quoted, pstate, i.get_buffer());
       }
       // return v;
     }
     Signature selector_nest_sig = "selector-nest($selectors...)";
     BUILT_IN(selector_nest)
     {
-      To_String to_string(&ctx, false);
-      List* arglist = ARG("$selectors", List);
+      List_Ptr arglist = ARG("$selectors", List);
 
       // Not enough parameters
       if( arglist->length() == 0 )
-        error("$selectors: At least one selector must be passed", pstate);
+        error("$selectors: At least one selector must be passed for `selector-nest'", pstate);
 
       // Parse args into vector of selectors
-      std::vector<Selector_List*> parsedSelectors;
+      std::vector<Selector_List_Obj> parsedSelectors;
       for (size_t i = 0, L = arglist->length(); i < L; ++i) {
-        Expression* exp = dynamic_cast<Expression*>(arglist->value_at_index(i));
+        Expression_Obj exp = SASS_MEMORY_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);
         }
-        std::string exp_src = exp->perform(&to_string) + "{";
-        Selector_List* sel = Parser::parse_selector(exp_src.c_str(), ctx);
-        parsedSelectors.push_back(sel);
+        if (String_Constant_Obj str = SASS_MEMORY_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);
       }
 
       // Nothing to do
       if( parsedSelectors.empty() ) {
-        return SASS_MEMORY_NEW(ctx.mem, Null, pstate);
+        return SASS_MEMORY_NEW(Null, pstate);
       }
 
       // Set the first element as the `result`, keep appending to as we go down the parsedSelector vector.
-      std::vector<Selector_List*>::iterator itr = parsedSelectors.begin();
-      Selector_List* result = *itr;
+      std::vector<Selector_List_Obj>::iterator itr = parsedSelectors.begin();
+      Selector_List_Obj result = *itr;
       ++itr;
 
       for(;itr != parsedSelectors.end(); ++itr) {
-        Selector_List* child = *itr;
-        std::vector<Complex_Selector*> exploded;
-        Selector_List* rv = child->parentize(result, ctx);
+        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.pop_back();
         for (size_t m = 0, mLen = rv->length(); m < mLen; ++m) {
           exploded.push_back((*rv)[m]);
         }
         result->elements(exploded);
       }
 
-      Listize listize(ctx);
+      Listize listize;
       return result->perform(&listize);
     }
 
     Signature selector_append_sig = "selector-append($selectors...)";
     BUILT_IN(selector_append)
     {
-      To_String to_string;
-      List* arglist = ARG("$selectors", List);
+      List_Ptr arglist = ARG("$selectors", List);
 
       // Not enough parameters
       if( arglist->length() == 0 )
-        error("$selectors: At least one selector must be passed", pstate);
+        error("$selectors: At least one selector must be passed for `selector-append'", pstate);
 
       // Parse args into vector of selectors
-      std::vector<Selector_List*> parsedSelectors;
+      std::vector<Selector_List_Obj> parsedSelectors;
       for (size_t i = 0, L = arglist->length(); i < L; ++i) {
-        Expression* exp = dynamic_cast<Expression*>(arglist->value_at_index(i));
+        Expression_Obj exp = SASS_MEMORY_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);
         }
-        std::string exp_src = exp->perform(&to_string) + "{";
-        Selector_List* sel = Parser::parse_selector(exp_src.c_str(), ctx);
-        parsedSelectors.push_back(sel);
+        if (String_Constant_Ptr str = SASS_MEMORY_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);
       }
 
       // Nothing to do
       if( parsedSelectors.empty() ) {
-        return SASS_MEMORY_NEW(ctx.mem, Null, pstate);
+        return SASS_MEMORY_NEW(Null, pstate);
       }
 
       // Set the first element as the `result`, keep appending to as we go down the parsedSelector vector.
-      std::vector<Selector_List*>::iterator itr = parsedSelectors.begin();
-      Selector_List* result = *itr;
+      std::vector<Selector_List_Obj>::iterator itr = parsedSelectors.begin();
+      Selector_List_Obj result = *itr;
       ++itr;
 
       for(;itr != parsedSelectors.end(); ++itr) {
-        Selector_List* child = *itr;
-        std::vector<Complex_Selector*> newElements;
+        Selector_List_Obj child = *itr;
+        std::vector<Complex_Selector_Obj> newElements;
 
         // For every COMPLEX_SELECTOR in `result`
         // For every COMPLEX_SELECTOR in `child`
@@ -1783,74 +1850,73 @@
         // Replace result->elements with newElements
         for (size_t i = 0, resultLen = result->length(); i < resultLen; ++i) {
           for (size_t j = 0, childLen = child->length(); j < childLen; ++j) {
-            Complex_Selector* parentSeqClone = (*result)[i]->cloneFully(ctx);
-            Complex_Selector* childSeq = (*child)[j];
-            Complex_Selector* base = childSeq->tail();
+            Complex_Selector_Obj parentSeqClone = SASS_MEMORY_CLONE((*result)[i]);
+            Complex_Selector_Obj childSeq = (*child)[j];
+            Complex_Selector_Obj base = childSeq->tail();
 
             // Must be a simple sequence
             if( childSeq->combinator() != Complex_Selector::Combinator::ANCESTOR_OF ) {
-              std::string msg("Can't append  `");
-              msg += childSeq->perform(&to_string);
-              msg += "` to `";
-              msg += parentSeqClone->perform(&to_string);;
-              msg += "`";
+              std::string msg("Can't append \"");
+              msg += childSeq->to_string();
+              msg += "\" to \"";
+              msg += parentSeqClone->to_string();
+              msg += "\" for `selector-append'";
               error(msg, pstate, backtrace);
             }
 
             // Cannot be a Universal selector
-            Type_Selector* pType = dynamic_cast<Type_Selector*>(base->head()->first());
+            Element_Selector_Obj pType = SASS_MEMORY_CAST(Element_Selector, childSeq->head()->first());
             if(pType && pType->name() == "*") {
-              std::string msg("Can't append  `");
-              msg += childSeq->perform(&to_string);
-              msg += "` to `";
-              msg += parentSeqClone->perform(&to_string);;
-              msg += "`";
+              std::string msg("Can't append \"");
+              msg += childSeq->to_string();
+              msg += "\" to \"";
+              msg += parentSeqClone->to_string();
+              msg += "\" for `selector-append'";
               error(msg, pstate, backtrace);
             }
 
             // TODO: Add check for namespace stuff
 
             // append any selectors in childSeq's head
-            *(parentSeqClone->innermost()->head()) += (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);
           }
         }
 
         result->elements(newElements);
       }
 
-      Listize listize(ctx);
+      Listize listize;
       return result->perform(&listize);
     }
 
     Signature selector_unify_sig = "selector-unify($selector1, $selector2)";
     BUILT_IN(selector_unify)
     {
-      Selector_List* selector1 = ARGSEL("$selector1", Selector_List, p_contextualize);
-      Selector_List* selector2 = ARGSEL("$selector2", Selector_List, p_contextualize);
+      Selector_List_Obj selector1 = ARGSEL("$selector1", Selector_List_Obj, p_contextualize);
+      Selector_List_Obj selector2 = ARGSEL("$selector2", Selector_List_Obj, p_contextualize);
 
-      Selector_List* result = selector1->unify_with(selector2, ctx);
-      Listize listize(ctx);
+      Selector_List_Obj result = selector1->unify_with(&selector2, ctx);
+      Listize listize;
       return result->perform(&listize);
     }
 
     Signature simple_selectors_sig = "simple-selectors($selector)";
     BUILT_IN(simple_selectors)
     {
-      Compound_Selector* sel = ARGSEL("$selector", Compound_Selector, p_contextualize);
+      Compound_Selector_Obj sel = ARGSEL("$selector", Compound_Selector_Obj, p_contextualize);
 
-      To_String to_string;
-      List* l = SASS_MEMORY_NEW(ctx.mem, List, sel->pstate(), sel->length(), SASS_COMMA);
+      List_Ptr l = SASS_MEMORY_NEW(List, sel->pstate(), sel->length(), SASS_COMMA);
 
       for (size_t i = 0, L = sel->length(); i < L; ++i) {
-        Simple_Selector* ss = (*sel)[i];
-        std::string ss_string = ss->perform(&to_string) ;
+        Simple_Selector_Obj ss = (*sel)[i];
+        std::string ss_string = ss->to_string() ;
 
-        *l << SASS_MEMORY_NEW(ctx.mem, String_Quoted, ss->pstate(), ss_string);
+        l->append(SASS_MEMORY_NEW(String_Quoted, ss->pstate(), ss_string));
       }
 
       return l;
@@ -1859,54 +1925,50 @@
     Signature selector_extend_sig = "selector-extend($selector, $extendee, $extender)";
     BUILT_IN(selector_extend)
     {
-      Selector_List*  selector = ARGSEL("$selector", Selector_List, p_contextualize);
-      Selector_List*  extendee = ARGSEL("$extendee", Selector_List, p_contextualize);
-      Selector_List*  extender = ARGSEL("$extender", Selector_List, p_contextualize);
+      Selector_List_Obj  selector = ARGSEL("$selector", Selector_List_Obj, p_contextualize);
+      Selector_List_Obj  extendee = ARGSEL("$extendee", Selector_List_Obj, p_contextualize);
+      Selector_List_Obj  extender = ARGSEL("$extender", Selector_List_Obj, p_contextualize);
 
-      ExtensionSubsetMap subset_map;
+      Subset_Map subset_map;
       extender->populate_extends(extendee, ctx, subset_map);
 
-      bool extendedSomething;
-      Selector_List* result = Extend::extendSelectorList(selector, ctx, subset_map, false, extendedSomething);
+      Selector_List_Obj result = Extend::extendSelectorList(selector, ctx, subset_map, false);
 
-      Listize listize(ctx);
+      Listize listize;
       return result->perform(&listize);
     }
 
     Signature selector_replace_sig = "selector-replace($selector, $original, $replacement)";
     BUILT_IN(selector_replace)
     {
-      Selector_List*  selector = ARGSEL("$selector", Selector_List, p_contextualize);
-      Selector_List*  original = ARGSEL("$original", Selector_List, p_contextualize);
-      Selector_List*  replacement = ARGSEL("$replacement", Selector_List, p_contextualize);
-
-      ExtensionSubsetMap subset_map;
+      Selector_List_Obj selector = ARGSEL("$selector", Selector_List_Obj, p_contextualize);
+      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);
 
-      bool extendedSomething;
-      Selector_List* result = Extend::extendSelectorList(selector, ctx, subset_map, true, extendedSomething);
+      Selector_List_Obj result = Extend::extendSelectorList(selector, ctx, subset_map, true);
 
-      Listize listize(ctx);
+      Listize listize;
       return result->perform(&listize);
     }
 
     Signature selector_parse_sig = "selector-parse($selector)";
     BUILT_IN(selector_parse)
     {
-      Selector_List* sel = ARGSEL("$selector", Selector_List, p_contextualize);
+      Selector_List_Obj sel = ARGSEL("$selector", Selector_List_Obj, p_contextualize);
 
-      Listize listize(ctx);
+      Listize listize;
       return sel->perform(&listize);
     }
 
     Signature is_superselector_sig = "is-superselector($super, $sub)";
     BUILT_IN(is_superselector)
     {
-      To_String to_string(&ctx, false);
-      Selector_List*  sel_sup = ARGSEL("$super", Selector_List, p_contextualize);
-      Selector_List*  sel_sub = ARGSEL("$sub", Selector_List, p_contextualize);
+      Selector_List_Obj  sel_sup = ARGSEL("$super", Selector_List_Obj, p_contextualize);
+      Selector_List_Obj  sel_sub = ARGSEL("$sub", Selector_List_Obj, p_contextualize);
       bool result = sel_sup->is_superselector_of(sel_sub);
-      return SASS_MEMORY_NEW(ctx.mem, Boolean, pstate, result);
+      return SASS_MEMORY_NEW(Boolean, pstate, result);
     }
 
     Signature unique_id_sig = "unique-id()";
@@ -1916,7 +1978,7 @@
       std::uniform_real_distribution<> distributor(0, 4294967296); // 16^8
       uint_fast32_t distributed = static_cast<uint_fast32_t>(distributor(rand));
       ss << "u" << std::setfill('0') << std::setw(8) << std::hex << distributed;
-      return SASS_MEMORY_NEW(ctx.mem, String_Quoted, pstate, ss.str());
+      return SASS_MEMORY_NEW(String_Quoted, pstate, ss.str());
     }
 
   }
diff --git a/libsass/src/functions.hpp b/libsass/src/functions.hpp
--- a/libsass/src/functions.hpp
+++ b/libsass/src/functions.hpp
@@ -1,25 +1,23 @@
 #ifndef SASS_FUNCTIONS_H
 #define SASS_FUNCTIONS_H
 
+#include "listize.hpp"
 #include "position.hpp"
 #include "environment.hpp"
+#include "ast_fwd_decl.hpp"
 #include "sass/functions.h"
 
-#define BUILT_IN(name) Expression*\
-name(Env& env, Env& d_env, Context& ctx, Signature sig, ParserState pstate, Backtrace* backtrace)
+#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)
 
 namespace Sass {
-  class Context;
   struct Backtrace;
-  class AST_Node;
-  class Expression;
-  class Definition;
-  typedef Environment<AST_Node*> Env;
+  typedef Environment<AST_Node_Obj> Env;
   typedef const char* Signature;
-  typedef Expression* (*Native_Function)(Env&, Env&, Context&, Signature, ParserState, Backtrace*);
+  typedef Expression_Ptr (*Native_Function)(Env&, Env&, Context&, Signature, ParserState, Backtrace*, std::vector<Selector_List_Obj>);
 
-  Definition* make_native_function(Signature, Native_Function, Context& ctx);
-  Definition* make_c_function(Sass_Function_Entry c_func, Context& ctx);
+  Definition_Ptr make_native_function(Signature, Native_Function, Context& ctx);
+  Definition_Ptr make_c_function(Sass_Function_Entry c_func, Context& ctx);
 
   std::string function_name(Signature);
 
diff --git a/libsass/src/inspect.cpp b/libsass/src/inspect.cpp
--- a/libsass/src/inspect.cpp
+++ b/libsass/src/inspect.cpp
@@ -1,3 +1,4 @@
+#include "sass.hpp"
 #include <cmath>
 #include <string>
 #include <iostream>
@@ -20,17 +21,17 @@
   Inspect::~Inspect() { }
 
   // statements
-  void Inspect::operator()(Block* block)
+  void Inspect::operator()(Block_Ptr block)
   {
     if (!block->is_root()) {
       add_open_mapping(block);
       append_scope_opener();
     }
-    if (output_style() == SASS_STYLE_NESTED) indentation += block->tabs();
+    if (output_style() == NESTED) indentation += block->tabs();
     for (size_t i = 0, L = block->length(); i < L; ++i) {
       (*block)[i]->perform(this);
     }
-    if (output_style() == SASS_STYLE_NESTED) indentation -= block->tabs();
+    if (output_style() == NESTED) indentation -= block->tabs();
     if (!block->is_root()) {
       append_scope_closer();
       add_close_mapping(block);
@@ -38,26 +39,23 @@
 
   }
 
-  void Inspect::operator()(Ruleset* ruleset)
+  void Inspect::operator()(Ruleset_Ptr ruleset)
   {
-    ruleset->selector()->perform(this);
-    ruleset->block()->perform(this);
+    if (ruleset->selector()) {
+      ruleset->selector()->perform(this);
+    }
+    if (ruleset->block()) {
+      ruleset->block()->perform(this);
+    }
   }
 
-  void Inspect::operator()(Keyframe_Rule* rule)
+  void Inspect::operator()(Keyframe_Rule_Ptr rule)
   {
-    if (rule->selector()) rule->selector()->perform(this);
+    if (rule->name()) rule->name()->perform(this);
     if (rule->block()) rule->block()->perform(this);
   }
 
-  void Inspect::operator()(Propset* propset)
-  {
-    propset->property_fragment()->perform(this);
-    append_colon_separator();
-    propset->block()->perform(this);
-  }
-
-  void Inspect::operator()(Bubble* bubble)
+  void Inspect::operator()(Bubble_Ptr bubble)
   {
     append_indentation();
     append_token("::BUBBLE", bubble);
@@ -66,7 +64,7 @@
     append_scope_closer();
   }
 
-  void Inspect::operator()(Media_Block* media_block)
+  void Inspect::operator()(Media_Block_Ptr media_block)
   {
     append_indentation();
     append_token("@media", media_block);
@@ -77,7 +75,7 @@
     media_block->block()->perform(this);
   }
 
-  void Inspect::operator()(Supports_Block* feature_block)
+  void Inspect::operator()(Supports_Block_Ptr feature_block)
   {
     append_indentation();
     append_token("@supports", feature_block);
@@ -86,7 +84,7 @@
     feature_block->block()->perform(this);
   }
 
-  void Inspect::operator()(At_Root_Block* at_root_block)
+  void Inspect::operator()(At_Root_Block_Ptr at_root_block)
   {
     append_indentation();
     append_token("@at-root ", at_root_block);
@@ -95,7 +93,7 @@
     at_root_block->block()->perform(this);
   }
 
-  void Inspect::operator()(At_Rule* at_rule)
+  void Inspect::operator()(Directive_Ptr at_rule)
   {
     append_indentation();
     append_token(at_rule->keyword(), at_rule);
@@ -118,20 +116,22 @@
     }
   }
 
-  void Inspect::operator()(Declaration* dec)
+  void Inspect::operator()(Declaration_Ptr dec)
   {
     if (dec->value()->concrete_type() == Expression::NULL_VAL) return;
     bool was_decl = in_declaration;
     in_declaration = true;
-    if (output_style() == SASS_STYLE_NESTED)
+    if (output_style() == NESTED)
       indentation += dec->tabs();
     append_indentation();
-    dec->property()->perform(this);
+    if (dec->property())
+      dec->property()->perform(this);
     append_colon_separator();
 
     if (dec->value()->concrete_type() == Expression::SELECTOR) {
-      Listize listize(*ctx);
-      dec->value()->perform(&listize)->perform(this);
+      Listize listize;
+      Expression_Obj ls = dec->value()->perform(&listize);
+      ls->perform(this);
     } else {
       dec->value()->perform(this);
     }
@@ -141,12 +141,12 @@
       append_string("!important");
     }
     append_delimiter();
-    if (output_style() == SASS_STYLE_NESTED)
+    if (output_style() == NESTED)
       indentation -= dec->tabs();
     in_declaration = was_decl;
   }
 
-  void Inspect::operator()(Assignment* assn)
+  void Inspect::operator()(Assignment_Ptr assn)
   {
     append_token(assn->variable(), assn);
     append_colon_separator();
@@ -158,20 +158,18 @@
     append_delimiter();
   }
 
-  void Inspect::operator()(Import* import)
+  void Inspect::operator()(Import_Ptr import)
   {
     if (!import->urls().empty()) {
       append_token("@import", import);
       append_mandatory_space();
 
-      if (String_Quoted* strq = dynamic_cast<String_Quoted*>(import->urls().front())) {
-        strq->is_delayed(false);
-      }
-
       import->urls().front()->perform(this);
-      if (import->media_queries()) {
-        append_mandatory_space();
-        import->media_queries()->perform(this);
+      if (import->urls().size() == 1) {
+        if (&import->import_queries()) {
+          append_mandatory_space();
+          import->import_queries()->perform(this);
+        }
       }
       append_delimiter();
       for (size_t i = 1, S = import->urls().size(); i < S; ++i) {
@@ -179,21 +177,19 @@
         append_token("@import", import);
         append_mandatory_space();
 
-        if (String_Quoted* strq = dynamic_cast<String_Quoted*>(import->urls()[i])) {
-          strq->is_delayed(false);
-        }
-
         import->urls()[i]->perform(this);
-        if (import->media_queries()) {
-          append_mandatory_space();
-          import->media_queries()->perform(this);
+        if (import->urls().size() - 1 == i) {
+          if (&import->import_queries()) {
+            append_mandatory_space();
+            import->import_queries()->perform(this);
+          }
         }
         append_delimiter();
       }
     }
   }
 
-  void Inspect::operator()(Import_Stub* import)
+  void Inspect::operator()(Import_Stub_Ptr import)
   {
     append_indentation();
     append_token("@import", import);
@@ -202,7 +198,7 @@
     append_delimiter();
   }
 
-  void Inspect::operator()(Warning* warning)
+  void Inspect::operator()(Warning_Ptr warning)
   {
     append_indentation();
     append_token("@warn", warning);
@@ -211,7 +207,7 @@
     append_delimiter();
   }
 
-  void Inspect::operator()(Error* error)
+  void Inspect::operator()(Error_Ptr error)
   {
     append_indentation();
     append_token("@error", error);
@@ -220,7 +216,7 @@
     append_delimiter();
   }
 
-  void Inspect::operator()(Debug* debug)
+  void Inspect::operator()(Debug_Ptr debug)
   {
     append_indentation();
     append_token("@debug", debug);
@@ -229,14 +225,14 @@
     append_delimiter();
   }
 
-  void Inspect::operator()(Comment* comment)
+  void Inspect::operator()(Comment_Ptr comment)
   {
     in_comment = true;
     comment->text()->perform(this);
     in_comment = false;
   }
 
-  void Inspect::operator()(If* cond)
+  void Inspect::operator()(If_Ptr cond)
   {
     append_indentation();
     append_token("@if", cond);
@@ -251,7 +247,7 @@
     }
   }
 
-  void Inspect::operator()(For* loop)
+  void Inspect::operator()(For_Ptr loop)
   {
     append_indentation();
     append_token("@for", loop);
@@ -264,7 +260,7 @@
     loop->block()->perform(this);
   }
 
-  void Inspect::operator()(Each* loop)
+  void Inspect::operator()(Each_Ptr loop)
   {
     append_indentation();
     append_token("@each", loop);
@@ -279,7 +275,7 @@
     loop->block()->perform(this);
   }
 
-  void Inspect::operator()(While* loop)
+  void Inspect::operator()(While_Ptr loop)
   {
     append_indentation();
     append_token("@while", loop);
@@ -288,7 +284,7 @@
     loop->block()->perform(this);
   }
 
-  void Inspect::operator()(Return* ret)
+  void Inspect::operator()(Return_Ptr ret)
   {
     append_indentation();
     append_token("@return", ret);
@@ -297,7 +293,7 @@
     append_delimiter();
   }
 
-  void Inspect::operator()(Extension* extend)
+  void Inspect::operator()(Extension_Ptr extend)
   {
     append_indentation();
     append_token("@extend", extend);
@@ -306,7 +302,7 @@
     append_delimiter();
   }
 
-  void Inspect::operator()(Definition* def)
+  void Inspect::operator()(Definition_Ptr def)
   {
     append_indentation();
     if (def->type() == Definition::MIXIN) {
@@ -321,7 +317,7 @@
     def->block()->perform(this);
   }
 
-  void Inspect::operator()(Mixin_Call* call)
+  void Inspect::operator()(Mixin_Call_Ptr call)
   {
     append_indentation();
     append_token("@include", call);
@@ -337,15 +333,19 @@
     if (!call->block()) append_delimiter();
   }
 
-  void Inspect::operator()(Content* content)
+  void Inspect::operator()(Content_Ptr content)
   {
     append_indentation();
     append_token("@content", content);
     append_delimiter();
   }
 
-  void Inspect::operator()(Map* map)
+  void Inspect::operator()(Map_Ptr map)
   {
+    if (output_style() == TO_SASS && map->empty()) {
+      append_string("()");
+      return;
+    }
     if (map->empty()) return;
     if (map->is_invisible()) return;
     bool items_output = false;
@@ -360,17 +360,29 @@
     append_string(")");
   }
 
-  void Inspect::operator()(List* list)
+  void Inspect::operator()(List_Ptr list)
   {
+    if (output_style() == TO_SASS && list->empty()) {
+      append_string("()");
+      return;
+    }
     std::string sep(list->separator() == SASS_SPACE ? " " : ",");
-    if ((output_style() != SASS_STYLE_COMPRESSED || in_debug) && sep == ",") sep += " ";
+    if ((output_style() != COMPRESSED) && sep == ",") sep += " ";
     else if (in_media_block && sep != " ") sep += " "; // verified
     if (list->empty()) return;
     bool items_output = false;
 
     bool was_space_array = in_space_array;
     bool was_comma_array = in_comma_array;
-    if (!in_declaration && (
+    // probably ruby sass eqivalent of element_needs_parens
+    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("(");
+    }
+    else if (!in_declaration && (list->separator() == SASS_HASH ||
         (list->separator() == SASS_SPACE && in_space_array) ||
         (list->separator() == SASS_COMMA && in_comma_array)
     )) {
@@ -381,9 +393,16 @@
     else if (list->separator() == SASS_COMMA) in_comma_array = true;
 
     for (size_t i = 0, L = list->size(); i < L; ++i) {
-      Expression* list_item = (*list)[i];
-      if (list_item->is_invisible()) {
-        continue;
+      if (list->separator() == SASS_HASH)
+      { sep[0] = i % 2 ? ':' : ','; }
+      Expression_Obj list_item = list->at(i);
+      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)) {
+            continue;
+          }
+        }
       }
       if (items_output) {
         append_string(sep);
@@ -396,7 +415,15 @@
 
     in_comma_array = was_comma_array;
     in_space_array = was_space_array;
-    if (!in_declaration && (
+    // probably ruby sass eqivalent of element_needs_parens
+    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(",)");
+    }
+    else if (!in_declaration && (list->separator() == SASS_HASH ||
         (list->separator() == SASS_SPACE && in_space_array) ||
         (list->separator() == SASS_COMMA && in_comma_array)
     )) {
@@ -405,85 +432,258 @@
 
   }
 
-  void Inspect::operator()(Binary_Expression* expr)
+  void Inspect::operator()(Binary_Expression_Ptr expr)
   {
     expr->left()->perform(this);
+    if ( in_media_block ||
+         (output_style() == INSPECT) || (
+          expr->op().ws_before
+          && (!expr->is_interpolant())
+          && (expr->is_left_interpolant() ||
+              expr->is_right_interpolant())
+
+    )) append_string(" ");
     switch (expr->type()) {
-      case Sass_OP::AND: append_string(" and "); break;
-      case Sass_OP::OR:  append_string(" or ");  break;
-      case Sass_OP::EQ:  append_string(" == ");  break;
-      case Sass_OP::NEQ: append_string(" != ");  break;
-      case Sass_OP::GT:  append_string(" > ");   break;
-      case Sass_OP::GTE: append_string(" >= ");  break;
-      case Sass_OP::LT:  append_string(" < ");   break;
-      case Sass_OP::LTE: append_string(" <= ");  break;
-      case Sass_OP::ADD: append_string(" + ");   break;
-      case Sass_OP::SUB: append_string(" - ");   break;
-      case Sass_OP::MUL: append_string(" * ");   break;
-      case Sass_OP::DIV: append_string(in_media_block ? " / " : "/"); break;
-      case Sass_OP::MOD: append_string(" % ");   break;
+      case Sass_OP::AND: append_string("&&"); break;
+      case Sass_OP::OR:  append_string("||");  break;
+      case Sass_OP::EQ:  append_string("==");  break;
+      case Sass_OP::NEQ: append_string("!=");  break;
+      case Sass_OP::GT:  append_string(">");   break;
+      case Sass_OP::GTE: append_string(">=");  break;
+      case Sass_OP::LT:  append_string("<");   break;
+      case Sass_OP::LTE: append_string("<=");  break;
+      case Sass_OP::ADD: append_string("+");   break;
+      case Sass_OP::SUB: append_string("-");   break;
+      case Sass_OP::MUL: append_string("*");   break;
+      case Sass_OP::DIV: append_string("/"); break;
+      case Sass_OP::MOD: append_string("%");   break;
       default: break; // shouldn't get here
     }
+    if ( in_media_block ||
+         (output_style() == INSPECT) || (
+          expr->op().ws_after
+          && (!expr->is_interpolant())
+          && (expr->is_left_interpolant() ||
+              expr->is_right_interpolant())
+    )) append_string(" ");
     expr->right()->perform(this);
   }
 
-  void Inspect::operator()(Unary_Expression* expr)
+  void Inspect::operator()(Unary_Expression_Ptr expr)
   {
     if (expr->type() == Unary_Expression::PLUS) append_string("+");
     else                                        append_string("-");
     expr->operand()->perform(this);
   }
 
-  void Inspect::operator()(Function_Call* call)
+  void Inspect::operator()(Function_Call_Ptr call)
   {
     append_token(call->name(), call);
     call->arguments()->perform(this);
   }
 
-  void Inspect::operator()(Function_Call_Schema* call)
+  void Inspect::operator()(Function_Call_Schema_Ptr call)
   {
     call->name()->perform(this);
     call->arguments()->perform(this);
   }
 
-  void Inspect::operator()(Variable* var)
+  void Inspect::operator()(Variable_Ptr var)
   {
     append_token(var->name(), var);
   }
 
-  void Inspect::operator()(Textual* txt)
+  void Inspect::operator()(Textual_Ptr txt)
   {
     append_token(txt->value(), txt);
   }
 
-  void Inspect::operator()(Number* n)
+  void Inspect::operator()(Number_Ptr n)
   {
-    // use values to_string facility
-    bool compressed = ctx->output_style() == SASS_STYLE_COMPRESSED;
-    std::string res(n->to_string(compressed, (int)ctx->c_options->precision));
+
+    std::string res;
+
+    // check if the fractional part of the value equals to zero
+    // neat trick from http://stackoverflow.com/a/1521682/1550314
+    // double int_part; bool is_int = modf(value, &int_part) == 0.0;
+
+    // this all cannot be done with one run only, since fixed
+    // output differs from normal output and regular output
+    // can contain scientific notation which we do not want!
+
+    // first sample
+    std::stringstream ss;
+    ss.precision(12);
+    ss << n->value();
+
+    // check if we got scientific notation in result
+    if (ss.str().find_first_of("e") != std::string::npos) {
+      ss.clear(); ss.str(std::string());
+      ss.precision(std::max(12, opt.precision));
+      ss << std::fixed << n->value();
+    }
+
+    std::string tmp = ss.str();
+    size_t pos_point = tmp.find_first_of(".,");
+    size_t pos_fract = tmp.find_last_not_of("0");
+    bool is_int = pos_point == pos_fract ||
+                  pos_point == std::string::npos;
+
+    // reset stream for another run
+    ss.clear(); ss.str(std::string());
+
+    // take a shortcut for integers
+    if (is_int)
+    {
+      ss.precision(0);
+      ss << std::fixed << n->value();
+      res = std::string(ss.str());
+    }
+    // process floats
+    else
+    {
+      // do we have have too much precision?
+      if (pos_fract < opt.precision + pos_point)
+      { ss.precision((int)(pos_fract - pos_point)); }
+      else { ss.precision(opt.precision); }
+      // round value again
+      ss << std::fixed << n->value();
+      res = std::string(ss.str());
+      // maybe we truncated up to decimal point
+      size_t pos = res.find_last_not_of("0");
+      // handle case where we have a "0"
+      if (pos == std::string::npos) {
+        res = "0.0";
+      } else {
+        bool at_dec_point = res[pos] == '.' ||
+                            res[pos] == ',';
+        // don't leave a blank point
+        if (at_dec_point) ++ pos;
+        res.resize (pos + 1);
+      }
+    }
+
+    // some final cosmetics
+    if (res == "0.0") res = "0";
+    else if (res == "") res = "0";
+    else if (res == "-0") res = "0";
+    else if (res == "-0.0") res = "0";
+    else if (opt.output_style == COMPRESSED)
+    {
+      // check if handling negative nr
+      size_t off = res[0] == '-' ? 1 : 0;
+      // remove leading zero from floating point in compressed mode
+      if (n->zero() && res[off] == '0' && res[off+1] == '.') res.erase(off, 1);
+    }
+
+    // add unit now
+    res += n->unit();
+
     // output the final token
     append_token(res, n);
   }
 
-  void Inspect::operator()(Color* c)
+  // helper function for serializing colors
+  template <size_t range>
+  static double cap_channel(double c) {
+    if      (c > range) return range;
+    else if (c < 0)     return 0;
+    else                return c;
+  }
+
+  void Inspect::operator()(Color_Ptr c)
   {
-    // use values to_string facility
-    bool compressed = ctx->output_style() == SASS_STYLE_COMPRESSED;
-    std::string res(c->to_string(compressed, (int)ctx->c_options->precision));
     // output the final token
-    append_token(res, c);
+    std::stringstream ss;
+
+    // original color name
+    // maybe an unknown token
+    std::string name = c->disp();
+
+    // resolved color
+    std::string res_name = name;
+
+    double r = Sass::round(cap_channel<0xff>(c->r()), opt.precision);
+    double g = Sass::round(cap_channel<0xff>(c->g()), opt.precision);
+    double b = Sass::round(cap_channel<0xff>(c->b()), opt.precision);
+    double a = cap_channel<1>   (c->a());
+
+    // get color from given name (if one was given at all)
+    if (name != "" && name_to_color(name)) {
+      Color_Ptr_Const n = name_to_color(name);
+      r = Sass::round(cap_channel<0xff>(n->r()), opt.precision);
+      g = Sass::round(cap_channel<0xff>(n->g()), opt.precision);
+      b = Sass::round(cap_channel<0xff>(n->b()), opt.precision);
+      a = cap_channel<1>   (n->a());
+    }
+    // otherwise get the possible resolved color name
+    else {
+      double numval = r * 0x10000 + g * 0x100 + b;
+      if (color_to_name(numval))
+        res_name = color_to_name(numval);
+    }
+
+    std::stringstream hexlet;
+    bool compressed = opt.output_style == COMPRESSED;
+    hexlet << '#' << std::setw(1) << std::setfill('0');
+    // create a short color hexlet if there is any need for it
+    if (compressed && is_color_doublet(r, g, b) && a == 1) {
+      hexlet << std::hex << std::setw(1) << (static_cast<unsigned long>(r) >> 4);
+      hexlet << std::hex << std::setw(1) << (static_cast<unsigned long>(g) >> 4);
+      hexlet << std::hex << std::setw(1) << (static_cast<unsigned long>(b) >> 4);
+    } else {
+      hexlet << std::hex << std::setw(2) << static_cast<unsigned long>(r);
+      hexlet << std::hex << std::setw(2) << static_cast<unsigned long>(g);
+      hexlet << std::hex << std::setw(2) << static_cast<unsigned long>(b);
+    }
+
+    if (compressed && !c->is_delayed()) name = "";
+    if (opt.output_style == INSPECT && a >= 1) {
+      append_token(hexlet.str(), c);
+      return;
+    }
+
+    // retain the originally specified color definition if unchanged
+    if (name != "") {
+      ss << name;
+    }
+    else if (r == 0 && g == 0 && b == 0 && a == 0) {
+        ss << "transparent";
+    }
+    else if (a >= 1) {
+      if (res_name != "") {
+        if (compressed && hexlet.str().size() < res_name.size()) {
+          ss << hexlet.str();
+        } else {
+          ss << res_name;
+        }
+      }
+      else {
+        ss << hexlet.str();
+      }
+    }
+    else {
+      ss << "rgba(";
+      ss << static_cast<unsigned long>(r) << ",";
+      if (!compressed) ss << " ";
+      ss << static_cast<unsigned long>(g) << ",";
+      if (!compressed) ss << " ";
+      ss << static_cast<unsigned long>(b) << ",";
+      if (!compressed) ss << " ";
+      ss << a << ')';
+    }
+
+    append_token(ss.str(), c);
+
   }
 
-  void Inspect::operator()(Boolean* b)
+  void Inspect::operator()(Boolean_Ptr b)
   {
-    // use values to_string facility
-    bool compressed = ctx->output_style() == SASS_STYLE_COMPRESSED;
-    std::string res(b->to_string(compressed, (int)ctx->c_options->precision));
     // output the final token
-    append_token(res, b);
+    append_token(b->value() ? "true" : "false", b);
   }
 
-  void Inspect::operator()(String_Schema* ss)
+  void Inspect::operator()(String_Schema_Ptr ss)
   {
     // Evaluation should turn these into String_Constants,
     // so this method is only for inspection purposes.
@@ -494,30 +694,33 @@
     }
   }
 
-  void Inspect::operator()(String_Constant* s)
+  void Inspect::operator()(String_Constant_Ptr s)
   {
-    // get options from optional? context
-    int precision = ctx ? (int)ctx->c_options->precision : 5;
-    bool compressed = ctx ? ctx->output_style() == SASS_STYLE_COMPRESSED : false;
-    // use values to_string facility
-    std::string res(s->to_string(compressed, precision));
-    // output the final token
-    append_token(res, s);
+    append_token(s->value(), s);
   }
 
-  void Inspect::operator()(String_Quoted* s)
+  void Inspect::operator()(String_Quoted_Ptr s)
   {
-    // get options from optional? context
-    int precision = ctx ? (int)ctx->c_options->precision : 5;
-    bool compressed = ctx ? ctx->output_style() == SASS_STYLE_COMPRESSED : false;
-    // use values to_string facility
-    std::string res(s->to_string(compressed, precision));
-    // output the final token
-    append_token(res, s);
+    if (const char q = s->quote_mark()) {
+      append_token(quote(s->value(), q), s);
+    } else {
+      append_token(s->value(), s);
+    }
   }
-  void Inspect::operator()(Supports_Operator* so)
+
+  void Inspect::operator()(Custom_Error_Ptr e)
   {
+    append_token(e->message(), e);
+  }
 
+  void Inspect::operator()(Custom_Warning_Ptr w)
+  {
+    append_token(w->message(), w);
+  }
+
+  void Inspect::operator()(Supports_Operator_Ptr so)
+  {
+
     if (so->needs_parens(so->left())) append_string("(");
     so->left()->perform(this);
     if (so->needs_parens(so->left())) append_string(")");
@@ -537,16 +740,16 @@
     if (so->needs_parens(so->right())) append_string(")");
   }
 
-  void Inspect::operator()(Supports_Negation* sn)
+  void Inspect::operator()(Supports_Negation_Ptr sn)
   {
     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* sd)
+  void Inspect::operator()(Supports_Declaration_Ptr sd)
   {
     append_string("(");
     sd->feature()->perform(this);
@@ -555,15 +758,15 @@
     append_string(")");
   }
 
-  void Inspect::operator()(Supports_Interpolation* sd)
+  void Inspect::operator()(Supports_Interpolation_Ptr sd)
   {
     sd->value()->perform(this);
   }
 
-  void Inspect::operator()(Media_Query* mq)
+  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);
@@ -577,7 +780,7 @@
     }
   }
 
-  void Inspect::operator()(Media_Query_Expression* mqe)
+  void Inspect::operator()(Media_Query_Expression_Ptr mqe)
   {
     if (mqe->is_interpolated()) {
       mqe->feature()->perform(this);
@@ -593,33 +796,25 @@
     }
   }
 
-  void Inspect::operator()(At_Root_Expression* ae)
+  void Inspect::operator()(At_Root_Query_Ptr ae)
   {
-    if (ae->is_interpolated()) {
-      ae->feature()->perform(this);
-    }
-    else {
-      append_string("(");
-      ae->feature()->perform(this);
-      if (ae->value()) {
-        append_colon_separator();
-        ae->value()->perform(this);
-      }
-      append_string(")");
+    append_string("(");
+    ae->feature()->perform(this);
+    if (ae->value()) {
+      append_colon_separator();
+      ae->value()->perform(this);
     }
+    append_string(")");
   }
 
-  void Inspect::operator()(Null* n)
+  void Inspect::operator()(Null_Ptr n)
   {
-    // use values to_string facility
-    bool compressed = output_style() == SASS_STYLE_COMPRESSED;
-    std::string res(n->to_string(compressed, (int)ctx->c_options->precision));
     // output the final token
-    append_token(res, n);
+    append_token("null", n);
   }
 
   // parameters and arguments
-  void Inspect::operator()(Parameter* p)
+  void Inspect::operator()(Parameter_Ptr p)
   {
     append_token(p->name(), p);
     if (p->default_value()) {
@@ -631,7 +826,7 @@
     }
   }
 
-  void Inspect::operator()(Parameters* p)
+  void Inspect::operator()(Parameters_Ptr p)
   {
     append_string("(");
     if (!p->empty()) {
@@ -644,26 +839,29 @@
     append_string(")");
   }
 
-  void Inspect::operator()(Argument* a)
+  void Inspect::operator()(Argument_Ptr a)
   {
     if (!a->name().empty()) {
       append_token(a->name(), a);
       append_colon_separator();
     }
+    if (!a->value()) return;
     // Special case: argument nulls can be ignored
     if (a->value()->concrete_type() == Expression::NULL_VAL) {
       return;
     }
     if (a->value()->concrete_type() == Expression::STRING) {
-      String_Constant* s = static_cast<String_Constant*>(a->value());
-      s->perform(this);
-    } else a->value()->perform(this);
+      String_Constant_Ptr s = SASS_MEMORY_CAST(String_Constant, a->value());
+      if (s) s->perform(this);
+    } else {
+      a->value()->perform(this);
+    }
     if (a->is_rest_argument()) {
       append_string("...");
     }
   }
 
-  void Inspect::operator()(Arguments* a)
+  void Inspect::operator()(Arguments_Ptr a)
   {
     append_string("(");
     if (!a->empty()) {
@@ -677,17 +875,17 @@
     append_string(")");
   }
 
-  void Inspect::operator()(Selector_Schema* s)
+  void Inspect::operator()(Selector_Schema_Ptr s)
   {
     s->contents()->perform(this);
   }
 
-  void Inspect::operator()(Parent_Selector* p)
+  void Inspect::operator()(Parent_Selector_Ptr p)
   {
-    append_string("&");
+    if (p->is_real_parent_ref()) append_string("&");
   }
 
-  void Inspect::operator()(Selector_Placeholder* s)
+  void Inspect::operator()(Placeholder_Selector_Ptr s)
   {
     append_token(s->name(), s);
     if (s->has_line_break()) append_optional_linefeed();
@@ -695,26 +893,33 @@
 
   }
 
-  void Inspect::operator()(Type_Selector* s)
+  void Inspect::operator()(Element_Selector_Ptr s)
   {
     append_token(s->ns_name(), s);
   }
 
-  void Inspect::operator()(Selector_Qualifier* s)
+  void Inspect::operator()(Class_Selector_Ptr s)
   {
     append_token(s->ns_name(), s);
     if (s->has_line_break()) append_optional_linefeed();
     if (s->has_line_break()) append_indentation();
   }
 
-  void Inspect::operator()(Attribute_Selector* s)
+  void Inspect::operator()(Id_Selector_Ptr s)
   {
+    append_token(s->ns_name(), s);
+    if (s->has_line_break()) append_optional_linefeed();
+    if (s->has_line_break()) append_indentation();
+  }
+
+  void Inspect::operator()(Attribute_Selector_Ptr s)
+  {
     append_string("[");
     add_open_mapping(s);
     append_token(s->ns_name(), s);
     if (!s->matcher().empty()) {
       append_string(s->matcher());
-      if (s->value()) {
+      if (&s->value() && *s->value()) {
         s->value()->perform(this);
       }
     }
@@ -722,7 +927,7 @@
     append_string("]");
   }
 
-  void Inspect::operator()(Pseudo_Selector* s)
+  void Inspect::operator()(Pseudo_Selector_Ptr s)
   {
     append_token(s->ns_name(), s);
     if (s->expression()) {
@@ -732,7 +937,7 @@
     }
   }
 
-  void Inspect::operator()(Wrapped_Selector* s)
+  void Inspect::operator()(Wrapped_Selector_Ptr s)
   {
     bool was = in_wrapped;
     in_wrapped = true;
@@ -746,24 +951,29 @@
     in_wrapped = was;
   }
 
-  void Inspect::operator()(Compound_Selector* s)
+  void Inspect::operator()(Compound_Selector_Ptr s)
   {
     for (size_t i = 0, L = s->length(); i < L; ++i) {
       (*s)[i]->perform(this);
     }
     if (s->has_line_break()) {
-      if (output_style() != SASS_STYLE_COMPACT) {
+      if (output_style() != COMPACT) {
         append_optional_linefeed();
       }
     }
   }
 
-  void Inspect::operator()(Complex_Selector* c)
+  void Inspect::operator()(Complex_Selector_Ptr c)
   {
-    Compound_Selector*           head = c->head();
-    Complex_Selector*            tail = c->tail();
+    Compound_Selector_Obj      head = c->head();
+    Complex_Selector_Obj            tail = c->tail();
     Complex_Selector::Combinator comb = c->combinator();
 
+    if (comb == Complex_Selector::ANCESTOR_OF && (!head || head->empty())) {
+      if (tail) tail->perform(this);
+      return;
+    }
+
     if (c->has_line_feed()) {
       if (!(c->has_parent_ref())) {
         append_optional_linefeed();
@@ -774,7 +984,7 @@
     if (head && head->length() != 0) head->perform(this);
     bool is_empty = !head || head->length() == 0 || head->is_empty_reference();
     bool is_tail = head && !head->is_empty_reference() && tail;
-    if (output_style() == SASS_STYLE_COMPRESSED && comb != Complex_Selector::ANCESTOR_OF) scheduled_space = 0;
+    if (output_style() == COMPRESSED && comb != Complex_Selector::ANCESTOR_OF) scheduled_space = 0;
 
     switch (comb) {
       case Complex_Selector::ANCESTOR_OF:
@@ -810,27 +1020,43 @@
     }
     if (tail) tail->perform(this);
     if (!tail && c->has_line_break()) {
-      if (output_style() == SASS_STYLE_COMPACT) {
+      if (output_style() == COMPACT) {
         append_mandatory_space();
       }
     }
   }
 
-  void Inspect::operator()(Selector_List* g)
+  void Inspect::operator()(Selector_List_Ptr g)
   {
-    if (g->empty()) return;
 
+    if (g->empty()) {
+      if (output_style() == TO_SASS) {
+        append_token("()", g);
+      }
+      return;
+    }
+
+
     bool was_comma_array = in_comma_array;
-    if (!in_declaration && 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]))) {
       append_string("(");
     }
+    else if (!in_declaration && in_comma_array) {
+      append_string("(");
+    }
 
     if (in_declaration) in_comma_array = true;
 
     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());
+      // add_open_mapping((*g)[i]->last());
       (*g)[i]->perform(this);
+      // add_close_mapping((*g)[i]->last());
       if (i < L - 1) {
         scheduled_space = 0;
         append_comma_separator();
@@ -838,13 +1064,19 @@
     }
 
     in_comma_array = was_comma_array;
-    if (!in_declaration && 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]))) {
+      append_string(",)");
+    }
+    else if (!in_declaration && in_comma_array) {
       append_string(")");
     }
 
   }
 
-  void Inspect::fallback_impl(AST_Node* n)
+  void Inspect::fallback_impl(AST_Node_Ptr n)
   {
   }
 
diff --git a/libsass/src/inspect.hpp b/libsass/src/inspect.hpp
--- a/libsass/src/inspect.hpp
+++ b/libsass/src/inspect.hpp
@@ -13,7 +13,7 @@
     // import all the class-specific methods and override as desired
     using Operation_CRTP<void, Inspect>::operator();
 
-    void fallback_impl(AST_Node* n);
+    void fallback_impl(AST_Node_Ptr n);
 
   public:
 
@@ -21,77 +21,79 @@
     virtual ~Inspect();
 
     // statements
-    virtual void operator()(Block*);
-    virtual void operator()(Ruleset*);
-    virtual void operator()(Propset*);
-    virtual void operator()(Bubble*);
-    virtual void operator()(Supports_Block*);
-    virtual void operator()(Media_Block*);
-    virtual void operator()(At_Root_Block*);
-    virtual void operator()(At_Rule*);
-    virtual void operator()(Keyframe_Rule*);
-    virtual void operator()(Declaration*);
-    virtual void operator()(Assignment*);
-    virtual void operator()(Import*);
-    virtual void operator()(Import_Stub*);
-    virtual void operator()(Warning*);
-    virtual void operator()(Error*);
-    virtual void operator()(Debug*);
-    virtual void operator()(Comment*);
-    virtual void operator()(If*);
-    virtual void operator()(For*);
-    virtual void operator()(Each*);
-    virtual void operator()(While*);
-    virtual void operator()(Return*);
-    virtual void operator()(Extension*);
-    virtual void operator()(Definition*);
-    virtual void operator()(Mixin_Call*);
-    virtual void operator()(Content*);
+    virtual void operator()(Block_Ptr);
+    virtual void operator()(Ruleset_Ptr);
+    virtual void operator()(Bubble_Ptr);
+    virtual void operator()(Supports_Block_Ptr);
+    virtual void operator()(Media_Block_Ptr);
+    virtual void operator()(At_Root_Block_Ptr);
+    virtual void operator()(Directive_Ptr);
+    virtual void operator()(Keyframe_Rule_Ptr);
+    virtual void operator()(Declaration_Ptr);
+    virtual void operator()(Assignment_Ptr);
+    virtual void operator()(Import_Ptr);
+    virtual void operator()(Import_Stub_Ptr);
+    virtual void operator()(Warning_Ptr);
+    virtual void operator()(Error_Ptr);
+    virtual void operator()(Debug_Ptr);
+    virtual void operator()(Comment_Ptr);
+    virtual void operator()(If_Ptr);
+    virtual void operator()(For_Ptr);
+    virtual void operator()(Each_Ptr);
+    virtual void operator()(While_Ptr);
+    virtual void operator()(Return_Ptr);
+    virtual void operator()(Extension_Ptr);
+    virtual void operator()(Definition_Ptr);
+    virtual void operator()(Mixin_Call_Ptr);
+    virtual void operator()(Content_Ptr);
     // expressions
-    virtual void operator()(Map*);
-    virtual void operator()(List*);
-    virtual void operator()(Binary_Expression*);
-    virtual void operator()(Unary_Expression*);
-    virtual void operator()(Function_Call*);
-    virtual void operator()(Function_Call_Schema*);
-    // virtual void operator()(Custom_Warning*);
-    // virtual void operator()(Custom_Error*);
-    virtual void operator()(Variable*);
-    virtual void operator()(Textual*);
-    virtual void operator()(Number*);
-    virtual void operator()(Color*);
-    virtual void operator()(Boolean*);
-    virtual void operator()(String_Schema*);
-    virtual void operator()(String_Constant*);
-    virtual void operator()(String_Quoted*);
-    virtual void operator()(Supports_Operator*);
-    virtual void operator()(Supports_Negation*);
-    virtual void operator()(Supports_Declaration*);
-    virtual void operator()(Supports_Interpolation*);
-    virtual void operator()(Media_Query*);
-    virtual void operator()(Media_Query_Expression*);
-    virtual void operator()(At_Root_Expression*);
-    virtual void operator()(Null*);
-    virtual void operator()(Parent_Selector* p);
+    virtual void operator()(Map_Ptr);
+    virtual void operator()(List_Ptr);
+    virtual void operator()(Binary_Expression_Ptr);
+    virtual void operator()(Unary_Expression_Ptr);
+    virtual void operator()(Function_Call_Ptr);
+    virtual void operator()(Function_Call_Schema_Ptr);
+    // 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);
+    virtual void operator()(String_Schema_Ptr);
+    virtual void operator()(String_Constant_Ptr);
+    virtual void operator()(String_Quoted_Ptr);
+    virtual void operator()(Custom_Error_Ptr);
+    virtual void operator()(Custom_Warning_Ptr);
+    virtual void operator()(Supports_Operator_Ptr);
+    virtual void operator()(Supports_Negation_Ptr);
+    virtual void operator()(Supports_Declaration_Ptr);
+    virtual void operator()(Supports_Interpolation_Ptr);
+    virtual void operator()(Media_Query_Ptr);
+    virtual void operator()(Media_Query_Expression_Ptr);
+    virtual void operator()(At_Root_Query_Ptr);
+    virtual void operator()(Null_Ptr);
+    virtual void operator()(Parent_Selector_Ptr p);
     // parameters and arguments
-    virtual void operator()(Parameter*);
-    virtual void operator()(Parameters*);
-    virtual void operator()(Argument*);
-    virtual void operator()(Arguments*);
+    virtual void operator()(Parameter_Ptr);
+    virtual void operator()(Parameters_Ptr);
+    virtual void operator()(Argument_Ptr);
+    virtual void operator()(Arguments_Ptr);
     // selectors
-    virtual void operator()(Selector_Schema*);
-    virtual void operator()(Selector_Placeholder*);
-    virtual void operator()(Type_Selector*);
-    virtual void operator()(Selector_Qualifier*);
-    virtual void operator()(Attribute_Selector*);
-    virtual void operator()(Pseudo_Selector*);
-    virtual void operator()(Wrapped_Selector*);
-    virtual void operator()(Compound_Selector*);
-    virtual void operator()(Complex_Selector*);
-    virtual void operator()(Selector_List*);
+    virtual void operator()(Selector_Schema_Ptr);
+    virtual void operator()(Placeholder_Selector_Ptr);
+    virtual void operator()(Element_Selector_Ptr);
+    virtual void operator()(Class_Selector_Ptr);
+    virtual void operator()(Id_Selector_Ptr);
+    virtual void operator()(Attribute_Selector_Ptr);
+    virtual void operator()(Pseudo_Selector_Ptr);
+    virtual void operator()(Wrapped_Selector_Ptr);
+    virtual void operator()(Compound_Selector_Ptr);
+    virtual void operator()(Complex_Selector_Ptr);
+    virtual void operator()(Selector_List_Ptr);
 
     // template <typename U>
-    // void fallback(U x) { fallback_impl(reinterpret_cast<AST_Node*>(x)); }
+    // void fallback(U x) { fallback_impl(reinterpret_cast<AST_Node_Ptr>(x)); }
   };
 
 }
diff --git a/libsass/src/json.cpp b/libsass/src/json.cpp
--- a/libsass/src/json.cpp
+++ b/libsass/src/json.cpp
@@ -28,6 +28,10 @@
 
 #include "json.hpp"
 
+// include utf8 library used by libsass
+// ToDo: replace internal json utf8 code
+#include "utf8.h"
+
 #include <assert.h>
 #include <stdint.h>
 #include <stdio.h>
@@ -395,7 +399,13 @@
   SB sb;
   sb_init(&sb);
 
-  emit_string(&sb, str);
+  try {
+    emit_string(&sb, str);
+  }
+  catch (std::exception) {
+    sb_free(&sb);
+    throw;
+  }
 
   return sb_finish(&sb);
 }
@@ -405,10 +415,16 @@
   SB sb;
   sb_init(&sb);
 
-  if (space != NULL)
-    emit_value_indented(&sb, node, space, 0);
-  else
-    emit_value(&sb, node);
+  try {
+    if (space != NULL)
+      emit_value_indented(&sb, node, space, 0);
+    else
+      emit_value(&sb, node);
+  }
+  catch (std::exception) {
+    sb_free(&sb);
+    throw;
+  }
 
   return sb_finish(&sb);
 }
@@ -544,42 +560,50 @@
 
 static void append_node(JsonNode *parent, JsonNode *child)
 {
-  child->parent = parent;
-  child->prev = parent->children.tail;
-  child->next = NULL;
+  if (child != NULL && parent != NULL) {
+      child->parent = parent;
+      child->prev = parent->children.tail;
+      child->next = NULL;
 
-  if (parent->children.tail != NULL)
-    parent->children.tail->next = child;
-  else
-    parent->children.head = child;
-  parent->children.tail = child;
+      if (parent->children.tail != NULL)
+          parent->children.tail->next = child;
+      else
+          parent->children.head = child;
+      parent->children.tail = child;
+  }
 }
 
 static void prepend_node(JsonNode *parent, JsonNode *child)
 {
-  child->parent = parent;
-  child->prev = NULL;
-  child->next = parent->children.head;
+  if (child != NULL && parent != NULL) {
+      child->parent = parent;
+      child->prev = NULL;
+      child->next = parent->children.head;
 
-  if (parent->children.head != NULL)
-    parent->children.head->prev = child;
-  else
-    parent->children.tail = child;
-  parent->children.head = child;
+      if (parent->children.head != NULL)
+          parent->children.head->prev = child;
+      else
+          parent->children.tail = child;
+      parent->children.head = child;
+  }
 }
 
 static void append_member(JsonNode *object, char *key, JsonNode *value)
 {
-  value->key = key;
-  append_node(object, value);
+  if (value != NULL && object != NULL) {
+      value->key = key;
+      append_node(object, value);
+  }
 }
 
 void json_append_element(JsonNode *array, JsonNode *element)
 {
-  assert(array->tag == JSON_ARRAY);
-  assert(element->parent == NULL);
+  if (array != NULL && element !=NULL) {
+      assert(array->tag == JSON_ARRAY);
+      assert(element->parent == NULL);
 
-  append_node(array, element);
+      append_node(array, element);
+  }
 }
 
 void json_prepend_element(JsonNode *array, JsonNode *element)
@@ -592,40 +616,47 @@
 
 void json_append_member(JsonNode *object, const char *key, JsonNode *value)
 {
-  assert(object->tag == JSON_OBJECT);
-  assert(value->parent == NULL);
+  if (object != NULL && key != NULL && value != NULL) {
+      assert(object->tag == JSON_OBJECT);
+      assert(value->parent == NULL);
 
-  append_member(object, json_strdup(key), value);
+      append_member(object, json_strdup(key), value);
+  }
 }
 
 void json_prepend_member(JsonNode *object, const char *key, JsonNode *value)
 {
-  assert(object->tag == JSON_OBJECT);
-  assert(value->parent == NULL);
+  if (object != NULL && key != NULL && value != NULL) {
+      assert(object->tag == JSON_OBJECT);
+      assert(value->parent == NULL);
 
-  value->key = json_strdup(key);
-  prepend_node(object, value);
+      value->key = json_strdup(key);
+      prepend_node(object, value);
+  }
 }
 
 void json_remove_from_parent(JsonNode *node)
 {
-  JsonNode *parent = node->parent;
+  if (node != NULL) {
+      JsonNode *parent = node->parent;
 
-  if (parent != NULL) {
-    if (node->prev != NULL)
-      node->prev->next = node->next;
-    else
-      parent->children.head = node->next;
-    if (node->next != NULL)
-      node->next->prev = node->prev;
-    else
-      parent->children.tail = node->prev;
+      if (parent != NULL) {
+          if (node->prev != NULL)
+              node->prev->next = node->next;
+          else
+              parent->children.head = node->next;
 
-    free(node->key);
+          if (node->next != NULL)
+              node->next->prev = node->prev;
+          else
+              parent->children.tail = node->prev;
 
-    node->parent = NULL;
-    node->prev = node->next = NULL;
-    node->key = NULL;
+          free(node->key);
+
+          node->parent = NULL;
+          node->prev = node->next = NULL;
+          node->key = NULL;
+      }
   }
 }
 
@@ -1125,6 +1156,13 @@
   bool escape_unicode = false;
   const char *s = str;
   char *b;
+
+// make assertion catchable
+#ifndef NDEBUG
+  if (!utf8_validate(str)) {
+    throw utf8::invalid_utf8(0);
+  }
+#endif
 
   assert(utf8_validate(str));
 
diff --git a/libsass/src/json.hpp b/libsass/src/json.hpp
--- a/libsass/src/json.hpp
+++ b/libsass/src/json.hpp
@@ -43,21 +43,21 @@
   /* only if parent is an object or array (NULL otherwise) */
   JsonNode *parent;
   JsonNode *prev, *next;
-  
+
   /* only if parent is an object (NULL otherwise) */
   char *key; /* Must be valid UTF-8. */
-  
+
   JsonTag tag;
   union {
     /* JSON_BOOL */
     bool bool_;
-    
+
     /* JSON_STRING */
     char *string_; /* Must be valid UTF-8. */
-    
+
     /* JSON_NUMBER */
     double number_;
-    
+
     /* JSON_ARRAY */
     /* JSON_OBJECT */
     struct {
diff --git a/libsass/src/lexer.cpp b/libsass/src/lexer.cpp
--- a/libsass/src/lexer.cpp
+++ b/libsass/src/lexer.cpp
@@ -1,3 +1,4 @@
+#include "sass.hpp"
 #include <cctype>
 #include <cstddef>
 #include <iostream>
@@ -80,9 +81,9 @@
     bool is_nonascii(const char& chr)
     {
       return (
-        (unsigned(chr) > 127 && unsigned(chr) < 55296) ||
-        (unsigned(chr) > 57343 && unsigned(chr) < 65534) ||
-        (unsigned(chr) > 65535 && unsigned(chr) < 1114111)
+        (unsigned(chr) >= 128 && unsigned(chr) <= 15572911) ||
+        (unsigned(chr) >= 15630464 && unsigned(chr) <= 15712189) ||
+        (unsigned(chr) >= 4036001920)
       );
     }
 
@@ -90,7 +91,8 @@
     // valid in a uri (copied from Ruby Sass)
     bool is_uri_character(const char& chr)
     {
-      return unsigned(chr) > 41 && unsigned(chr) < 127;
+      return (unsigned(chr) > 41 && unsigned(chr) < 127) ||
+             unsigned(chr) == ':' || unsigned(chr) == '/';
     }
 
     // check if char is within a reduced ascii range
@@ -120,6 +122,7 @@
     const char* xdigit(const char* src) { return is_xdigit(*src) ? src + 1 : 0; }
     const char* alnum(const char* src) { return is_alnum(*src) ? src + 1 : 0; }
     const char* punct(const char* src) { return is_punct(*src) ? src + 1 : 0; }
+    const char* hyphen(const char* src) { return *src && *src == '-' ? src + 1 : 0; }
     const char* character(const char* src) { return is_character(*src) ? src + 1 : 0; }
     const char* uri_character(const char* src) { return is_uri_character(*src) ? src + 1 : 0; }
     const char* escapable_character(const char* src) { return is_escapable_character(*src) ? src + 1 : 0; }
@@ -127,6 +130,7 @@
     // Match multiple ctype characters.
     const char* spaces(const char* src) { return one_plus<space>(src); }
     const char* digits(const char* src) { return one_plus<digit>(src); }
+    const char* hyphens(const char* src) { return one_plus<hyphen>(src); }
 
     // Whitespace handling.
     const char* no_spaces(const char* src) { return negate< space >(src); }
@@ -136,7 +140,7 @@
     const char* any_char(const char* src) { return *src ? src + 1 : src; }
 
     // Match word boundary (zero-width lookahead).
-    const char* word_boundary(const char* src) { return is_character(*src) ? 0 : src; }
+    const char* word_boundary(const char* src) { return is_character(*src) || *src == '#' ? 0 : src; }
 
     // Match linefeed /(?:\n|\r\n?)/
     const char* re_linebreak(const char* src)
diff --git a/libsass/src/lexer.hpp b/libsass/src/lexer.hpp
--- a/libsass/src/lexer.hpp
+++ b/libsass/src/lexer.hpp
@@ -44,6 +44,7 @@
     const char* xdigit(const char* src);
     const char* alnum(const char* src);
     const char* punct(const char* src);
+    const char* hyphen(const char* src);
     const char* unicode(const char* src);
     const char* nonascii(const char* src);
     const char* character(const char* src);
@@ -53,6 +54,7 @@
     // Match multiple ctype characters.
     const char* spaces(const char* src);
     const char* digits(const char* src);
+    const char* hyphens(const char* src);
 
     // Whitespace handling.
     const char* no_spaces(const char* src);
@@ -139,6 +141,25 @@
     const char* class_chars(const char* src) {
       const char* p = src;
       while (class_char<char_class>(p)) ++p;
+      return p == src ? 0 : p;
+    }
+
+    // Match for members of char class.
+    // Regex equivalent: /[^axy]/
+    template <const char* neg_char_class>
+    const char* neg_class_char(const char* src) {
+      if (*src == 0) return 0;
+      const char* cc = neg_char_class;
+      while (*cc && *src != *cc) ++cc;
+      return *cc ? 0 : src + 1;
+    }
+
+    // Match for members of char class.
+    // Regex equivalent: /[^axy]+/
+    template <const char* neg_char_class>
+    const char* neg_class_chars(const char* src) {
+      const char* p = src;
+      while (neg_class_char<neg_char_class>(p)) ++p;
       return p == src ? 0 : p;
     }
 
diff --git a/libsass/src/listize.cpp b/libsass/src/listize.cpp
--- a/libsass/src/listize.cpp
+++ b/libsass/src/listize.cpp
@@ -1,87 +1,85 @@
+#include "sass.hpp"
 #include <iostream>
 #include <typeinfo>
 #include <string>
 
 #include "listize.hpp"
-#include "to_string.hpp"
 #include "context.hpp"
 #include "backtrace.hpp"
 #include "error_handling.hpp"
 
 namespace Sass {
 
-  Listize::Listize(Context& ctx)
-  : ctx(ctx)
+  Listize::Listize()
   {  }
 
-  Expression* Listize::operator()(Selector_List* sel)
+  Expression_Ptr Listize::operator()(Selector_List_Ptr sel)
   {
-    List* l = SASS_MEMORY_NEW(ctx.mem, List, sel->pstate(), sel->length(), SASS_COMMA);
+    List_Obj l = SASS_MEMORY_NEW(List, sel->pstate(), sel->length(), SASS_COMMA);
+    l->from_selector(true);
     for (size_t i = 0, L = sel->length(); i < L; ++i) {
-      if (!(*sel)[i]) continue;
-      *l << (*sel)[i]->perform(this);
+      if (!sel->at(i)) continue;
+      l->append(sel->at(i)->perform(this));
     }
-    return l;
+    if (l->length()) return l.detach();
+    return SASS_MEMORY_NEW(Null, l->pstate());
   }
 
-  Expression* Listize::operator()(Compound_Selector* sel)
+  Expression_Ptr Listize::operator()(Compound_Selector_Ptr sel)
   {
-    To_String to_string;
     std::string str;
     for (size_t i = 0, L = sel->length(); i < L; ++i) {
-      Expression* e = (*sel)[i]->perform(this);
-      if (e) str += e->perform(&to_string);
+      Expression_Ptr e = (*sel)[i]->perform(this);
+      if (e) str += e->to_string();
     }
-    return SASS_MEMORY_NEW(ctx.mem, String_Quoted, sel->pstate(), str);
+    return SASS_MEMORY_NEW(String_Quoted, sel->pstate(), str);
   }
 
-  Expression* Listize::operator()(Complex_Selector* sel)
+  Expression_Ptr Listize::operator()(Complex_Selector_Ptr sel)
   {
-    List* l = SASS_MEMORY_NEW(ctx.mem, List, sel->pstate(), 2);
-
-    Compound_Selector* head = sel->head();
+    List_Obj l = SASS_MEMORY_NEW(List, sel->pstate(), 2);
+    l->from_selector(true);
+    Compound_Selector_Obj head = sel->head();
     if (head && !head->is_empty_reference())
     {
-      Expression* hh = head->perform(this);
-      if (hh) *l << hh;
+      Expression_Ptr hh = head->perform(this);
+      if (hh) l->append(hh);
     }
 
-    To_String to_string;
     std::string reference = ! sel->reference() ? ""
-      : sel->reference()->perform(&to_string);
+      : sel->reference()->to_string();
     switch(sel->combinator())
     {
       case Complex_Selector::PARENT_OF:
-        *l << SASS_MEMORY_NEW(ctx.mem, String_Quoted, sel->pstate(), ">");
+        l->append(SASS_MEMORY_NEW(String_Quoted, sel->pstate(), ">"));
       break;
       case Complex_Selector::ADJACENT_TO:
-        *l << SASS_MEMORY_NEW(ctx.mem, String_Quoted, sel->pstate(), "+");
+        l->append(SASS_MEMORY_NEW(String_Quoted, sel->pstate(), "+"));
       break;
       case Complex_Selector::REFERENCE:
-        *l << SASS_MEMORY_NEW(ctx.mem, String_Quoted, sel->pstate(), "/" + reference + "/");
+        l->append(SASS_MEMORY_NEW(String_Quoted, sel->pstate(), "/" + reference + "/"));
       break;
       case Complex_Selector::PRECEDES:
-        *l << SASS_MEMORY_NEW(ctx.mem, String_Quoted, sel->pstate(), "~");
+        l->append(SASS_MEMORY_NEW(String_Quoted, sel->pstate(), "~"));
       break;
       case Complex_Selector::ANCESTOR_OF:
       break;
     }
 
-    Complex_Selector* tail = sel->tail();
+    Complex_Selector_Obj tail = sel->tail();
     if (tail)
     {
-      Expression* tt = tail->perform(this);
-      if (tt && tt->concrete_type() == Expression::LIST)
-      { *l += static_cast<List*>(tt); }
-      else if (tt) *l << static_cast<List*>(tt);
+      Expression_Obj tt = tail->perform(this);
+      if (List_Ptr ls = SASS_MEMORY_CAST(List, tt))
+      { l->concat(ls); }
     }
     if (l->length() == 0) return 0;
-    return l;
+    return l.detach();
   }
 
-  Expression* Listize::fallback_impl(AST_Node* n)
+  Expression_Ptr Listize::fallback_impl(AST_Node_Ptr n)
   {
-    return dynamic_cast<Expression*>(n);
+    return dynamic_cast<Expression_Ptr>(n);
   }
 
 }
diff --git a/libsass/src/listize.hpp b/libsass/src/listize.hpp
--- a/libsass/src/listize.hpp
+++ b/libsass/src/listize.hpp
@@ -11,27 +11,23 @@
 
 namespace Sass {
 
-  typedef Environment<AST_Node*> Env;
+  typedef Environment<AST_Node_Obj> Env;
   struct Backtrace;
 
-  class Listize : public Operation_CRTP<Expression*, Listize> {
-
-    Context&            ctx;
+  class Listize : public Operation_CRTP<Expression_Ptr, Listize> {
 
-    Expression* fallback_impl(AST_Node* n);
+    Expression_Ptr fallback_impl(AST_Node_Ptr n);
 
   public:
-    Listize(Context&);
-    virtual ~Listize() { }
-
-    using Operation<Expression*>::operator();
+    Listize();
+    ~Listize() { }
 
-    Expression* operator()(Selector_List*);
-    Expression* operator()(Complex_Selector*);
-    Expression* operator()(Compound_Selector*);
+    Expression_Ptr operator()(Selector_List_Ptr);
+    Expression_Ptr operator()(Complex_Selector_Ptr);
+    Expression_Ptr operator()(Compound_Selector_Ptr);
 
     template <typename U>
-    Expression* fallback(U x) { return fallback_impl(x); }
+    Expression_Ptr fallback(U x) { return fallback_impl(x); }
   };
 
 }
diff --git a/libsass/src/memory/SharedPtr.cpp b/libsass/src/memory/SharedPtr.cpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/memory/SharedPtr.cpp
@@ -0,0 +1,116 @@
+#include "../sass.hpp"
+#include <iostream>
+#include <typeinfo>
+
+#include "SharedPtr.hpp"
+#include "../ast_fwd_decl.hpp"
+
+#ifdef DEBUG_SHARED_PTR
+#include "../debugger.hpp"
+#endif
+
+namespace Sass {
+
+  #ifdef DEBUG_SHARED_PTR
+  void SharedObj::dumpMemLeaks() {
+    if (!all.empty()) {
+      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)) {
+          debug_ast(ast);
+        } else {
+          std::cerr << "LEAKED " << var << "\n";
+        }
+      }
+    }
+  }
+  std::vector<SharedObj*> SharedObj::all;
+  #endif
+
+  bool SharedObj::taint = false;
+
+  SharedObj::SharedObj()
+  : detached(false)
+    #ifdef DEBUG_SHARED_PTR
+    , 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
+    };
+
+
+
+  void SharedPtr::decRefCount() {
+    if (node) {
+      -- node->refcounter;
+      #ifdef DEBUG_SHARED_PTR
+        if (node->dbg)  std::cerr << "- " << node << " X " << node->refcounter << " (" << this << ") " << "\n";
+      #endif
+      if (node->refcounter == 0) {
+        #ifdef DEBUG_SHARED_PTR
+          AST_Node_Ptr ptr = SASS_MEMORY_CAST_PTR(AST_Node, node);
+          if (node->dbg) std::cerr << "DELETE NODE " << node << "\n";
+        #endif
+        if (!node->detached) {
+          delete(node);
+        }
+      }
+    }
+  }
+
+  void SharedPtr::incRefCount() {
+    if (node) {
+      ++ node->refcounter;
+      node->detached = false;
+      #ifdef DEBUG_SHARED_PTR
+        if (node->dbg) {
+          std::cerr << "+ " << node << " X " << node->refcounter << " (" << this << ") " << "\n";
+        }
+      #endif
+    }
+  }
+
+  SharedPtr::~SharedPtr() {
+    decRefCount();
+  }
+
+
+  // the create constructor
+  SharedPtr::SharedPtr(SharedObj* ptr)
+  : node(ptr) {
+    incRefCount();
+  }
+  // copy assignment operator
+  SharedPtr& SharedPtr::operator=(const SharedPtr& rhs) {
+    void* cur_ptr = (void*) node;
+    void* rhs_ptr = (void*) rhs.node;
+    if (cur_ptr == rhs_ptr) {
+      return *this;
+    }
+    decRefCount();
+    node = rhs.node;
+    incRefCount();
+    return *this;
+  }
+
+  // the copy constructor
+  SharedPtr::SharedPtr(const SharedPtr& obj)
+  : node(obj.node) {
+    incRefCount();
+  }
+
+}
diff --git a/libsass/src/memory/SharedPtr.hpp b/libsass/src/memory/SharedPtr.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/memory/SharedPtr.hpp
@@ -0,0 +1,202 @@
+#ifndef SASS_MEMORY_SHARED_PTR_H
+#define SASS_MEMORY_SHARED_PTR_H
+
+#include "sass/base.h"
+
+#include <vector>
+
+namespace Sass {
+
+  class SharedPtr;
+
+  ///////////////////////////////////////////////////////////////////////////////
+  // Use macros for the allocation task, since overloading operator `new`
+  // has been proven to be flaky under certain compilers (see comment below).
+  ///////////////////////////////////////////////////////////////////////////////
+
+  #ifdef DEBUG_SHARED_PTR
+
+    #define SASS_MEMORY_NEW(Class, ...) \
+      static_cast<Class##_Ptr>((new Class(__VA_ARGS__))->trace(__FILE__, __LINE__)) \
+
+    #define SASS_MEMORY_COPY(obj) \
+      ((obj)->copy(__FILE__, __LINE__)) \
+
+    #define SASS_MEMORY_CLONE(obj) \
+      ((obj)->clone(__FILE__, __LINE__)) \
+
+  #else
+
+    #define SASS_MEMORY_NEW(Class, ...) \
+      new Class(__VA_ARGS__) \
+
+    #define SASS_MEMORY_COPY(obj) \
+      ((obj)->copy()) \
+
+    #define SASS_MEMORY_CLONE(obj) \
+      ((obj)->clone()) \
+
+  #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;
+  friend class Memory_Manager;
+    #ifdef DEBUG_SHARED_PTR
+      static std::vector<SharedObj*> all;
+      std::string file;
+      size_t line;
+    #endif
+    static bool taint;
+    long refcounter;
+    // long refcount;
+    bool detached;
+    #ifdef DEBUG_SHARED_PTR
+      bool dbg;
+    #endif
+  public:
+    #ifdef DEBUG_SHARED_PTR
+      static void dumpMemLeaks();
+      SharedObj* trace(std::string file, size_t line) {
+        this->file = file;
+        this->line = line;
+        return this;
+      }
+    #endif
+    SharedObj();
+    #ifdef DEBUG_SHARED_PTR
+      std::string getDbgFile() {
+        return file;
+      }
+      size_t getDbgLine() {
+        return line;
+      }
+      void setDbg(bool dbg) {
+        this->dbg = dbg;
+      }
+    #endif
+    static void setTaint(bool val) {
+      taint = val;
+    }
+    virtual ~SharedObj();
+    long getRefCount() {
+      return refcounter;
+    }
+  };
+
+
+  class SharedPtr {
+  private:
+    SharedObj* node;
+  private:
+    void decRefCount();
+    void incRefCount();
+  public:
+    // the empty constructor
+    SharedPtr()
+    : 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();
+  public:
+    SharedObj* obj () {
+      return node;
+    };
+    SharedObj* obj () const {
+      return node;
+    };
+    SharedObj* operator-> () {
+      return node;
+    };
+    bool isNull () {
+      return node == NULL;
+    };
+    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 >
+  class SharedImpl : private SharedPtr {
+  public:
+    SharedImpl()
+    : SharedPtr(NULL) {};
+    SharedImpl(T* node)
+    : SharedPtr(node) {};
+    SharedImpl(T&& node)
+    : SharedPtr(node) {};
+    SharedImpl(const T& node)
+    : SharedPtr(node) {};
+    ~SharedImpl() {};
+  public:
+    T* operator& () {
+      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* operator-> () {
+      return static_cast<T*>(this->obj());
+    };
+    T* operator-> () const {
+      return static_cast<T*>(this->obj());
+    };
+    T* ptr () {
+      return static_cast<T*>(this->obj());
+    };
+    T* detach() {
+      if (this->obj() == NULL) return NULL;
+      return static_cast<T*>(SharedPtr::detach());
+    }
+    bool isNull() {
+      return this->obj() == NULL;
+    }
+    operator bool() {
+      return this->obj() != NULL;
+    };
+    operator bool() const {
+      return this->obj() != NULL;
+    };
+  };
+
+}
+
+#endif
diff --git a/libsass/src/memory_manager.cpp b/libsass/src/memory_manager.cpp
deleted file mode 100644
--- a/libsass/src/memory_manager.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-#include "ast.hpp"
-#include "memory_manager.hpp"
-
-namespace Sass {
-
-  Memory_Manager::Memory_Manager(size_t size)
-  : nodes(std::vector<Memory_Object*>())
-  {
-    size_t init = size;
-    if (init < 8) init = 8;
-    // reserve some space
-    nodes.reserve(init);
-  }
-
-  Memory_Manager::~Memory_Manager()
-  {
-    // release memory for all controlled nodes
-    // avoid calling erase for every single node
-    for (size_t i = 0, S = nodes.size(); i < S; ++i) {
-      deallocate(nodes[i]);
-    }
-    // just in case
-    nodes.clear();
-  }
-
-  Memory_Object* Memory_Manager::add(Memory_Object* np)
-  {
-    // object has been initialized
-    // it can be "deleted" from now on
-    np->refcount = 1;
-    return np;
-  }
-
-  bool Memory_Manager::has(Memory_Object* np)
-  {
-    // check if the pointer is controlled under our pool
-    return find(nodes.begin(), nodes.end(), np) != nodes.end();
-  }
-
-  Memory_Object* Memory_Manager::allocate(size_t size)
-  {
-    // allocate requested memory
-    void* heap = malloc(size);
-    // init internal refcount status to zero
-    (static_cast<Memory_Object*>(heap))->refcount = 0;
-    // add the memory under our management
-    nodes.push_back(static_cast<Memory_Object*>(heap));
-    // cast object to its initial type
-    return static_cast<Memory_Object*>(heap);
-  }
-
-  void Memory_Manager::deallocate(Memory_Object* np)
-  {
-    // only call destructor if initialized
-    if (np->refcount) np->~Memory_Object();
-    // always free the memory
-    free(np);
-  }
-
-  void Memory_Manager::remove(Memory_Object* np)
-  {
-    // remove node from pool (no longer active)
-    nodes.erase(find(nodes.begin(), nodes.end(), np));
-    // you are now in control of the memory
-  }
-
-  void Memory_Manager::destroy(Memory_Object* np)
-  {
-    // remove from pool
-    remove(np);
-    // release memory
-    deallocate(np);
-  }
-
-}
-
diff --git a/libsass/src/memory_manager.hpp b/libsass/src/memory_manager.hpp
deleted file mode 100644
--- a/libsass/src/memory_manager.hpp
+++ /dev/null
@@ -1,48 +0,0 @@
-#ifndef SASS_MEMORY_MANAGER_H
-#define SASS_MEMORY_MANAGER_H
-
-#include <vector>
-
-namespace Sass {
-
-  class Memory_Object {
-  friend class Memory_Manager;
-    long refcount;
-  public:
-    Memory_Object() { refcount = 0; };
-    virtual ~Memory_Object() {};
-  };
-
-  /////////////////////////////////////////////////////////////////////////////
-  // A class for tracking allocations of AST_Node objects. The intended usage
-  // is something like: Some_Node* n = new (mem_mgr) Some_Node(...);
-  // Then, at the end of the program, the memory manager will delete all of the
-  // allocated nodes that have been passed to it.
-  // In the future, this class may implement a custom allocator.
-  /////////////////////////////////////////////////////////////////////////////
-  class Memory_Manager {
-    std::vector<Memory_Object*> nodes;
-
-  public:
-    Memory_Manager(size_t size = 0);
-    ~Memory_Manager();
-
-    bool has(Memory_Object* np);
-    Memory_Object* allocate(size_t size);
-    void deallocate(Memory_Object* np);
-    void remove(Memory_Object* np);
-    void destroy(Memory_Object* np);
-    Memory_Object* add(Memory_Object* np);
-
-  };
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Use macros for the allocation task, since overloading operator `new`
-// has been proven to be flaky under certain compilers (see comment below).
-///////////////////////////////////////////////////////////////////////////////
-
-#define SASS_MEMORY_NEW(mgr, Class, ...)                                                 \
-  (static_cast<Class*>(mgr.add(new (mgr.allocate(sizeof(Class))) Class(__VA_ARGS__))))   \
-
-#endif
diff --git a/libsass/src/node.cpp b/libsass/src/node.cpp
--- a/libsass/src/node.cpp
+++ b/libsass/src/node.cpp
@@ -1,7 +1,7 @@
+#include "sass.hpp"
 #include <vector>
 
 #include "node.hpp"
-#include "to_string.hpp"
 #include "context.hpp"
 #include "parser.hpp"
 
@@ -14,10 +14,10 @@
   }
 
 
-  Node Node::createSelector(Complex_Selector* pSelector, Context& ctx) {
+  Node Node::createSelector(Complex_Selector_Ptr pSelector, Context& ctx) {
     NodeDequePtr null;
 
-    Complex_Selector* pStripped = pSelector->clone(ctx);
+    Complex_Selector_Ptr pStripped = SASS_MEMORY_COPY(pSelector);
     pStripped->tail(NULL);
     pStripped->combinator(Complex_Selector::ANCESTOR_OF);
 
@@ -45,21 +45,21 @@
   }
 
 
-  Node::Node(const TYPE& type, Complex_Selector::Combinator combinator, Complex_Selector* pSelector, NodeDequePtr& pCollection)
+  Node::Node(const TYPE& type, Complex_Selector::Combinator combinator, Complex_Selector_Ptr pSelector, NodeDequePtr& pCollection)
   : got_line_feed(false), mType(type), mCombinator(combinator), mpSelector(pSelector), mpCollection(pCollection)
   { if (pSelector) got_line_feed = pSelector->has_line_feed(); }
 
 
-  Node Node::clone(Context& ctx) const {
+  Node Node::klone(Context& ctx) 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.clone(ctx));
+        pNewCollection->push_back(toClone.klone(ctx));
       }
     }
 
-    Node n(mType, mCombinator, mpSelector ? mpSelector->clone(ctx) : NULL, pNewCollection);
+    Node n(mType, mCombinator, mpSelector ? SASS_MEMORY_COPY(mpSelector) : NULL, pNewCollection);
     n.got_line_feed = got_line_feed;
     return n;
   }
@@ -101,7 +101,7 @@
 
     } else if (lhs.isSelector()){
 
-      return selectors_equal(*lhs.selector(), *rhs.selector(), simpleSelectorOrderDependent);
+      return selectors_equal(*&lhs.selector(), *&rhs.selector(), simpleSelectorOrderDependent);
 
     } else if (lhs.isCollection()) {
 
@@ -153,8 +153,7 @@
 
     } else if (node.isSelector()){
 
-      To_String to_string;
-      os << node.selector()->head()->perform(&to_string);
+      os << node.selector()->head()->to_string();
 
     } else if (node.isCollection()) {
 
@@ -178,7 +177,7 @@
 #endif
 
 
-  Node complexSelectorToNode(Complex_Selector* pToConvert, Context& ctx) {
+  Node complexSelectorToNode(Complex_Selector_Ptr pToConvert, Context& ctx) {
     if (pToConvert == NULL) {
       return Node::createNil();
     }
@@ -188,20 +187,20 @@
 
     // unwrap the selector from parent ref
     if (pToConvert->head() && pToConvert->head()->has_parent_ref()) {
-      Complex_Selector* tail = pToConvert->tail();
+      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() == NULL || empty_parent_ref) {
+      if (pToConvert->head() || empty_parent_ref) {
       }
 
       // the first Complex_Selector may contain a dummy head pointer, skip it.
-      if (pToConvert->head() != NULL && !empty_parent_ref) {
+      if (pToConvert->head() && !empty_parent_ref) {
         node.collection()->push_back(Node::createSelector(pToConvert, ctx));
         if (has_lf) node.collection()->back().got_line_feed = has_lf;
         has_lf = false;
@@ -217,21 +216,21 @@
         // pToConvert->tail()->has_line_feed(pToConvert->has_line_feed());
       }
 
-      pToConvert = pToConvert->tail();
+      pToConvert = &pToConvert->tail();
     }
 
     return node;
   }
 
 
-  Complex_Selector* nodeToComplexSelector(const Node& toConvert, Context& ctx) {
+  Complex_Selector_Ptr nodeToComplexSelector(const Node& toConvert, Context& ctx) {
     if (toConvert.isNil()) {
       return NULL;
     }
 
 
     if (!toConvert.isCollection()) {
-      throw "The node to convert to a Complex_Selector* must be a collection type or nil.";
+      throw "The node to convert to a Complex_Selector_Ptr must be a collection type or nil.";
     }
 
 
@@ -239,9 +238,9 @@
 
     std::string noPath("");
     Position noPosition(-1, -1, -1);
-    Complex_Selector* pFirst = SASS_MEMORY_NEW(ctx.mem, Complex_Selector, ParserState("[NODE]"), Complex_Selector::ANCESTOR_OF, NULL, NULL);
+    Complex_Selector_Obj pFirst = SASS_MEMORY_NEW(Complex_Selector, ParserState("[NODE]"), Complex_Selector::ANCESTOR_OF, NULL, NULL);
 
-    Complex_Selector* pCurrent = pFirst;
+    Complex_Selector_Obj pCurrent = pFirst;
 
     if (toConvert.isSelector()) pFirst->has_line_feed(toConvert.got_line_feed);
     if (toConvert.isCombinator()) pFirst->has_line_feed(toConvert.got_line_feed);
@@ -251,9 +250,11 @@
       Node& child = *childIter;
 
       if (child.isSelector()) {
-        pCurrent->tail(child.selector()->clone(ctx));   // JMA - need to clone the selector, because they can end up getting shared across Node collections, and can result in an infinite loop during the call to parentSuperselector()
+        // JMA - need to clone the selector, because they can end up getting shared across Node
+        // 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);
@@ -262,9 +263,9 @@
         if (childIter+1 != childIterEnd) {
           Node& nextNode = *(childIter+1);
           if (nextNode.isCombinator()) {
-            pCurrent->tail(SASS_MEMORY_NEW(ctx.mem, Complex_Selector, ParserState("[NODE]"), Complex_Selector::ANCESTOR_OF, NULL, NULL));
+            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 {
@@ -273,13 +274,13 @@
     }
 
     // Put the dummy Compound_Selector in the first position, for consistency with the rest of libsass
-    Compound_Selector* fakeHead = SASS_MEMORY_NEW(ctx.mem, Compound_Selector, ParserState("[NODE]"), 1);
-    Parent_Selector* selectorRef = SASS_MEMORY_NEW(ctx.mem, Parent_Selector, ParserState("[NODE]"));
+    Compound_Selector_Ptr fakeHead = SASS_MEMORY_NEW(Compound_Selector, ParserState("[NODE]"), 1);
+    Parent_Selector_Ptr selectorRef = SASS_MEMORY_NEW(Parent_Selector, ParserState("[NODE]"));
     fakeHead->elements().push_back(selectorRef);
     if (toConvert.got_line_feed) pFirst->has_line_feed(toConvert.got_line_feed);
     // pFirst->has_line_feed(pFirst->has_line_feed() || pFirst->tail()->has_line_feed() || toConvert.got_line_feed);
     pFirst->head(fakeHead);
-    return pFirst;
+    return SASS_MEMORY_COPY(pFirst);
   }
 
   // A very naive trim function, which removes duplicates in a node
@@ -287,7 +288,7 @@
   Node Node::naiveTrim(Node& seqses, Context& ctx) {
 
     std::vector<Node*> res;
-    std::vector<Complex_Selector*> known;
+    std::vector<Complex_Selector_Obj> known;
 
     NodeDeque::reverse_iterator seqsesIter = seqses.collection()->rbegin(),
                                 seqsesIterEnd = seqses.collection()->rend();
@@ -296,8 +297,8 @@
     {
       Node& seqs1 = *seqsesIter;
       if( seqs1.isSelector() ) {
-        Complex_Selector* sel = seqs1.selector();
-        std::vector<Complex_Selector*>::iterator it;
+        Complex_Selector_Obj sel = seqs1.selector();
+        std::vector<Complex_Selector_Obj>::iterator it;
         bool found = false;
         for (it = known.begin(); it != known.end(); ++it) {
           if (**it == *sel) { found = true; break; }
diff --git a/libsass/src/node.hpp b/libsass/src/node.hpp
--- a/libsass/src/node.hpp
+++ b/libsass/src/node.hpp
@@ -52,16 +52,16 @@
 
     Complex_Selector::Combinator combinator() const { return mCombinator; }
 
-    Complex_Selector* selector() { return mpSelector; }
-    const Complex_Selector* selector() const { return mpSelector; }
+    Complex_Selector_Obj selector() { return mpSelector; }
+    Complex_Selector_Obj selector() const { return mpSelector; }
 
     NodeDequePtr collection() { return mpCollection; }
     const NodeDequePtr collection() const { return mpCollection; }
 
     static Node createCombinator(const Complex_Selector::Combinator& combinator);
 
-    // This method will clone the selector, stripping off the tail and combinator
-    static Node createSelector(Complex_Selector* pSelector, Context& ctx);
+    // This method will klone the selector, stripping off the tail and combinator
+    static Node createSelector(Complex_Selector_Ptr pSelector, Context& ctx);
 
     static Node createCollection();
     static Node createCollection(const NodeDeque& values);
@@ -69,7 +69,7 @@
     static Node createNil();
     static Node naiveTrim(Node& seqses, Context& ctx);
 
-    Node clone(Context& ctx) const;
+    Node klone(Context& ctx) const;
 
     bool operator==(const Node& rhs) const;
     inline bool operator!=(const Node& rhs) const { return !(*this == rhs); }
@@ -97,21 +97,21 @@
     // Private constructor; Use the static methods (like createCombinator and createSelector)
     // to instantiate this object. This is more expressive, and it allows us to break apart each
     // case into separate functions.
-    Node(const TYPE& type, Complex_Selector::Combinator combinator, Complex_Selector* pSelector, NodeDequePtr& pCollection);
+    Node(const TYPE& type, Complex_Selector::Combinator combinator, Complex_Selector_Ptr pSelector, NodeDequePtr& pCollection);
 
     TYPE mType;
 
     // TODO: can we union these to save on memory?
     Complex_Selector::Combinator mCombinator;
-    Complex_Selector* mpSelector; // this is an AST_Node, so it will be handled by the Memory_Manager
+    Complex_Selector_Obj mpSelector;
     NodeDequePtr mpCollection;
   };
 
 #ifdef DEBUG
   std::ostream& operator<<(std::ostream& os, const Node& node);
 #endif
-  Node complexSelectorToNode(Complex_Selector* pToConvert, Context& ctx);
-  Complex_Selector* nodeToComplexSelector(const Node& toConvert, Context& ctx);
+  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);
 
diff --git a/libsass/src/operation.hpp b/libsass/src/operation.hpp
--- a/libsass/src/operation.hpp
+++ b/libsass/src/operation.hpp
@@ -8,78 +8,79 @@
   template<typename T>
   class Operation {
   public:
-    virtual T operator()(AST_Node* x)               = 0;
+    virtual T operator()(AST_Node_Ptr x)               = 0;
     virtual ~Operation()                            { }
     // statements
-    virtual T operator()(Block* x)                  = 0;
-    virtual T operator()(Ruleset* x)                = 0;
-    virtual T operator()(Propset* x)                = 0;
-    virtual T operator()(Bubble* x)                 = 0;
-    virtual T operator()(Supports_Block* x)          = 0;
-    virtual T operator()(Media_Block* x)            = 0;
-    virtual T operator()(At_Root_Block* x)          = 0;
-    virtual T operator()(At_Rule* x)                = 0;
-    virtual T operator()(Keyframe_Rule* x)          = 0;
-    virtual T operator()(Declaration* x)            = 0;
-    virtual T operator()(Assignment* x)             = 0;
-    virtual T operator()(Import* x)                 = 0;
-    virtual T operator()(Import_Stub* x)            = 0;
-    virtual T operator()(Warning* x)                = 0;
-    virtual T operator()(Error* x)                  = 0;
-    virtual T operator()(Debug* x)                  = 0;
-    virtual T operator()(Comment* x)                = 0;
-    virtual T operator()(If* x)                     = 0;
-    virtual T operator()(For* x)                    = 0;
-    virtual T operator()(Each* x)                   = 0;
-    virtual T operator()(While* x)                  = 0;
-    virtual T operator()(Return* x)                 = 0;
-    virtual T operator()(Content* x)                = 0;
-    virtual T operator()(Extension* x)              = 0;
-    virtual T operator()(Definition* x)             = 0;
-    virtual T operator()(Mixin_Call* x)             = 0;
+    virtual T operator()(Block_Ptr x)                  = 0;
+    virtual T operator()(Ruleset_Ptr x)                = 0;
+    virtual T operator()(Bubble_Ptr x)                 = 0;
+    virtual T operator()(Trace_Ptr x)                  = 0;
+    virtual T operator()(Supports_Block_Ptr x)         = 0;
+    virtual T operator()(Media_Block_Ptr x)            = 0;
+    virtual T operator()(At_Root_Block_Ptr x)          = 0;
+    virtual T operator()(Directive_Ptr x)              = 0;
+    virtual T operator()(Keyframe_Rule_Ptr x)          = 0;
+    virtual T operator()(Declaration_Ptr x)            = 0;
+    virtual T operator()(Assignment_Ptr x)             = 0;
+    virtual T operator()(Import_Ptr x)                 = 0;
+    virtual T operator()(Import_Stub_Ptr x)            = 0;
+    virtual T operator()(Warning_Ptr x)                = 0;
+    virtual T operator()(Error_Ptr x)                  = 0;
+    virtual T operator()(Debug_Ptr x)                  = 0;
+    virtual T operator()(Comment_Ptr x)                = 0;
+    virtual T operator()(If_Ptr x)                     = 0;
+    virtual T operator()(For_Ptr x)                    = 0;
+    virtual T operator()(Each_Ptr x)                   = 0;
+    virtual T operator()(While_Ptr x)                  = 0;
+    virtual T operator()(Return_Ptr x)                 = 0;
+    virtual T operator()(Content_Ptr x)                = 0;
+    virtual T operator()(Extension_Ptr x)              = 0;
+    virtual T operator()(Definition_Ptr x)             = 0;
+    virtual T operator()(Mixin_Call_Ptr x)             = 0;
     // expressions
-    virtual T operator()(List* x)                   = 0;
-    virtual T operator()(Map* x)                    = 0;
-    virtual T operator()(Binary_Expression* x)      = 0;
-    virtual T operator()(Unary_Expression* x)       = 0;
-    virtual T operator()(Function_Call* x)          = 0;
-    virtual T operator()(Function_Call_Schema* x)   = 0;
-    virtual T operator()(Custom_Warning* x)         = 0;
-    virtual T operator()(Custom_Error* x)           = 0;
-    virtual T operator()(Variable* x)               = 0;
-    virtual T operator()(Textual* x)                = 0;
-    virtual T operator()(Number* x)                 = 0;
-    virtual T operator()(Color* x)                  = 0;
-    virtual T operator()(Boolean* x)                = 0;
-    virtual T operator()(String_Schema* x)          = 0;
-    virtual T operator()(String_Quoted* x)          = 0;
-    virtual T operator()(String_Constant* x)        = 0;
-    virtual T operator()(Supports_Condition* x)     = 0;
-    virtual T operator()(Supports_Operator* x)      = 0;
-    virtual T operator()(Supports_Negation* x)      = 0;
-    virtual T operator()(Supports_Declaration* x)   = 0;
-    virtual T operator()(Supports_Interpolation* x) = 0;
-    virtual T operator()(Media_Query* x)            = 0;
-    virtual T operator()(Media_Query_Expression* x) = 0;
-    virtual T operator()(At_Root_Expression* x)     = 0;
-    virtual T operator()(Null* x)                   = 0;
-    virtual T operator()(Parent_Selector* x)        = 0;
+    virtual T operator()(List_Ptr x)                   = 0;
+    virtual T operator()(Map_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;
+    virtual T operator()(Function_Call_Schema_Ptr x)   = 0;
+    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;
+    virtual T operator()(String_Schema_Ptr x)          = 0;
+    virtual T operator()(String_Quoted_Ptr x)          = 0;
+    virtual T operator()(String_Constant_Ptr x)        = 0;
+    virtual T operator()(Supports_Condition_Ptr x)     = 0;
+    virtual T operator()(Supports_Operator_Ptr x)      = 0;
+    virtual T operator()(Supports_Negation_Ptr x)      = 0;
+    virtual T operator()(Supports_Declaration_Ptr x)   = 0;
+    virtual T operator()(Supports_Interpolation_Ptr x) = 0;
+    virtual T operator()(Media_Query_Ptr x)            = 0;
+    virtual T operator()(Media_Query_Expression_Ptr x) = 0;
+    virtual T operator()(At_Root_Query_Ptr x)          = 0;
+    virtual T operator()(Null_Ptr x)                   = 0;
+    virtual T operator()(Parent_Selector_Ptr x)        = 0;
     // parameters and arguments
-    virtual T operator()(Parameter* x)              = 0;
-    virtual T operator()(Parameters* x)             = 0;
-    virtual T operator()(Argument* x)               = 0;
-    virtual T operator()(Arguments* x)              = 0;
+    virtual T operator()(Parameter_Ptr x)              = 0;
+    virtual T operator()(Parameters_Ptr x)             = 0;
+    virtual T operator()(Argument_Ptr x)               = 0;
+    virtual T operator()(Arguments_Ptr x)              = 0;
     // selectors
-    virtual T operator()(Selector_Schema* x)        = 0;
-    virtual T operator()(Selector_Placeholder* x)   = 0;
-    virtual T operator()(Type_Selector* x)          = 0;
-    virtual T operator()(Selector_Qualifier* x)     = 0;
-    virtual T operator()(Attribute_Selector* x)     = 0;
-    virtual T operator()(Pseudo_Selector* x)        = 0;
-    virtual T operator()(Wrapped_Selector* x)       = 0;
-    virtual T operator()(Compound_Selector* x)      = 0;
-    virtual T operator()(Complex_Selector* x)       = 0;
-    virtual T operator()(Selector_List* x)          = 0;
+    virtual T operator()(Selector_Schema_Ptr x)        = 0;
+    virtual T operator()(Placeholder_Selector_Ptr x)   = 0;
+    virtual T operator()(Element_Selector_Ptr x)       = 0;
+    virtual T operator()(Class_Selector_Ptr x)         = 0;
+    virtual T operator()(Id_Selector_Ptr x)            = 0;
+    virtual T operator()(Attribute_Selector_Ptr x)     = 0;
+    virtual T operator()(Pseudo_Selector_Ptr x)        = 0;
+    virtual T operator()(Wrapped_Selector_Ptr x)       = 0;
+    virtual T operator()(Compound_Selector_Ptr x)= 0;
+    virtual T operator()(Complex_Selector_Ptr x)      = 0;
+    virtual T operator()(Selector_List_Ptr x) = 0;
 
     template <typename U>
     T fallback(U x) { return T(); }
@@ -88,84 +89,84 @@
   template <typename T, typename D>
   class Operation_CRTP : public Operation<T> {
   public:
-    virtual T operator()(AST_Node* x)               { return static_cast<D*>(this)->fallback(x); }
-    virtual ~Operation_CRTP()                       = 0;
+    D& impl() { return static_cast<D&>(*this); }
+  public:
+    T operator()(AST_Node_Ptr x)               { return static_cast<D*>(this)->fallback(x); }
     // statements
-    virtual T operator()(Block* x)                  { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Ruleset* x)                { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Propset* x)                { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Bubble* x)                 { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Supports_Block* x)          { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Media_Block* x)            { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(At_Root_Block* x)          { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(At_Rule* x)                { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Keyframe_Rule* x)          { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Declaration* x)            { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Assignment* x)             { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Import* x)                 { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Import_Stub* x)            { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Warning* x)                { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Error* x)                  { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Debug* x)                  { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Comment* x)                { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(If* x)                     { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(For* x)                    { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Each* x)                   { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(While* x)                  { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Return* x)                 { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Content* x)                { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Extension* x)              { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Definition* x)             { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Mixin_Call* x)             { return static_cast<D*>(this)->fallback(x); }
+    T operator()(Block_Ptr x)                  { return static_cast<D*>(this)->fallback(x); }
+    T operator()(Ruleset_Ptr x)                { return static_cast<D*>(this)->fallback(x); }
+    T operator()(Bubble_Ptr x)                 { return static_cast<D*>(this)->fallback(x); }
+    T operator()(Trace_Ptr x)                  { return static_cast<D*>(this)->fallback(x); }
+    T operator()(Supports_Block_Ptr x)         { return static_cast<D*>(this)->fallback(x); }
+    T operator()(Media_Block_Ptr x)            { return static_cast<D*>(this)->fallback(x); }
+    T operator()(At_Root_Block_Ptr x)          { return static_cast<D*>(this)->fallback(x); }
+    T operator()(Directive_Ptr x)              { return static_cast<D*>(this)->fallback(x); }
+    T operator()(Keyframe_Rule_Ptr x)          { return static_cast<D*>(this)->fallback(x); }
+    T operator()(Declaration_Ptr x)            { return static_cast<D*>(this)->fallback(x); }
+    T operator()(Assignment_Ptr x)             { return static_cast<D*>(this)->fallback(x); }
+    T operator()(Import_Ptr x)                 { return static_cast<D*>(this)->fallback(x); }
+    T operator()(Import_Stub_Ptr x)            { return static_cast<D*>(this)->fallback(x); }
+    T operator()(Warning_Ptr x)                { return static_cast<D*>(this)->fallback(x); }
+    T operator()(Error_Ptr x)                  { return static_cast<D*>(this)->fallback(x); }
+    T operator()(Debug_Ptr x)                  { return static_cast<D*>(this)->fallback(x); }
+    T operator()(Comment_Ptr x)                { return static_cast<D*>(this)->fallback(x); }
+    T operator()(If_Ptr x)                     { return static_cast<D*>(this)->fallback(x); }
+    T operator()(For_Ptr x)                    { return static_cast<D*>(this)->fallback(x); }
+    T operator()(Each_Ptr x)                   { return static_cast<D*>(this)->fallback(x); }
+    T operator()(While_Ptr x)                  { return static_cast<D*>(this)->fallback(x); }
+    T operator()(Return_Ptr x)                 { return static_cast<D*>(this)->fallback(x); }
+    T operator()(Content_Ptr x)                { return static_cast<D*>(this)->fallback(x); }
+    T operator()(Extension_Ptr x)              { return static_cast<D*>(this)->fallback(x); }
+    T operator()(Definition_Ptr x)             { return static_cast<D*>(this)->fallback(x); }
+    T operator()(Mixin_Call_Ptr x)             { return static_cast<D*>(this)->fallback(x); }
     // expressions
-    virtual T operator()(List* x)                   { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Map* x)                    { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Binary_Expression* x)      { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Unary_Expression* x)       { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Function_Call* x)          { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Function_Call_Schema* x)   { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Custom_Warning* x)         { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Custom_Error* x)           { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Variable* x)               { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Textual* x)                { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Number* x)                 { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Color* x)                  { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Boolean* x)                { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(String_Schema* x)          { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(String_Constant* x)        { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(String_Quoted* x)          { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Supports_Condition* x)     { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Supports_Operator* x)      { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Supports_Negation* x)      { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Supports_Declaration* x)   { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Supports_Interpolation* x) { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Media_Query* x)            { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Media_Query_Expression* x) { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(At_Root_Expression* x)     { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Null* x)                   { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Parent_Selector* x)        { return static_cast<D*>(this)->fallback(x); }
+    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()(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); }
+    T operator()(Function_Call_Schema_Ptr x)   { return static_cast<D*>(this)->fallback(x); }
+    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); }
+    T operator()(String_Schema_Ptr x)          { return static_cast<D*>(this)->fallback(x); }
+    T operator()(String_Constant_Ptr x)        { return static_cast<D*>(this)->fallback(x); }
+    T operator()(String_Quoted_Ptr x)          { return static_cast<D*>(this)->fallback(x); }
+    T operator()(Supports_Condition_Ptr x)     { return static_cast<D*>(this)->fallback(x); }
+    T operator()(Supports_Operator_Ptr x)      { return static_cast<D*>(this)->fallback(x); }
+    T operator()(Supports_Negation_Ptr x)      { return static_cast<D*>(this)->fallback(x); }
+    T operator()(Supports_Declaration_Ptr x)   { return static_cast<D*>(this)->fallback(x); }
+    T operator()(Supports_Interpolation_Ptr x) { return static_cast<D*>(this)->fallback(x); }
+    T operator()(Media_Query_Ptr x)            { return static_cast<D*>(this)->fallback(x); }
+    T operator()(Media_Query_Expression_Ptr x) { return static_cast<D*>(this)->fallback(x); }
+    T operator()(At_Root_Query_Ptr x)          { return static_cast<D*>(this)->fallback(x); }
+    T operator()(Null_Ptr x)                   { return static_cast<D*>(this)->fallback(x); }
+    T operator()(Parent_Selector_Ptr x)        { return static_cast<D*>(this)->fallback(x); }
     // parameters and arguments
-    virtual T operator()(Parameter* x)              { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Parameters* x)             { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Argument* x)               { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Arguments* x)              { return static_cast<D*>(this)->fallback(x); }
+    T operator()(Parameter_Ptr x)              { return static_cast<D*>(this)->fallback(x); }
+    T operator()(Parameters_Ptr x)             { return static_cast<D*>(this)->fallback(x); }
+    T operator()(Argument_Ptr x)               { return static_cast<D*>(this)->fallback(x); }
+    T operator()(Arguments_Ptr x)              { return static_cast<D*>(this)->fallback(x); }
     // selectors
-    virtual T operator()(Selector_Schema* x)        { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Selector_Placeholder* x)   { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Type_Selector* x)          { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Selector_Qualifier* x)     { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Attribute_Selector* x)     { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Pseudo_Selector* x)        { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Wrapped_Selector* x)       { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Compound_Selector* x)      { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Complex_Selector* x)       { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Selector_List* x)          { return static_cast<D*>(this)->fallback(x); }
+    T operator()(Selector_Schema_Ptr x)        { return static_cast<D*>(this)->fallback(x); }
+    T operator()(Placeholder_Selector_Ptr x)   { return static_cast<D*>(this)->fallback(x); }
+    T operator()(Element_Selector_Ptr x)       { return static_cast<D*>(this)->fallback(x); }
+    T operator()(Class_Selector_Ptr x)         { return static_cast<D*>(this)->fallback(x); }
+    T operator()(Id_Selector_Ptr x)            { return static_cast<D*>(this)->fallback(x); }
+    T operator()(Attribute_Selector_Ptr x)     { return static_cast<D*>(this)->fallback(x); }
+    T operator()(Pseudo_Selector_Ptr x)        { return static_cast<D*>(this)->fallback(x); }
+    T operator()(Wrapped_Selector_Ptr x)       { return static_cast<D*>(this)->fallback(x); }
+    T operator()(Compound_Selector_Ptr x){ return static_cast<D*>(this)->fallback(x); }
+    T operator()(Complex_Selector_Ptr x)      { return static_cast<D*>(this)->fallback(x); }
+    T operator()(Selector_List_Ptr x) { return static_cast<D*>(this)->fallback(x); }
 
     template <typename U>
-    T fallback(U x)                                 { return T(); }
+    T fallback(U x)                         { return T(); }
   };
-  template<typename T, typename D>
-  inline Operation_CRTP<T, D>::~Operation_CRTP()    { }
 
 }
 
diff --git a/libsass/src/output.cpp b/libsass/src/output.cpp
--- a/libsass/src/output.cpp
+++ b/libsass/src/output.cpp
@@ -1,56 +1,50 @@
+#include "sass.hpp"
 #include "ast.hpp"
 #include "output.hpp"
-#include "to_string.hpp"
 
 namespace Sass {
 
-  Output::Output(Context* ctx)
-  : Inspect(Emitter(ctx)),
+  Output::Output(Sass_Output_Options& opt)
+  : Inspect(Emitter(opt)),
     charset(""),
     top_nodes(0)
   {}
 
   Output::~Output() { }
 
-  void Output::fallback_impl(AST_Node* n)
+  void Output::fallback_impl(AST_Node_Ptr n)
   {
     return n->perform(this);
   }
 
-  void Output::operator()(Number* n)
+  void Output::operator()(Number_Ptr n)
   {
     // use values to_string facility
-    To_String to_string(ctx);
-    std::string res = n->perform(&to_string);
+    std::string res = n->to_string(opt);
     // check for a valid unit here
     // includes result for reporting
-    if (n->numerator_units().size() > 1 ||
-        n->denominator_units().size() > 0 ||
-        (n->numerator_units().size() && n->numerator_units()[0].find_first_of('/') != std::string::npos) ||
-        (n->numerator_units().size() && n->numerator_units()[0].find_first_of('*') != std::string::npos)
-    ) {
-      error(res + " isn't a valid CSS value.", n->pstate());
+    if (!n->is_valid_css_unit()) {
+      throw Exception::InvalidValue(*n);
     }
     // output the final token
     append_token(res, n);
   }
 
-  void Output::operator()(Import* imp)
+  void Output::operator()(Import_Ptr imp)
   {
     top_nodes.push_back(imp);
   }
 
-  void Output::operator()(Map* m)
+  void Output::operator()(Map_Ptr m)
   {
-    To_String to_string(ctx);
-    std::string dbg(m->perform(&to_string));
+    std::string dbg(m->to_string(opt));
     error(dbg + " isn't a valid CSS value.", m->pstate());
   }
 
   OutputBuffer Output::get_buffer(void)
   {
 
-    Emitter emitter(ctx);
+    Emitter emitter(opt);
     Inspect inspect(emitter);
 
     size_t size_nodes = top_nodes.size();
@@ -60,23 +54,25 @@
     }
 
     // flush scheduled outputs
-    inspect.finalize();
+    // maybe omit semicolon if possible
+    inspect.finalize(wbuf.buffer.size() == 0);
     // prepend buffer on top
     prepend_output(inspect.output());
     // make sure we end with a linefeed
-    if (!ends_with(wbuf.buffer, ctx->linefeed)) {
+    if (!ends_with(wbuf.buffer, opt.linefeed)) {
       // if the output is not completely empty
-      if (!wbuf.buffer.empty()) append_string(ctx->linefeed);
+      if (!wbuf.buffer.empty()) append_string(opt.linefeed);
     }
 
     // search for unicode char
     for(const char& chr : wbuf.buffer) {
       // skip all ascii chars
-      if (chr >= 0) continue;
+      // static cast to unsigned to handle `char` being signed / unsigned
+      if (static_cast<unsigned>(chr) < 128) continue;
       // declare the charset
-      if (output_style() != SASS_STYLE_COMPRESSED)
+      if (output_style() != COMPRESSED)
         charset = "@charset \"UTF-8\";"
-                  + ctx->linefeed;
+                + std::string(opt.linefeed);
       else charset = "\xEF\xBB\xBF";
       // abort search
       break;
@@ -89,13 +85,12 @@
 
   }
 
-  void Output::operator()(Comment* c)
+  void Output::operator()(Comment_Ptr c)
   {
-    To_String to_string(ctx);
-    std::string txt = c->text()->perform(&to_string);
+    std::string txt = c->text()->to_string(opt);
     // if (indentation && txt == "/**/") return;
     bool important = c->is_important();
-    if (output_style() != SASS_STYLE_COMPRESSED || important) {
+    if (output_style() != COMPRESSED || important) {
       if (buffer().size() == 0) {
         top_nodes.push_back(c);
       } else {
@@ -112,87 +107,72 @@
     }
   }
 
-  void Output::operator()(Ruleset* r)
+  void Output::operator()(Ruleset_Ptr r)
   {
-    Selector* s     = r->selector();
-    Block*    b     = r->block();
-    bool      decls = false;
+    Selector_Obj s     = r->selector();
+    Block_Obj    b     = r->block();
 
     // Filter out rulesets that aren't printable (process its children though)
     if (!Util::isPrintable(r, output_style())) {
       for (size_t i = 0, L = b->length(); i < L; ++i) {
-        Statement* stm = (*b)[i];
-        if (dynamic_cast<Has_Block*>(stm)) {
-          stm->perform(this);
+        const Statement_Obj& stm = b->at(i);
+        if (dynamic_cast<Has_Block_Ptr>(&stm)) {
+          if (!dynamic_cast<Declaration_Ptr>(&stm)) {
+            stm->perform(this);
+          }
         }
       }
       return;
     }
 
-    if (b->has_non_hoistable()) {
-      decls = true;
-      if (output_style() == SASS_STYLE_NESTED) indentation += r->tabs();
-      if (ctx && ctx->c_options->source_comments) {
-        std::stringstream ss;
-        append_indentation();
-        ss << "/* line " << r->pstate().line + 1 << ", " << r->pstate().path << " */";
-        append_string(ss.str());
-        append_optional_linefeed();
-      }
-      s->perform(this);
-      append_scope_opener(b);
-      for (size_t i = 0, L = b->length(); i < L; ++i) {
-        Statement* stm = (*b)[i];
-        bool bPrintExpression = true;
-        // Check print conditions
-        if (typeid(*stm) == typeid(Declaration)) {
-          Declaration* dec = static_cast<Declaration*>(stm);
-          if (dec->value()->concrete_type() == Expression::STRING) {
-            String_Constant* valConst = static_cast<String_Constant*>(dec->value());
-            std::string val(valConst->value());
-            if (auto qstr = dynamic_cast<String_Quoted*>(valConst)) {
-              if (!qstr->quote_mark() && val.empty()) {
-                bPrintExpression = false;
-              }
+    if (output_style() == NESTED) indentation += r->tabs();
+    if (opt.source_comments) {
+      std::stringstream ss;
+      append_indentation();
+      std::string path(File::abs2rel(r->pstate().path));
+      ss << "/* line " << r->pstate().line + 1 << ", " << path << " */";
+      append_string(ss.str());
+      append_optional_linefeed();
+    }
+    if (s) s->perform(this);
+    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())) {
+          std::string val(valConst->value());
+          if (String_Quoted_Ptr qstr = SASS_MEMORY_CAST_PTR(String_Quoted, valConst)) {
+            if (!qstr->quote_mark() && val.empty()) {
+              bPrintExpression = false;
             }
           }
-          else if (dec->value()->concrete_type() == Expression::LIST) {
-            List* list = static_cast<List*>(dec->value());
-            bool all_invisible = true;
-            for (size_t list_i = 0, list_L = list->length(); list_i < list_L; ++list_i) {
-              Expression* item = (*list)[list_i];
-              if (!item->is_invisible()) all_invisible = false;
-            }
-            if (all_invisible) bPrintExpression = false;
-          }
         }
-        // Print if OK
-        if (!stm->is_hoistable() && bPrintExpression) {
-          stm->perform(this);
+        else if (List_Ptr list = SASS_MEMORY_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);
+            if (!item->is_invisible()) all_invisible = false;
+          }
+          if (all_invisible) bPrintExpression = false;
         }
       }
-      if (output_style() == SASS_STYLE_NESTED) indentation -= r->tabs();
-      append_scope_closer(b);
-    }
-
-    if (b->has_hoistable()) {
-      if (decls) ++indentation;
-      for (size_t i = 0, L = b->length(); i < L; ++i) {
-        Statement* stm = (*b)[i];
-        if (stm->is_hoistable()) {
-          stm->perform(this);
-        }
+      // Print if OK
+      if (bPrintExpression) {
+        stm->perform(this);
       }
-      if (decls) --indentation;
     }
-  }
+    if (output_style() == NESTED) indentation -= r->tabs();
+    append_scope_closer(&b);
 
-  void Output::operator()(Keyframe_Rule* r)
+  }
+  void Output::operator()(Keyframe_Rule_Ptr r)
   {
-    Block* b = r->block();
-    Selector* v = r->selector();
+    Block_Obj b = r->block();
+    Selector_Obj v = r->name();
 
-    if (v) {
+    if (&v) {
       v->perform(this);
     }
 
@@ -203,124 +183,93 @@
 
     append_scope_opener();
     for (size_t i = 0, L = b->length(); i < L; ++i) {
-      Statement* stm = (*b)[i];
-      if (!stm->is_hoistable()) {
-        stm->perform(this);
-        if (i < L - 1) append_special_linefeed();
-      }
-    }
-
-    for (size_t i = 0, L = b->length(); i < L; ++i) {
-      Statement* stm = (*b)[i];
-      if (stm->is_hoistable()) {
-        stm->perform(this);
-      }
+      Statement_Obj stm = b->at(i);
+      stm->perform(this);
+      if (i < L - 1) append_special_linefeed();
     }
-
     append_scope_closer();
   }
 
-  void Output::operator()(Supports_Block* f)
+  void Output::operator()(Supports_Block_Ptr f)
   {
     if (f->is_invisible()) return;
 
-    Supports_Condition* c = f->condition();
-    Block* b              = f->block();
+    Supports_Condition_Obj c = f->condition();
+    Block_Obj b              = f->block();
 
     // Filter out feature blocks that aren't printable (process its children though)
     if (!Util::isPrintable(f, output_style())) {
       for (size_t i = 0, L = b->length(); i < L; ++i) {
-        Statement* stm = (*b)[i];
-        if (dynamic_cast<Has_Block*>(stm)) {
+        Statement_Obj stm = b->at(i);
+        if (dynamic_cast<Has_Block_Ptr>(&stm)) {
           stm->perform(this);
         }
       }
       return;
     }
 
-    if (output_style() == SASS_STYLE_NESTED) indentation += f->tabs();
+    if (output_style() == NESTED) indentation += f->tabs();
     append_indentation();
     append_token("@supports", f);
     append_mandatory_space();
     c->perform(this);
     append_scope_opener();
 
-    if (b->has_non_hoistable()) {
-      // JMA - hoisted, output the non-hoistable in a nested block, followed by the hoistable
-      append_scope_opener();
-
-      for (size_t i = 0, L = b->length(); i < L; ++i) {
-        Statement* stm = (*b)[i];
-        if (!stm->is_hoistable()) {
-          stm->perform(this);
-        }
-      }
-
-      append_scope_closer();
-
-      for (size_t i = 0, L = b->length(); i < L; ++i) {
-        Statement* stm = (*b)[i];
-        if (stm->is_hoistable()) {
-          stm->perform(this);
-        }
-      }
-    }
-    else {
-      // JMA - not hoisted, just output in order
-      for (size_t i = 0, L = b->length(); i < L; ++i) {
-        Statement* stm = (*b)[i];
-        stm->perform(this);
-        if (i < L - 1) append_special_linefeed();
-      }
+    for (size_t i = 0, L = b->length(); i < L; ++i) {
+      Statement_Obj stm = b->at(i);
+      stm->perform(this);
+      if (i < L - 1) append_special_linefeed();
     }
 
-    if (output_style() == SASS_STYLE_NESTED) indentation -= f->tabs();
+    if (output_style() == NESTED) indentation -= f->tabs();
 
     append_scope_closer();
 
   }
 
-  void Output::operator()(Media_Block* m)
+  void Output::operator()(Media_Block_Ptr m)
   {
     if (m->is_invisible()) return;
 
-    List*  q     = m->media_queries();
-    Block* b     = m->block();
+    Block_Obj b     = m->block();
 
     // Filter out media blocks that aren't printable (process its children though)
     if (!Util::isPrintable(m, output_style())) {
       for (size_t i = 0, L = b->length(); i < L; ++i) {
-        Statement* stm = (*b)[i];
-        if (dynamic_cast<Has_Block*>(stm)) {
+        Statement_Obj stm = b->at(i);
+        if (dynamic_cast<Has_Block_Ptr>(&stm)) {
           stm->perform(this);
         }
       }
       return;
     }
-    if (output_style() == SASS_STYLE_NESTED) indentation += m->tabs();
+    if (output_style() == NESTED) indentation += m->tabs();
     append_indentation();
     append_token("@media", m);
     append_mandatory_space();
     in_media_block = true;
-    q->perform(this);
+    m->media_queries()->perform(this);
     in_media_block = false;
     append_scope_opener();
 
     for (size_t i = 0, L = b->length(); i < L; ++i) {
-      if ((*b)[i]) (*b)[i]->perform(this);
+      if (b->at(i)) {
+      Statement_Obj stm = b->at(i);
+        stm->perform(this);
+      }
       if (i < L - 1) append_special_linefeed();
     }
 
-    if (output_style() == SASS_STYLE_NESTED) indentation -= m->tabs();
+    if (output_style() == NESTED) indentation -= m->tabs();
     append_scope_closer();
   }
 
-  void Output::operator()(At_Rule* a)
+  void Output::operator()(Directive_Ptr a)
   {
     std::string      kwd   = a->keyword();
-    Selector*   s     = a->selector();
-    Expression* v     = a->value();
-    Block*      b     = a->block();
+    Selector_Obj   s     = a->selector();
+    Expression_Obj v     = a->value();
+    Block_Obj      b     = a->block();
 
     append_indentation();
     append_token(kwd, a);
@@ -332,7 +281,8 @@
     }
     if (v) {
       append_mandatory_space();
-      v->perform(this);
+      // ruby sass bug? should use options?
+      append_token(v->to_string(/* opt */), &v);
     }
     if (!b) {
       append_delimiter();
@@ -340,7 +290,8 @@
     }
 
     if (b->is_invisible() || b->length() == 0) {
-      return append_string(" {}");
+      append_optional_space();
+      return append_string("{}");
     }
 
     append_scope_opener();
@@ -348,25 +299,15 @@
     bool format = kwd != "@font-face";;
 
     for (size_t i = 0, L = b->length(); i < L; ++i) {
-      Statement* stm = (*b)[i];
-      if (!stm->is_hoistable()) {
-        stm->perform(this);
-        if (i < L - 1 && format) append_special_linefeed();
-      }
-    }
-
-    for (size_t i = 0, L = b->length(); i < L; ++i) {
-      Statement* stm = (*b)[i];
-      if (stm->is_hoistable()) {
-        stm->perform(this);
-        if (i < L - 1 && format) append_special_linefeed();
-      }
+      Statement_Obj stm = b->at(i);
+      stm->perform(this);
+      if (i < L - 1 && format) append_special_linefeed();
     }
 
     append_scope_closer();
   }
 
-  void Output::operator()(String_Quoted* s)
+  void Output::operator()(String_Quoted_Ptr s)
   {
     if (s->quote_mark()) {
       append_token(quote(s->value(), s->quote_mark()), s);
@@ -377,10 +318,10 @@
     }
   }
 
-  void Output::operator()(String_Constant* s)
+  void Output::operator()(String_Constant_Ptr s)
   {
     std::string value(s->value());
-    if (s->can_compress_whitespace() && output_style() == SASS_STYLE_COMPRESSED) {
+    if (s->can_compress_whitespace() && output_style() == COMPRESSED) {
       value.erase(std::remove_if(value.begin(), value.end(), ::isspace), value.end());
     }
     if (!in_comment) {
diff --git a/libsass/src/output.hpp b/libsass/src/output.hpp
--- a/libsass/src/output.hpp
+++ b/libsass/src/output.hpp
@@ -23,31 +23,29 @@
     using Inspect::operator();
 
   public:
-    // change to Emitter
-    Output(Context* ctx);
+    Output(Sass_Output_Options& opt);
     virtual ~Output();
 
   protected:
     std::string charset;
-    std::vector<AST_Node*> top_nodes;
+    std::vector<AST_Node_Ptr> top_nodes;
 
   public:
     OutputBuffer get_buffer(void);
 
-    virtual void operator()(Map*);
-    virtual void operator()(Ruleset*);
-    // virtual void operator()(Propset*);
-    virtual void operator()(Supports_Block*);
-    virtual void operator()(Media_Block*);
-    virtual void operator()(At_Rule*);
-    virtual void operator()(Keyframe_Rule*);
-    virtual void operator()(Import*);
-    virtual void operator()(Comment*);
-    virtual void operator()(Number*);
-    virtual void operator()(String_Quoted*);
-    virtual void operator()(String_Constant*);
+    virtual void operator()(Map_Ptr);
+    virtual void operator()(Ruleset_Ptr);
+    virtual void operator()(Supports_Block_Ptr);
+    virtual void operator()(Media_Block_Ptr);
+    virtual void operator()(Directive_Ptr);
+    virtual void operator()(Keyframe_Rule_Ptr);
+    virtual void operator()(Import_Ptr);
+    virtual void operator()(Comment_Ptr);
+    virtual void operator()(Number_Ptr);
+    virtual void operator()(String_Quoted_Ptr);
+    virtual void operator()(String_Constant_Ptr);
 
-    void fallback_impl(AST_Node* n);
+    void fallback_impl(AST_Node_Ptr n);
 
   };
 
diff --git a/libsass/src/parser.cpp b/libsass/src/parser.cpp
--- a/libsass/src/parser.cpp
+++ b/libsass/src/parser.cpp
@@ -1,2434 +1,2774 @@
-#include <cstdlib>
-#include <iostream>
-#include <vector>
-#include "parser.hpp"
-#include "file.hpp"
-#include "inspect.hpp"
-#include "to_string.hpp"
-#include "constants.hpp"
-#include "util.hpp"
-#include "prelexer.hpp"
-#include "color_maps.hpp"
-#include "sass/functions.h"
-#include "error_handling.hpp"
-
-#include <typeinfo>
-#include <tuple>
-
-namespace Sass {
-  using namespace Constants;
-  using namespace Prelexer;
-
-  Parser Parser::from_c_str(const char* str, Context& ctx, ParserState pstate)
-  {
-    Parser p(ctx, pstate);
-    p.source   = str;
-    p.position = p.source;
-    p.end      = str + strlen(str);
-    Block* root = SASS_MEMORY_NEW(ctx.mem, 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)
-  {
-    Parser p(ctx, pstate);
-    p.source   = beg;
-    p.position = p.source;
-    p.end      = end;
-    Block* root = SASS_MEMORY_NEW(ctx.mem, Block, pstate);
-    p.block_stack.push_back(root);
-    root->is_root(true);
-    return p;
-  }
-
-  Selector_List* Parser::parse_selector(const char* src, Context& ctx, ParserState pstate)
-  {
-    Parser p = Parser::from_c_str(src, ctx, pstate);
-    // ToDo: ruby sass errors on parent references
-    // ToDo: remap the source-map entries somehow
-    return p.parse_selector_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)
-  {
-    Parser p(ctx, pstate);
-    p.source   = t.begin;
-    p.position = p.source;
-    p.end      = t.end;
-    Block* root = SASS_MEMORY_NEW(ctx.mem, Block, pstate);
-    p.block_stack.push_back(root);
-    root->is_root(true);
-    return p;
-  }
-
-  /* main entry point to parse root block */
-  Block* Parser::parse()
-  {
-    bool is_root = false;
-    Block* root = SASS_MEMORY_NEW(ctx.mem, 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* 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* block = SASS_MEMORY_NEW(ctx.mem, 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
-    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* 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* block = block_stack.back();
-
-    while (lex< block_comment >()) {
-      bool is_important = lexed.begin[2] == '!';
-      String*  contents = parse_interpolated_chunk(lexed);
-      (*block) << SASS_MEMORY_NEW(ctx.mem, Comment, pstate, contents, is_important);
-    }
-
-    // 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) << parse_assignment(); }
-    else if (lex < kwd_err >(true)) { (*block) << parse_error(); }
-    else if (lex < kwd_dbg >(true)) { (*block) << parse_debug(); }
-    else if (lex < kwd_warn >(true)) { (*block) << parse_warning(); }
-    else if (lex < kwd_if_directive >(true)) { (*block) << parse_if_directive(); }
-    else if (lex < kwd_for_directive >(true)) { (*block) << parse_for_directive(); }
-    else if (lex < kwd_each_directive >(true)) { (*block) << parse_each_directive(); }
-    else if (lex < kwd_while_directive >(true)) { (*block) << parse_while_directive(); }
-    else if (lex < kwd_return_directive >(true)) { (*block) << parse_return_directive(); }
-
-    // abort if we are in function context and have nothing parsed yet
-    else if (stack.back() == function_def) {
-      error("Functions can only contain variable declarations and control directives", pstate);
-    }
-
-    // parse imports to process later
-    else if (lex < kwd_import >(true)) {
-      if (stack.back() == mixin_def || stack.back() == function_def) {
-        error("Import directives may not be used within control directives or mixins.", pstate);
-      }
-      Import* imp = parse_import();
-      // if it is a url, we only add the statement
-      if (!imp->urls().empty()) (*block) << imp;
-      // process all resources now (add Import_Stub nodes)
-      for (size_t i = 0, S = imp->incs().size(); i < S; ++i) {
-        (*block) << SASS_MEMORY_NEW(ctx.mem, Import_Stub, pstate, imp->incs()[i]);
-      }
-    }
-
-    else if (lex < kwd_extend >(true)) {
-      if (block->is_root()) {
-        error("Extend directives may only be used within rules.", pstate);
-      }
-
-      Lookahead lookahead = lookahead_for_include(position);
-      if (!lookahead.found) css_error("Invalid CSS", " after ", ": expected selector, was ");
-      Selector* target;
-      if (lookahead.has_interpolants) target = parse_selector_schema(lookahead.found);
-      else                            target = parse_selector_list(true);
-      (*block) << SASS_MEMORY_NEW(ctx.mem, Extension, pstate, target);
-    }
-
-    // selector may contain interpolations which need delayed evaluation
-    else if (!(lookahead_result = lookahead_for_selector(position)).error)
-    { (*block) << parse_ruleset(lookahead_result, is_root); }
-
-    // parse multiple specific keyword directives
-    else if (lex < kwd_media >(true)) { (*block) << parse_media_block(); }
-    else if (lex < kwd_at_root >(true)) { (*block) << parse_at_root_block(); }
-    else if (lex < kwd_include_directive >(true)) { (*block) << parse_include_directive(); }
-    else if (lex < kwd_content_directive >(true)) { (*block) << parse_content_directive(); }
-    else if (lex < kwd_supports_directive >(true)) { (*block) << parse_supports_directive(); }
-    else if (lex < kwd_mixin >(true)) { (*block) << parse_definition(Definition::MIXIN); }
-    else if (lex < kwd_function >(true)) { (*block) << 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< at_keyword >(true)) { (*block) << parse_at_rule(); }
-
-    else if (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* decl = parse_declaration();
-      decl->tabs(indentation);
-      (*block) << 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
-        (*block) << SASS_MEMORY_NEW(ctx.mem, Propset, pstate, decl->property(), parse_block());
-        if (decl->is_indented()) -- indentation;
-      }
-    }
-    // something matched
-    return true;
-  }
-  // EO parse_block_nodes
-
-  // parse imports inside the
-  Import* Parser::parse_import()
-  {
-    Import* imp = SASS_MEMORY_NEW(ctx.mem, Import, pstate);
-    std::vector<std::pair<std::string,Function_Call*>> to_import;
-    bool first = true;
-    do {
-      while (lex< block_comment >());
-      if (lex< quoted_string >()) {
-        if (!ctx.call_importers(unquote(std::string(lexed)), path, pstate, imp))
-        {
-          // push single file import
-          // import_single_file(imp, lexed);
-          to_import.push_back(std::pair<std::string,Function_Call*>(std::string(lexed), 0));
-        }
-      }
-      else if (lex< uri_prefix >()) {
-        Arguments* args = SASS_MEMORY_NEW(ctx.mem, Arguments, pstate);
-        Function_Call* result = SASS_MEMORY_NEW(ctx.mem, Function_Call, pstate, "url", args);
-        if (lex< quoted_string >()) {
-          Expression* the_url = parse_string();
-          *args << SASS_MEMORY_NEW(ctx.mem, Argument, the_url->pstate(), the_url);
-        }
-        else if (lex < uri_value >(false)) { // don't skip comments
-          String* the_url = parse_interpolated_chunk(lexed);
-          *args << SASS_MEMORY_NEW(ctx.mem, Argument, the_url->pstate(), the_url);
-        }
-        else if (peek < skip_over_scopes < exactly < '(' >, exactly < ')' > > >(position)) {
-          Expression* the_url = parse_list(); // parse_interpolated_chunk(lexed);
-          *args << SASS_MEMORY_NEW(ctx.mem, 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*>("", 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<';'>,end_of_file>>()) {
-      List* media_queries = parse_media_queries();
-      imp->media_queries(media_queries);
-    }
-
-    for(auto location : to_import) {
-      if (location.second) {
-        imp->urls().push_back(location.second);
-      } else {
-        ctx.import_url(imp, location.first, path);
-      }
-    }
-
-    return imp;
-  }
-
-  Definition* 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* params = parse_parameters();
-    if (which_type == Definition::MIXIN) stack.push_back(mixin_def);
-    else stack.push_back(function_def);
-    Block* body = parse_block();
-    stack.pop_back();
-    Definition* def = SASS_MEMORY_NEW(ctx.mem, Definition, source_position_of_def, name, params, body, which_type);
-    return def;
-  }
-
-  Parameters* Parser::parse_parameters()
-  {
-    std::string name(lexed);
-    Position position = after_token;
-    Parameters* params = SASS_MEMORY_NEW(ctx.mem, Parameters, pstate);
-    if (lex_css< exactly<'('> >()) {
-      // if there's anything there at all
-      if (!peek_css< exactly<')'> >()) {
-        do (*params) << 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* Parser::parse_parameter()
-  {
-    while (lex< alternatives < spaces, block_comment > >());
-    lex < variable >();
-    std::string name(Util::normalize_underscores(lexed));
-    ParserState pos = pstate;
-    Expression* val = 0;
-    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();
-      val->is_delayed(false);
-    }
-    else if (lex< exactly< ellipsis > >()) {
-      is_rest = true;
-    }
-    Parameter* p = SASS_MEMORY_NEW(ctx.mem, Parameter, pos, name, val, is_rest);
-    return p;
-  }
-
-  Arguments* Parser::parse_arguments()
-  {
-    std::string name(lexed);
-    Position position = after_token;
-    Arguments* args = SASS_MEMORY_NEW(ctx.mem, Arguments, pstate);
-    if (lex_css< exactly<'('> >()) {
-      // if there's anything there at all
-      if (!peek_css< exactly<')'> >()) {
-        do (*args) << 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* 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* 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* val = parse_space_list();
-      val->is_delayed(false);
-      arg = SASS_MEMORY_NEW(ctx.mem, Argument, p, val, name);
-    }
-    else {
-      bool is_arglist = false;
-      bool is_keyword = false;
-      Expression* val = parse_space_list();
-      val->is_delayed(false);
-      if (lex_css< exactly< ellipsis > >()) {
-        if (val->concrete_type() == Expression::MAP) is_keyword = true;
-        else is_arglist = true;
-      }
-      arg = SASS_MEMORY_NEW(ctx.mem, Argument, pstate, val, "", is_arglist, is_keyword);
-    }
-    return arg;
-  }
-
-  Assignment* 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);
-    Expression* val;
-    Lookahead lookahead = lookahead_for_value(position);
-    if (lookahead.has_interpolants && lookahead.found) {
-      val = parse_value_schema(lookahead.found);
-    } else {
-      val = parse_list();
-    }
-    val->is_delayed(false);
-    bool is_default = false;
-    bool is_global = false;
-    while (peek< alternatives < default_flag, global_flag > >()) {
-      if (lex< default_flag >()) is_default = true;
-      else if (lex< global_flag >()) is_global = true;
-    }
-    Assignment* var = SASS_MEMORY_NEW(ctx.mem, Assignment, var_source_position, name, val, is_default, is_global);
-    return var;
-  }
-
-  // a ruleset connects a selector and a block
-  Ruleset* 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* ruleset = SASS_MEMORY_NEW(ctx.mem, 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
-    ruleset->block(parse_block());
-    // update for end position
-    ruleset->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* 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* schema = SASS_MEMORY_NEW(ctx.mem, String_Schema, pstate);
-    // the selector schema is pretty much just a wrapper for the string schema
-    Selector_Schema* selector_schema = SASS_MEMORY_NEW(ctx.mem, 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> >(i, end_of_selector)) {
-        // accumulate the preceding segment if the position has advanced
-        if (i < p) (*schema) << SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, std::string(i, p));
-        // 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
-        Expression* interpolant = Parser::from_c_str(p+2, j, ctx, pstate).parse_list();
-        // set status on the list expression
-        interpolant->is_interpolant(true);
-        // add to the string schema
-        (*schema) << interpolant;
-        // 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) (*schema) << SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, std::string(i, end_of_selector));
-        // exit loop
-        i = end_of_selector;
-      }
-    }
-    // EO until eos
-
-    // update position
-    position = i;
-
-    // update for end position
-    selector_schema->update_pstate(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* 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* call = SASS_MEMORY_NEW(ctx.mem, 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;
-  }
-  // EO parse_include_directive
-
-  // parse a list of complex selectors
-  // this is the main entry point for most
-  Selector_List* Parser::parse_selector_list(bool in_root)
-  {
-    bool reloop = true;
-    bool had_linefeed = false;
-    Complex_Selector* sel = 0;
-    To_String to_string(&ctx);
-    Selector_List* group = SASS_MEMORY_NEW(ctx.mem, 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;
-
-      sel->has_line_feed(had_linefeed);
-
-      had_linefeed = false;
-
-      while (peek_css< exactly<','> >())
-      {
-        lex< css_comments >(false);
-        // consume everything up and including the comma speparator
-        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) << 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;
-  }
-  // 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* Parser::parse_complex_selector(bool in_root)
-  {
-
-    String* reference = 0;
-    lex < block_comment >();
-    // parse the left hand side
-    Compound_Selector* lhs = 0;
-    // 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(ctx.mem, 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 >();
-    // source position of a complex selector points to the combinator
-    // ToDo: make sure we update pstate for ancestor of (lex < zero >());
-    Complex_Selector* sel = SASS_MEMORY_NEW(ctx.mem, Complex_Selector, pstate, combinator, lhs);
-    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));
-      if (sel->tail()) {
-        // ToDo: move this logic below into tail setter
-        if (sel->tail()->has_reference()) sel->has_reference(true);
-        if (sel->tail()->has_placeholder()) sel->has_placeholder(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_reference() && !in_at_root && !in_root) {
-      // create the objects to wrap parent selector reference
-      Parent_Selector* parent = SASS_MEMORY_NEW(ctx.mem, Parent_Selector, pstate);
-      parent->media_block(last_media_block);
-      Compound_Selector* head = SASS_MEMORY_NEW(ctx.mem, Compound_Selector, pstate);
-      head->media_block(last_media_block);
-      // add simple selector
-      (*head) << 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(ctx.mem, 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);
-    }
-
-    // complex selector
-    return sel;
-  }
-  // EO parse_complex_selector
-
-  // parse one compound selector, which is basically
-  // a list of simple selectors (directly adjancent)
-  // lex them exactly (without skipping white-space)
-  Compound_Selector* Parser::parse_compound_selector()
-  {
-    // init an empty compound selector wrapper
-    Compound_Selector* seq = SASS_MEMORY_NEW(ctx.mem, 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 (peek < re_pseudo_selector >())
-      {
-        (*seq) << parse_simple_selector();
-      }
-      // parse parent selector
-      else if (lex< exactly<'&'> >(false))
-      {
-        // this produces a linefeed!?
-        seq->has_parent_reference(true);
-        (*seq) << SASS_MEMORY_NEW(ctx.mem, Parent_Selector, pstate);
-      }
-      // parse type selector
-      else if (lex< re_type_selector >(false))
-      {
-        (*seq) << SASS_MEMORY_NEW(ctx.mem, Type_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* sel = parse_simple_selector();
-        if (!sel) return 0;
-        (*seq) << sel;
-      }
-    }
-
-    if (seq && !peek_css<exactly<'{'>>()) {
-      seq->has_line_break(peek_newline());
-    }
-
-    // EO while true
-    return seq;
-
-  }
-  // EO parse_compound_selector
-
-  Simple_Selector* Parser::parse_simple_selector()
-  {
-    lex < css_comments >(false);
-    if (lex< alternatives < id_name, class_name > >()) {
-      return SASS_MEMORY_NEW(ctx.mem, Selector_Qualifier, pstate, lexed);
-    }
-    else if (lex< quoted_string >()) {
-      return SASS_MEMORY_NEW(ctx.mem, Type_Selector, pstate, unquote(lexed));
-    }
-    else if (lex< alternatives < variable, number, static_reference_combinator > >()) {
-      return SASS_MEMORY_NEW(ctx.mem, Type_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 >()) {
-      Selector_Placeholder* sel = SASS_MEMORY_NEW(ctx.mem, Selector_Placeholder, pstate, lexed);
-      sel->media_block(last_media_block);
-      return sel;
-    }
-    // failed
-    return 0;
-  }
-
-  Wrapped_Selector* Parser::parse_negated_selector()
-  {
-    lex< pseudo_not >();
-    std::string name(lexed);
-    ParserState nsource_position = pstate;
-    Selector* negated = parse_selector_list(true);
-    if (!lex< exactly<')'> >()) {
-      error("negated selector is missing ')'", pstate);
-    }
-    name.erase(name.size() - 1);
-    return SASS_MEMORY_NEW(ctx.mem, Wrapped_Selector, nsource_position, name, negated);
-  }
-
-  // a pseudo selector often starts with one or two colons
-  // it can contain more selectors inside parantheses
-  Simple_Selector* 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* expr = SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, lexed);
-        if (expr && lex_css< exactly<')'> >()) {
-          expr->can_compress_whitespace(true);
-          return SASS_MEMORY_NEW(ctx.mem, Pseudo_Selector, p, name, expr);
-        }
-      }
-      else if (Selector* wrapped = parse_selector_list(true)) {
-        if (wrapped && lex_css< exactly<')'> >()) {
-          return SASS_MEMORY_NEW(ctx.mem, Wrapped_Selector, p, name, wrapped);
-        }
-      }
-
-    }
-    // EO if pseudo selector
-
-    else if (lex < sequence< optional < pseudo_prefix >, identifier > >()) {
-      return SASS_MEMORY_NEW(ctx.mem, 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* 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(ctx.mem, 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* value = 0;
-    if (lex_css< identifier >()) {
-      value = SASS_MEMORY_NEW(ctx.mem, 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(ctx.mem, Attribute_Selector, p, name, matcher, value);
-  }
-
-  /* parse block comment and add to block */
-  void Parser::parse_block_comments()
-  {
-    Block* block = block_stack.back();
-    while (lex< block_comment >()) {
-      bool is_important = lexed.begin[2] == '!';
-      String*  contents = parse_interpolated_chunk(lexed);
-      (*block) << SASS_MEMORY_NEW(ctx.mem, Comment, pstate, contents, is_important);
-    }
-  }
-
-  Declaration* Parser::parse_declaration() {
-    String* prop = 0;
-    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(ctx.mem, String_Constant, pstate, lexed);
-      prop->is_delayed(true);
-    }
-    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(ctx.mem, Declaration, prop->pstate(), prop, parse_static_value()/*, lex<kwd_important>()*/);
-    }
-    else {
-      Expression* value;
-      Lookahead lookahead = lookahead_for_value(position);
-      if (lookahead.found) {
-        if (lookahead.has_interpolants) {
-          value = parse_value_schema(lookahead.found);
-        } else {
-          value = parse_list();
-        }
-      }
-      else {
-        value = parse_list();
-        if (List* list = dynamic_cast<List*>(value)) {
-          if (list->length() == 0 && !peek< exactly <'{'> >()) {
-            css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
-          }
-        }
-      }
-      lex < css_comments >(false);
-      auto decl = SASS_MEMORY_NEW(ctx.mem, Declaration, prop->pstate(), prop, value/*, lex<kwd_important>()*/);
-      decl->is_indented(is_indented);
-      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* Parser::parse_map()
-  {
-    Expression* key = parse_list();
-    Map* map = SASS_MEMORY_NEW(ctx.mem, Map, pstate, 1);
-    if (String_Quoted* str = dynamic_cast<String_Quoted*>(key)) {
-      if (!str->quote_mark() && !str->is_delayed()) {
-        if (const Color* col = name_to_color(str->value())) {
-          Color* c = SASS_MEMORY_NEW(ctx.mem, Color, *col);
-          c->pstate(str->pstate());
-          c->disp(str->value());
-          key = c;
-        }
-      }
-    }
-
-    // it's not a map so return the lexed value as a list value
-    if (!peek< exactly<':'> >())
-    { return key; }
-
-    lex< exactly<':'> >();
-
-    Expression* value = parse_space_list();
-
-    (*map) << std::make_pair(key, value);
-
-    while (lex_css< exactly<','> >())
-    {
-      // allow trailing commas - #495
-      if (peek_css< exactly<')'> >(position))
-      { break; }
-
-      Expression* key = parse_list();
-      if (String_Quoted* str = dynamic_cast<String_Quoted*>(key)) {
-        if (!str->quote_mark() && !str->is_delayed()) {
-          if (const Color* col = name_to_color(str->value())) {
-            Color* c = SASS_MEMORY_NEW(ctx.mem, Color, *col);
-            c->pstate(str->pstate());
-            c->disp(str->value());
-            key = c;
-          }
-        }
-      }
-
-      if (!(lex< exactly<':'> >()))
-      { error("invalid syntax", pstate); }
-
-      Expression* value = parse_space_list();
-
-      (*map) << std::make_pair(key, 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* Parser::parse_list()
-  {
-    // parse list is relly just an alias
-    return parse_comma_list();
-  }
-
-  // will return singletons unwrapped
-  Expression* Parser::parse_comma_list()
-  {
-    // check if we have an empty list
-    // return the empty list as such
-    if (peek_css< alternatives <
-          // exactly<'!'>,
-          exactly<';'>,
-          exactly<'}'>,
-          exactly<'{'>,
-          exactly<')'>,
-          exactly<':'>,
-          exactly<ellipsis>,
-          default_flag,
-          global_flag
-        > >(position))
-    { return SASS_MEMORY_NEW(ctx.mem, List, pstate, 0); }
-
-    // now try to parse a space list
-    Expression* list = parse_space_list();
-    // if it's a singleton, return it (don't wrap it)
-    if (!peek_css< exactly<','> >(position)) return list;
-
-    // if we got so far, we actually do have a comma list
-    List* comma_list = SASS_MEMORY_NEW(ctx.mem, List, pstate, 2, SASS_COMMA);
-    // wrap the first expression
-    (*comma_list) << list;
-
-    while (lex_css< exactly<','> >())
-    {
-      // check for abort condition
-      if (peek_css< alternatives <
-            exactly<';'>,
-            exactly<'}'>,
-            exactly<'{'>,
-            exactly<')'>,
-            exactly<':'>,
-            exactly<ellipsis>,
-            default_flag,
-            global_flag
-          > >(position)
-      ) { break; }
-      // otherwise add another expression
-      (*comma_list) << parse_space_list();
-    }
-    // return the list
-    return comma_list;
-  }
-  // EO parse_comma_list
-
-  // will return singletons unwrapped
-  Expression* Parser::parse_space_list()
-  {
-    Expression* 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<':'>,
-          exactly<ellipsis>,
-          default_flag,
-          global_flag
-        > >(position)
-    ) { return disj1; }
-
-    List* space_list = SASS_MEMORY_NEW(ctx.mem, List, pstate, 2, SASS_SPACE);
-    (*space_list) << disj1;
-
-    while (!(peek_css< alternatives <
-               // exactly<'!'>,
-               exactly<';'>,
-               exactly<'}'>,
-               exactly<'{'>,
-               exactly<')'>,
-               exactly<','>,
-               exactly<':'>,
-               exactly<ellipsis>,
-               default_flag,
-               global_flag
-           > >(position)) && peek_css< optional_css_whitespace >() != end
-    ) {
-      // the space is parsed implicitly?
-      (*space_list) << parse_disjunction();
-    }
-    // return the list
-    return space_list;
-  }
-  // EO parse_space_list
-
-  // parse logical OR operation
-  Expression* Parser::parse_disjunction()
-  {
-    // parse the left hand side conjunction
-    Expression* conj = parse_conjunction();
-    // parse multiple right hand sides
-    std::vector<Expression*> 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
-    return fold_operands(conj, operands, Sass_OP::OR);
-  }
-  // EO parse_disjunction
-
-  // parse logical AND operation
-  Expression* Parser::parse_conjunction()
-  {
-    // parse the left hand side relation
-    Expression* rel = parse_relation();
-    // parse multiple right hand sides
-    std::vector<Expression*> 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
-    return fold_operands(rel, operands, Sass_OP::AND);
-  }
-  // EO parse_conjunction
-
-  // parse comparison operations
-  Expression* Parser::parse_relation()
-  {
-    // parse the left hand side expression
-    Expression* lhs = parse_expression();
-    // if it's a singleton, return it (don't wrap it)
-    if (!(peek< alternatives <
-            kwd_eq,
-            kwd_neq,
-            kwd_gte,
-            kwd_gt,
-            kwd_lte,
-            kwd_lt
-          > >(position)))
-    { return lhs; }
-    // 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 possibilites on top of fn
-    :                  Sass_OP::EQ;
-    // parse the right hand side expression
-    Expression* rhs = parse_expression();
-    // return binary expression with a left and a right hand side
-    return SASS_MEMORY_NEW(ctx.mem, Binary_Expression, lhs->pstate(), op, lhs, rhs);
-  }
-  // 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* Parser::parse_expression()
-  {
-    Expression* lhs = parse_operators();
-    // if it's a singleton, return it (don't wrap it)
-    if (!(peek< 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< identifier >(position))
-    { return lhs; }
-
-    std::vector<Expression*> operands;
-    std::vector<Sass_OP> operators;
-    while (lex< exactly<'+'> >() || lex< sequence< negate< digit >, exactly<'-'> > >()) {
-      operators.push_back(lexed.to_string() == "+" ? Sass_OP::ADD : Sass_OP::SUB);
-      operands.push_back(parse_operators());
-    }
-
-    if (operands.size() == 0) return lhs;
-    return fold_operands(lhs, operands, operators);
-  }
-
-  // parse addition and subtraction operations
-  Expression* Parser::parse_operators()
-  {
-    Expression* factor = parse_factor();
-    // Special case: Ruby sass never tries to modulo if the lhs contains an interpolant
-    if (peek_css< exactly<'%'> >() && factor->concrete_type() == Expression::STRING) {
-      String_Schema* ss = dynamic_cast<String_Schema*>(factor);
-      if (ss && ss->has_interpolants()) return factor;
-    }
-    // if it's a singleton, return it (don't wrap it)
-    if (!peek_css< class_char< static_ops > >()) return factor;
-    // parse more factors and operators
-    std::vector<Expression*> operands; // factors
-    std::vector<enum Sass_OP> operators; // ops
-    // lex operations to apply to lhs
-    while (lex_css< class_char< static_ops > >()) {
-      switch(*lexed.begin) {
-        case '*': operators.push_back(Sass_OP::MUL); break;
-        case '/': operators.push_back(Sass_OP::DIV); break;
-        case '%': operators.push_back(Sass_OP::MOD); break;
-        default: throw std::runtime_error("unknown static op parsed"); break;
-      }
-      operands.push_back(parse_factor());
-    }
-    // operands and operators to binary expression
-    return fold_operands(factor, operands, operators);
-  }
-  // EO parse_operators
-
-
-  // called from parse_operators
-  // called from parse_value_schema
-  Expression* Parser::parse_factor()
-  {
-    lex < css_comments >(false);
-    if (lex_css< exactly<'('> >()) {
-      // parse_map may return a list
-      Expression* value = parse_map();
-      // lex the expected closing parenthesis
-      if (!lex_css< exactly<')'> >()) error("unclosed parenthesis", pstate);
-      // expression can be evaluated
-      value->is_delayed(false);
-      // make sure wrapped lists and division expressions are non-delayed within parentheses
-      if (value->concrete_type() == Expression::LIST) {
-        List* l = static_cast<List*>(value);
-        if (!l->empty()) (*l)[0]->is_delayed(false);
-      } else if (typeid(*value) == typeid(Binary_Expression)) {
-        Binary_Expression* b = static_cast<Binary_Expression*>(value);
-        Binary_Expression* lhs = static_cast<Binary_Expression*>(b->left());
-        if (lhs && lhs->type() == Sass_OP::DIV) lhs->is_delayed(false);
-      }
-      return value;
-    }
-    else if (peek< ie_property >()) {
-      return parse_ie_property();
-    }
-    else if (peek< ie_keyword_arg >()) {
-      return parse_ie_keyword_arg();
-    }
-    else if (peek< exactly< calc_kwd > >() ||
-             peek< exactly< moz_calc_kwd > >() ||
-             peek< exactly< ms_calc_kwd > >() ||
-             peek< exactly< webkit_calc_kwd > >()) {
-      return parse_calc_function();
-    }
-    else if (lex < functional_schema >()) {
-      return parse_function_call_schema();
-    }
-    else if (lex< identifier_schema >()) {
-      String* string = parse_identifier_schema();
-      if (String_Schema* schema = dynamic_cast<String_Schema*>(string)) {
-        if (lex < exactly < '(' > >()) {
-          *schema << 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<'+'> >()) {
-      return SASS_MEMORY_NEW(ctx.mem, Unary_Expression, pstate, Unary_Expression::PLUS, parse_factor());
-    }
-    else if (lex< exactly<'-'> >()) {
-      return SASS_MEMORY_NEW(ctx.mem, Unary_Expression, pstate, Unary_Expression::MINUS, parse_factor());
-    }
-    else if (lex< sequence< kwd_not > >()) {
-      return SASS_MEMORY_NEW(ctx.mem, Unary_Expression, pstate, Unary_Expression::NOT, parse_factor());
-    }
-    else if (peek < sequence < one_plus < alternatives < css_whitespace, exactly<'-'>, exactly<'+'> > >, number > >()) {
-      if (parse_number_prefix()) return parse_value(); // prefix is positive
-      return SASS_MEMORY_NEW(ctx.mem, Unary_Expression, pstate, Unary_Expression::MINUS, parse_value());
-    }
-    else {
-      return parse_value();
-    }
-  }
-
-  // parse one value for a list
-  Expression* Parser::parse_value()
-  {
-    lex< css_comments >(false);
-    if (lex< ampersand >())
-    {
-      return SASS_MEMORY_NEW(ctx.mem, Parent_Selector, pstate); }
-
-    if (lex< kwd_important >())
-    { return SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, "!important"); }
-
-    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(ctx.mem, Boolean, pstate, true); }
-
-    if (lex< kwd_false >())
-    { return SASS_MEMORY_NEW(ctx.mem, Boolean, pstate, false); }
-
-    if (lex< kwd_null >())
-    { return SASS_MEMORY_NEW(ctx.mem, Null, pstate); }
-
-    if (lex< identifier >()) {
-      return SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, lexed);
-    }
-
-    if (lex< percentage >())
-    { return SASS_MEMORY_NEW(ctx.mem, Textual, pstate, Textual::PERCENTAGE, lexed); }
-
-    // match hex number first because 0x000 looks like a number followed by an indentifier
-    if (lex< sequence < alternatives< hex, hex0 >, negate < exactly<'-'> > > >())
-    { return SASS_MEMORY_NEW(ctx.mem, Textual, pstate, Textual::HEX, lexed); }
-
-    if (lex< sequence < exactly <'#'>, identifier > >())
-    { return SASS_MEMORY_NEW(ctx.mem, String_Quoted, pstate, lexed); }
-
-    // also handle the 10em- foo special case
-    if (lex< sequence< dimension, optional< sequence< exactly<'-'>, negate< digit > > > > >())
-    { return SASS_MEMORY_NEW(ctx.mem, Textual, pstate, Textual::DIMENSION, lexed); }
-
-    if (lex< sequence< static_component, one_plus< strict_identifier > > >())
-    { return SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, lexed); }
-
-    if (lex< number >())
-    { return SASS_MEMORY_NEW(ctx.mem, Textual, pstate, Textual::NUMBER, lexed); }
-
-    if (lex< variable >())
-    { return SASS_MEMORY_NEW(ctx.mem, Variable, pstate, Util::normalize_underscores(lexed)); }
-
-    // Special case handling for `%` proceeding an interpolant.
-    if (lex< sequence< exactly<'%'>, optional< percentage > > >())
-    { return SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, lexed); }
-
-    error("error reading values after " + lexed.to_string(), pstate);
-
-    // unreachable statement
-    return 0;
-  }
-
-  // this parses interpolation inside other strings
-  // means the result should later be quoted again
-  String* Parser::parse_interpolated_chunk(Token chunk, bool constant)
-  {
-    const char* i = chunk.begin;
-    // see if there any interpolants
-    const char* p = find_first_in_interval< exactly<hash_lbrace> >(i, chunk.end);
-    if (!p) {
-      String_Quoted* str_quoted = SASS_MEMORY_NEW(ctx.mem, String_Quoted, pstate, std::string(i, chunk.end));
-      if (!constant && str_quoted->quote_mark()) str_quoted->quote_mark('*');
-      str_quoted->is_delayed(true);
-      return str_quoted;
-    }
-
-    String_Schema* schema = SASS_MEMORY_NEW(ctx.mem, String_Schema, pstate);
-    while (i < chunk.end) {
-      p = find_first_in_interval< exactly<hash_lbrace> >(i, chunk.end);
-      if (p) {
-        if (i < p) {
-          // accumulate the preceding segment if it's nonempty
-          (*schema) << SASS_MEMORY_NEW(ctx.mem, 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* interp_node = Parser::from_token(Token(p+2, j), ctx, pstate).parse_list();
-          interp_node->is_interpolant(true);
-          (*schema) << 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) << SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, std::string(i, chunk.end));
-        break;
-      }
-      ++ i;
-    }
-
-    return schema;
-  }
-
-  String_Constant* Parser::parse_static_expression()
-  {
-    if (peek< sequence< number, optional_spaces, exactly<'/'>, optional_spaces, number > >()) {
-      return parse_static_value();
-    }
-    return 0;
-  }
-
-  String_Constant* Parser::parse_static_value()
-  {
-    lex< static_value >();
-    Token str(lexed);
-    --str.end;
-    --position;
-
-    String_Constant* str_node = SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, str.time_wspace());
-    str_node->is_delayed(true);
-    return str_node;
-  }
-
-  String* Parser::parse_string()
-  {
-    return parse_interpolated_chunk(Token(lexed));
-  }
-
-  String* 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> >(str.begin, str.end);
-    if (!p) {
-      return SASS_MEMORY_NEW(ctx.mem, String_Quoted, pstate, std::string(str.begin, str.end));
-    }
-
-    String_Schema* schema = SASS_MEMORY_NEW(ctx.mem, String_Schema, pstate);
-    while (i < str.end) {
-      p = find_first_in_interval< exactly<hash_lbrace> >(i, str.end);
-      if (p) {
-        if (i < p) {
-          (*schema) << SASS_MEMORY_NEW(ctx.mem, 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* interp_node = Parser::from_token(Token(p+2, j), ctx, pstate).parse_list();
-          interp_node->is_interpolant(true);
-          (*schema) << 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) << SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, std::string(i, str.end));
-        }
-        break;
-      }
-    }
-    return schema;
-  }
-
-  String* Parser::parse_ie_keyword_arg()
-  {
-    String_Schema* kwd_arg = SASS_MEMORY_NEW(ctx.mem, String_Schema, pstate, 3);
-    if (lex< variable >()) {
-      *kwd_arg << SASS_MEMORY_NEW(ctx.mem, Variable, pstate, Util::normalize_underscores(lexed));
-    } else {
-      lex< alternatives< identifier_schema, identifier > >();
-      *kwd_arg << SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, lexed);
-    }
-    lex< exactly<'='> >();
-    *kwd_arg << SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, lexed);
-    if (peek< variable >()) *kwd_arg << parse_list();
-    else if (lex< number >()) *kwd_arg << SASS_MEMORY_NEW(ctx.mem, Textual, pstate, Textual::NUMBER, Util::normalize_decimals(lexed));
-    else if (peek < ie_keyword_arg_value >()) { *kwd_arg << parse_list(); }
-    return kwd_arg;
-  }
-
-  String_Schema* Parser::parse_value_schema(const char* stop)
-  {
-    // initialize the string schema object to add tokens
-    String_Schema* schema = SASS_MEMORY_NEW(ctx.mem, String_Schema, pstate);
-
-    if (peek<exactly<'}'>>()) {
-      css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
-    }
-
-    const char* e = 0;
-    size_t num_items = 0;
-    while (position < stop) {
-      // parse space between tokens
-      if (lex< spaces >() && num_items) {
-        (*schema) << SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, " ");
-      }
-      if ((e = peek< re_functional >()) && e < stop) {
-        (*schema) << 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 ");
-        }
-        if (lex< re_static_expression >()) {
-          (*schema) << SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, lexed);
-        } else {
-          (*schema) << parse_list();
-        }
-        // ToDo: no error check here?
-        lex < exactly < rbrace > >();
-      }
-      // lex some string constants
-      else if (lex< alternatives < exactly<'%'>, exactly < '-' >, identifier > >()) {
-        (*schema) << SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, lexed);
-        if (*position == '"' || *position == '\'') {
-          (*schema) << SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, " ");
-        }
-      }
-      // lex a quoted string
-      else if (lex< quoted_string >()) {
-        (*schema) << SASS_MEMORY_NEW(ctx.mem, String_Quoted, pstate, lexed, '"');
-        if (*position == '"' || *position == '\'' || alpha(position)) {
-          (*schema) << SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, " ");
-        }
-      }
-      // lex (normalized) variable
-      else if (lex< variable >()) {
-        std::string name(Util::normalize_underscores(lexed));
-        (*schema) << SASS_MEMORY_NEW(ctx.mem, Variable, pstate, name);
-      }
-      // lex percentage value
-      else if (lex< percentage >()) {
-        (*schema) << SASS_MEMORY_NEW(ctx.mem, Textual, pstate, Textual::PERCENTAGE, lexed);
-      }
-      // lex dimension value
-      else if (lex< dimension >()) {
-        (*schema) << SASS_MEMORY_NEW(ctx.mem, Textual, pstate, Textual::DIMENSION, lexed);
-      }
-      // lex number value
-      else if (lex< number >()) {
-        (*schema) <<  SASS_MEMORY_NEW(ctx.mem, Textual, pstate, Textual::NUMBER, lexed);
-      }
-      // lex hex color value
-      else if (lex< sequence < hex, negate < exactly < '-' > > > >()) {
-        (*schema) << SASS_MEMORY_NEW(ctx.mem, Textual, pstate, Textual::HEX, lexed);
-      }
-      else if (lex< sequence < exactly <'#'>, identifier > >()) {
-        (*schema) << SASS_MEMORY_NEW(ctx.mem, String_Quoted, pstate, lexed);
-      }
-      // lex a value in parentheses
-      else if (peek< parenthese_scope >()) {
-        (*schema) << parse_factor();
-      }
-      else {
-        return schema;
-      }
-      ++num_items;
-    }
-    return schema;
-  }
-
-  // this parses interpolation outside other strings
-  // means the result must not be quoted again later
-  String* 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> >(id.begin, id.end);
-    if (!p) {
-      return SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, std::string(id.begin, id.end));
-    }
-
-    String_Schema* schema = SASS_MEMORY_NEW(ctx.mem, String_Schema, pstate);
-    while (i < id.end) {
-      p = find_first_in_interval< exactly<hash_lbrace> >(i, id.end);
-      if (p) {
-        if (i < p) {
-          // accumulate the preceding segment if it's nonempty
-          const char* o = position; position = i;
-          *schema << 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* interp_node = Parser::from_token(Token(p+2, j), ctx, pstate).parse_list();
-          interp_node->is_interpolant(true);
-          (*schema) << 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 << parse_value_schema(id.end);
-          position = o;
-        }
-        break;
-      }
-    }
-    return schema;
-  }
-
-  // calc functions should preserve arguments
-  Function_Call* 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* arg = SASS_MEMORY_NEW(ctx.mem, Argument, arg_pos, parse_interpolated_chunk(Token(arg_beg, arg_end)));
-    Arguments* args = SASS_MEMORY_NEW(ctx.mem, Arguments, arg_pos);
-    *args << arg;
-    return SASS_MEMORY_NEW(ctx.mem, Function_Call, call_pos, name, args);
-  }
-
-  String* Parser::parse_url_function_string()
-  {
-    const char* p = position;
-
-    lex< uri_prefix >();
-    std::string prefix = lexed;
-
-    lex< real_uri_value >(false);
-    std::string uri = lexed;
-
-    if (peek< exactly< hash_lbrace > >()) {
-      const char* pp = position;
-      // TODO: error checking for unclosed interpolants
-      while (peek< exactly< hash_lbrace > >(pp)) {
-        pp = sequence< interpolant, real_uri_value >(pp);
-      }
-      position = peek< real_uri_suffix >(pp);
-      return parse_interpolated_chunk(Token(p, position));
-    } else {
-      lex< real_uri_suffix >();
-      std::string res = prefix + Util::rtrim(uri) + lexed.to_string();
-      return SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, res);
-    }
-
-  }
-
-  Function_Call* Parser::parse_function_call()
-  {
-    lex< identifier >();
-    std::string name(lexed);
-
-    ParserState call_pos = pstate;
-    Arguments* args = parse_arguments();
-    return SASS_MEMORY_NEW(ctx.mem, Function_Call, call_pos, name, args);
-  }
-
-  Function_Call_Schema* Parser::parse_function_call_schema()
-  {
-    String* name = parse_identifier_schema();
-    ParserState source_position_of_call = pstate;
-
-    Function_Call_Schema* the_call = SASS_MEMORY_NEW(ctx.mem, Function_Call_Schema, source_position_of_call, name, parse_arguments());
-    return the_call;
-  }
-
-  Content* Parser::parse_content_directive()
-  {
-    if (stack.back() != mixin_def) {
-      error("@content may only be used within a mixin", pstate);
-    }
-    return SASS_MEMORY_NEW(ctx.mem, Content, pstate);
-  }
-
-  If* Parser::parse_if_directive(bool else_if)
-  {
-    ParserState if_source_position = pstate;
-    Expression* predicate = parse_list();
-    predicate->is_delayed(false);
-    Block* block = parse_block();
-    Block* alternative = 0;
-
-    // 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(ctx.mem, Block, pstate);
-      (*alternative) << parse_if_directive(true);
-    }
-    else if (lex_css< kwd_else_directive >()) {
-      alternative = parse_block();
-    }
-    return SASS_MEMORY_NEW(ctx.mem, If, if_source_position, predicate, block, alternative);
-  }
-
-  For* Parser::parse_for_directive()
-  {
-    ParserState for_source_position = pstate;
-    lex_variable();
-    std::string var(Util::normalize_underscores(lexed));
-    if (!lex< kwd_from >()) error("expected 'from' keyword in @for directive", pstate);
-    Expression* lower_bound = parse_expression();
-    lower_bound->is_delayed(false);
-    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* upper_bound = parse_expression();
-    upper_bound->is_delayed(false);
-    Block* body = parse_block();
-    return SASS_MEMORY_NEW(ctx.mem, 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 identfier 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 identfier as the call name
-    if (!lex< identifier >()) { // ToDo: pstate wrong?
-      css_error("Invalid CSS", " after ", ": expected identifier, was ");
-    }
-    // return object
-    return token;
-  }
-
-  Each* Parser::parse_each_directive()
-  {
-    ParserState each_source_position = pstate;
-    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* list = parse_list();
-    list->is_delayed(false);
-    if (list->concrete_type() == Expression::LIST) {
-      List* l = static_cast<List*>(list);
-      for (size_t i = 0, L = l->length(); i < L; ++i) {
-        (*l)[i]->is_delayed(false);
-      }
-    }
-    Block* body = parse_block();
-    return SASS_MEMORY_NEW(ctx.mem, Each, each_source_position, vars, list, body);
-  }
-
-  // called after parsing `kwd_while_directive`
-  While* Parser::parse_while_directive()
-  {
-    // create the initial while call object
-    While* call = SASS_MEMORY_NEW(ctx.mem, While, pstate, 0, 0);
-    // parse mandatory predicate
-    Expression* predicate = parse_list();
-    predicate->is_delayed(false);
-    call->predicate(predicate);
-    // parse mandatory block
-    call->block(parse_block());
-    // return ast node
-    return call;
-  }
-
-  // EO parse_while_directive
-  Media_Block* Parser::parse_media_block()
-  {
-    Media_Block* media_block = SASS_MEMORY_NEW(ctx.mem, Media_Block, pstate, 0, 0);
-    media_block->media_queries(parse_media_queries());
-
-    Media_Block* prev_media_block = last_media_block;
-    last_media_block = media_block;
-    media_block->block(parse_css_block());
-    last_media_block = prev_media_block;
-
-    return media_block;
-  }
-
-  List* Parser::parse_media_queries()
-  {
-    List* media_queries = SASS_MEMORY_NEW(ctx.mem, List, pstate, 0, SASS_COMMA);
-    if (!peek_css < exactly <'{'> >()) (*media_queries) << parse_media_query();
-    while (lex_css < exactly <','> >()) (*media_queries) << parse_media_query();
-    return media_queries;
-  }
-
-  // Expression* Parser::parse_media_query()
-  Media_Query* Parser::parse_media_query()
-  {
-    Media_Query* media_query = SASS_MEMORY_NEW(ctx.mem, Media_Query, pstate);
-
-    lex < css_comments >(false);
-    if (lex < kwd_not >()) media_query->is_negated(true);
-    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) << parse_media_expression();
-
-    while (lex_css < kwd_and >()) (*media_query) << parse_media_expression();
-    if (lex < identifier_schema >()) {
-      String_Schema* schema = SASS_MEMORY_NEW(ctx.mem, String_Schema, pstate);
-      *schema << media_query->media_type();
-      *schema << SASS_MEMORY_NEW(ctx.mem, String_Constant, pstate, " ");
-      *schema << parse_identifier_schema();
-      media_query->media_type(schema);
-    }
-    while (lex_css < kwd_and >()) (*media_query) << parse_media_expression();
-    return media_query;
-  }
-
-  Media_Query_Expression* Parser::parse_media_expression()
-  {
-    if (lex < identifier_schema >()) {
-      String* ss = parse_identifier_schema();
-      return SASS_MEMORY_NEW(ctx.mem, Media_Query_Expression, pstate, ss, 0, true);
-    }
-    if (!lex_css< exactly<'('> >()) {
-      error("media query expression must begin with '('", pstate);
-    }
-    Expression* feature = 0;
-    if (peek_css< exactly<')'> >()) {
-      error("media feature required in media query expression", pstate);
-    }
-    feature = parse_expression();
-    Expression* expression = 0;
-    if (lex< exactly<':'> >()) {
-      expression = parse_list();
-    }
-    if (!lex< exactly<')'> >()) {
-      error("unclosed parenthesis in media query expression", pstate);
-    }
-    return SASS_MEMORY_NEW(ctx.mem, Media_Query_Expression, feature->pstate(), feature, expression);
-  }
-
-  // lexed after `kwd_supports_directive`
-  // these are very similar to media blocks
-  Supports_Block* Parser::parse_supports_directive()
-  {
-    Supports_Condition* cond = parse_supports_condition();
-    // create the ast node object for the support queries
-    Supports_Block* query = SASS_MEMORY_NEW(ctx.mem, 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* Parser::parse_supports_condition()
-  {
-    lex < css_whitespace >();
-    Supports_Condition* cond = parse_supports_negation();
-    if (!cond) cond = parse_supports_operator();
-    if (!cond) cond = parse_supports_interpolation();
-    return cond;
-  }
-
-  Supports_Condition* Parser::parse_supports_negation()
-  {
-    if (!lex < kwd_not >()) return 0;
-
-    Supports_Condition* cond = parse_supports_condition_in_parens();
-    return SASS_MEMORY_NEW(ctx.mem, Supports_Negation, pstate, cond);
-  }
-
-  Supports_Condition* Parser::parse_supports_operator()
-  {
-    Supports_Condition* 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* right = parse_supports_condition_in_parens();
-
-      // Supports_Condition* cc = SASS_MEMORY_NEW(ctx.mem, Supports_Condition, *static_cast<Supports_Condition*>(cond));
-      cond = SASS_MEMORY_NEW(ctx.mem, Supports_Operator, pstate, cond, right, op);
-    }
-    return cond;
-  }
-
-  Supports_Condition* Parser::parse_supports_interpolation()
-  {
-    if (!lex < interpolant >()) return 0;
-
-    String* interp = parse_interpolated_chunk(lexed);
-    if (!interp) return 0;
-
-    return SASS_MEMORY_NEW(ctx.mem, Supports_Interpolation, pstate, interp);
-  }
-
-  // TODO: This needs some major work. Although feature conditions
-  // look like declarations their semantics differ siginificantly
-  Supports_Condition* Parser::parse_supports_declaration()
-  {
-    Supports_Condition* cond = 0;
-    // parse something declaration like
-    Declaration* declaration = parse_declaration();
-    if (!declaration) error("@supports condition expected declaration", pstate);
-    cond = SASS_MEMORY_NEW(ctx.mem, Supports_Declaration,
-                     declaration->pstate(),
-                     declaration->property(),
-                     declaration->value());
-    // ToDo: maybe we need an additional error condition?
-    return cond;
-  }
-
-  Supports_Condition* Parser::parse_supports_condition_in_parens()
-  {
-    Supports_Condition* interp = parse_supports_interpolation();
-    if (interp != 0) return interp;
-
-    if (!lex < exactly <'('> >()) return 0;
-    lex < css_whitespace >();
-
-    Supports_Condition* 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* Parser::parse_at_root_block()
-  {
-    ParserState at_source_position = pstate;
-    Block* body = 0;
-    At_Root_Expression* expr = 0;
-    Lookahead lookahead_result;
-    LOCAL_FLAG(in_at_root, true);
-    if (lex< exactly<'('> >()) {
-      expr = parse_at_root_expression();
-    }
-    if (peek < exactly<'{'> >()) {
-      body = parse_block(true);
-    }
-    else if ((lookahead_result = lookahead_for_selector(position)).found) {
-      Ruleset* r = parse_ruleset(lookahead_result, false);
-      body = SASS_MEMORY_NEW(ctx.mem, Block, r->pstate(), 1, true);
-      *body << r;
-    }
-    At_Root_Block* at_root = SASS_MEMORY_NEW(ctx.mem, At_Root_Block, at_source_position, body);
-    if (expr) at_root->expression(expr);
-    return at_root;
-  }
-
-  At_Root_Expression* Parser::parse_at_root_expression()
-  {
-    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 ");
-    }
-
-    Declaration* declaration = parse_declaration();
-    List* value = SASS_MEMORY_NEW(ctx.mem, List, declaration->value()->pstate(), 1);
-
-    if (declaration->value()->concrete_type() == Expression::LIST) {
-        value = static_cast<List*>(declaration->value());
-    }
-    else *value << declaration->value();
-
-    At_Root_Expression* cond = SASS_MEMORY_NEW(ctx.mem, At_Root_Expression,
-                                               declaration->pstate(),
-                                               declaration->property(),
-                                               value);
-    if (!lex< exactly<')'> >()) error("unclosed parenthesis in @at-root expression", pstate);
-    return cond;
-  }
-
-  At_Rule* Parser::parse_at_rule()
-  {
-    std::string kwd(lexed);
-
-    if (lexed == "@else") error("Invalid CSS: @else must come after @if", pstate);
-
-    At_Rule* at_rule = SASS_MEMORY_NEW(ctx.mem, At_Rule, 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;
-  }
-
-  Warning* Parser::parse_warning()
-  {
-    return SASS_MEMORY_NEW(ctx.mem, Warning, pstate, parse_list());
-  }
-
-  Error* Parser::parse_error()
-  {
-    return SASS_MEMORY_NEW(ctx.mem, Error, pstate, parse_list());
-  }
-
-  Debug* Parser::parse_debug()
-  {
-    return SASS_MEMORY_NEW(ctx.mem, Debug, pstate, parse_list());
-  }
-
-  Return* 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(ctx.mem, 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 <
-        one_plus <
-          alternatives <
-            // consume whitespace and comments
-            spaces, block_comment, line_comment,
-            // match `/deep/` selector (pass-trough)
-            // there is no functionality for it yet
-            schema_reference_combinator,
-            // match selector ops /[*&%,()\[\]]/
-            class_char < selector_lookahead_ops >,
-            // match selector combinators /[>+~]/
-            class_char < selector_combinator_ops >,
-            // match attribute compare operators
-            alternatives <
-              exact_match, class_match, dash_match,
-              prefix_match, suffix_match, substring_match
-            >,
-            // main selector match
-            sequence <
-              // allow namespace prefix
-              optional < namespace_schema >,
-              // modifiers prefixes
-              alternatives <
-                sequence <
-                  exactly <'#'>,
-                  // not for interpolation
-                  negate < exactly <'{'> >
-                >,
-                // class match
-                exactly <'.'>,
-                // single or double colon
-                optional < pseudo_prefix >
-              >,
-              // accept hypens in token
-              one_plus < sequence <
-                // can start with hyphens
-                zero_plus < exactly<'-'> >,
-                // now the main token
-                alternatives <
-                  kwd_optional,
-                  exactly <'*'>,
-                  quoted_string,
-                  interpolant,
-                  identifier,
-                  percentage,
-                  dimension,
-                  variable,
-                  alnum
-                >
-              > >,
-              // can also end with hyphens
-              zero_plus < exactly<'-'> >
-            >
-          >
-        >
-      >(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;
-      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_at_rule
-  // 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
-            interpolant,
-            identifier,
-            variable,
-            // issue #442
-            sequence <
-              parenthese_scope,
-              interpolant
-            >
-          >,
-          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 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;
-    }
-
-    // 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* Parser::fold_operands(Expression* base, std::vector<Expression*>& operands, enum Sass_OP op)
-  {
-    for (size_t i = 0, S = operands.size(); i < S; ++i) {
-      base = SASS_MEMORY_NEW(ctx.mem, Binary_Expression, pstate, op, base, operands[i]);
-      Binary_Expression* b = static_cast<Binary_Expression*>(base);
-      if (op == Sass_OP::DIV && b->left()->is_delayed() && b->right()->is_delayed()) {
-        base->is_delayed(true);
-      }
-      else {
-        b->left()->is_delayed(false);
-        b->right()->is_delayed(false);
-      }
-    }
-    return base;
-  }
-
-  Expression* Parser::fold_operands(Expression* base, std::vector<Expression*>& operands, std::vector<enum Sass_OP>& ops)
-  {
-    for (size_t i = 0, S = operands.size(); i < S; ++i) {
-      base = SASS_MEMORY_NEW(ctx.mem, Binary_Expression, base->pstate(), ops[i], base, operands[i]);
-      Binary_Expression* b = static_cast<Binary_Expression*>(base);
-      if (ops[i] == Sass_OP::DIV && b->left()->is_delayed() && b->right()->is_delayed()) {
-        base->is_delayed(true);
-      }
-      else {
-        b->left()->is_delayed(false);
-        b->right()->is_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* pos = peek < optional_spaces >();
-
-    const char* last_pos(pos - 1);
-    // backup position to last significant char
-    while ((!*last_pos || Prelexer::is_space(*last_pos)) && last_pos > source) -- last_pos;
-
-    bool ellipsis_left = false;
-    const char* pos_left(last_pos + 1);
-    const char* end_left(last_pos + 1);
-    while (pos_left > source) {
-      if (end_left - pos_left >= max_len) {
-        ellipsis_left = true;
-        break;
-      }
-
-      const char* prev = pos_left - 1;
-      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 (end_right - pos_right > max_len) {
-        ellipsis_right = true;
-        break;
-      }
-      if (*end_right == '\r') break;
-      if (*end_right == '\n') break;
-      ++ end_right;
-    }
-    if (end_right > end) end_right = end;
-
-    std::string left(pos_left, end_left);
-    std::string right(pos_right, end_right);
-    if (ellipsis_left) left = ellipsis + left.substr(left.size() - 15);
-    if (ellipsis_right) right = right.substr(right.size() - 15) + ellipsis;
+#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);
   }
diff --git a/libsass/src/parser.hpp b/libsass/src/parser.hpp
--- a/libsass/src/parser.hpp
+++ b/libsass/src/parser.hpp
@@ -23,12 +23,12 @@
   class Parser : public ParserState {
   public:
 
-    enum Syntactic_Context { nothing, mixin_def, function_def };
+    enum Scope { Root, Mixin, Function, Media, Control, Properties, Rules };
 
     Context& ctx;
-    std::vector<Block*> block_stack;
-    std::vector<Syntactic_Context> stack;
-    Media_Block* last_media_block;
+    std::vector<Block_Obj> block_stack;
+    std::vector<Scope> stack;
+    Media_Block_Ptr last_media_block;
     const char* source;
     const char* position;
     const char* end;
@@ -42,16 +42,16 @@
     bool in_at_root;
 
     Parser(Context& ctx, const ParserState& pstate)
-    : ParserState(pstate), ctx(ctx), block_stack(0), stack(0), last_media_block(0),
+    : 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(nothing); }
+    { in_at_root = false; 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]"));
-    static Parser from_c_str(const char* beg, const char* end, Context& ctx, ParserState pstate = ParserState("[CSTRING]"));
-    static Parser from_token(Token t, Context& ctx, ParserState pstate = ParserState("[TOKEN]"));
+    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);
     // special static parsers to convert strings into certain selectors
-    static Selector_List* parse_selector(const char* src, Context& ctx, ParserState pstate = ParserState("[SELECTOR]"));
+    static Selector_List_Obj parse_selector(const char* src, Context& ctx, ParserState pstate = ParserState("[SELECTOR]"), const char* source = 0);
 
 #ifdef __clang__
 
@@ -66,6 +66,10 @@
 #endif
 
 
+    // skip current token and next whitespace
+    // moves ParserState right before next token
+    void advanceToNextToken();
+
     bool peek_newline(const char* start = 0);
 
     // skip over spaces, tabs and line comments
@@ -99,6 +103,15 @@
     // peek will only 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)
+    {
+      // match the given prelexer
+      return mx(position);
+    }
+
+    // peek will only skip over space, tabs and line comment
+    // return the position where the lexer match will occur
+    template <Prelexer::prelexer mx>
     const char* peek(const char* start = 0)
     {
 
@@ -107,8 +120,11 @@
       const char* it_before_token = sneak < mx >(start);
 
       // match the given prelexer
-      return mx(it_before_token);
+      const char* match = mx(it_before_token);
 
+      // check if match is in valid range
+      return match <= end ? match : 0;
+
     }
 
     // white-space handling is built into the lexer
@@ -121,6 +137,8 @@
     const char* lex(bool lazy = true, bool force = false)
     {
 
+      if (*position == 0) return 0;
+
       // position considered before lexed token
       // we can skip whitespace or comments for
       // lazy developers (but we need control)
@@ -133,6 +151,9 @@
       // now call matcher to get position after token
       const char* it_after_token = mx(it_before_token);
 
+      // check if match is in valid range
+      if (it_after_token > end) return 0;
+
       // maybe we want to update the parser state anyway?
       if (force == false) {
         // assertion that we got a valid match
@@ -210,84 +231,89 @@
                    const std::string& middle = ", was: ");
     void read_bom();
 
-    Block* parse();
-    Import* parse_import();
-    Definition* parse_definition(Definition::Type which_type);
-    Parameters* parse_parameters();
-    Parameter* parse_parameter();
-    Mixin_Call* parse_include_directive();
-    Arguments* parse_arguments();
-    Argument* parse_argument();
-    Assignment* parse_assignment();
-    // Propset* parse_propset();
-    Ruleset* parse_ruleset(Lookahead lookahead, bool is_root = false);
-    Selector_Schema* parse_selector_schema(const char* end_of_selector);
-    Selector_List* parse_selector_list(bool at_root = false);
-    Complex_Selector* parse_complex_selector(bool in_root = true);
-    Compound_Selector* parse_compound_selector();
-    Simple_Selector* parse_simple_selector();
-    Wrapped_Selector* parse_negated_selector();
-    Simple_Selector* parse_pseudo_selector();
-    Attribute_Selector* parse_attribute_selector();
-    Block* parse_block(bool is_root = false);
-    Block* parse_css_block(bool is_root = false);
+    Block_Obj parse();
+    Import_Obj parse_import();
+    Definition_Obj parse_definition(Definition::Type which_type);
+    Parameters_Obj parse_parameters();
+    Parameter_Obj parse_parameter();
+    Mixin_Call_Obj parse_include_directive();
+    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);
+    Compound_Selector_Obj parse_compound_selector();
+    Simple_Selector_Obj parse_simple_selector();
+    Wrapped_Selector_Obj parse_negated_selector();
+    Simple_Selector_Obj parse_pseudo_selector();
+    Attribute_Selector_Obj parse_attribute_selector();
+    Block_Obj parse_block(bool is_root = false);
+    Block_Obj parse_css_block(bool is_root = false);
     bool parse_block_nodes(bool is_root = false);
     bool parse_block_node(bool is_root = false);
 
     bool parse_number_prefix();
-    Declaration* parse_declaration();
-    Expression* parse_map_value();
-    Expression* parse_map();
-    Expression* parse_list();
-    Expression* parse_comma_list();
-    Expression* parse_space_list();
-    Expression* parse_disjunction();
-    Expression* parse_conjunction();
-    Expression* parse_relation();
-    Expression* parse_expression();
-    Expression* parse_operators();
-    Expression* parse_factor();
-    Expression* parse_value2();
-    Expression* parse_value();
-    Function_Call* parse_calc_function();
-    Function_Call* parse_function_call();
-    Function_Call_Schema* parse_function_call_schema();
-    String* parse_url_function_string();
-    String* parse_interpolated_chunk(Token, bool constant = false);
-    String* parse_string();
-    String_Constant* parse_static_expression();
-    // String_Constant* parse_static_property();
-    String_Constant* parse_static_value();
-    String* parse_ie_property();
-    String* parse_ie_keyword_arg();
-    String_Schema* parse_value_schema(const char* stop);
-    String* parse_identifier_schema();
-    // String_Schema* parse_url_schema();
-    If* parse_if_directive(bool else_if = false);
-    For* parse_for_directive();
-    Each* parse_each_directive();
-    While* parse_while_directive();
-    Return* parse_return_directive();
-    Content* parse_content_directive();
+    Declaration_Obj parse_declaration();
+    Expression_Obj parse_map();
+    Expression_Obj parse_list(bool delayed = false);
+    Expression_Obj parse_comma_list(bool delayed = false);
+    Expression_Obj parse_space_list();
+    Expression_Obj parse_disjunction();
+    Expression_Obj parse_conjunction();
+    Expression_Obj parse_relation();
+    Expression_Obj parse_expression();
+    Expression_Obj parse_operators();
+    Expression_Obj parse_factor();
+    Expression_Obj parse_value();
+    Function_Call_Obj parse_calc_function();
+    Function_Call_Obj parse_function_call();
+    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_string();
+    String_Constant_Obj parse_static_value();
+    String_Obj parse_ie_property();
+    String_Obj parse_ie_keyword_arg();
+    String_Schema_Obj parse_value_schema(const char* stop);
+    String_Obj parse_identifier_schema();
+    If_Obj parse_if_directive(bool else_if = false);
+    For_Obj parse_for_directive();
+    Each_Obj parse_each_directive();
+    While_Obj parse_while_directive();
+    Return_Obj parse_return_directive();
+    Content_Obj parse_content_directive();
     void parse_charset_directive();
-    Media_Block* parse_media_block();
-    List* parse_media_queries();
-    Media_Query* parse_media_query();
-    Media_Query_Expression* parse_media_expression();
-    Supports_Block* parse_supports_directive();
-    Supports_Condition* parse_supports_condition();
-    Supports_Condition* parse_supports_negation();
-    Supports_Condition* parse_supports_operator();
-    Supports_Condition* parse_supports_interpolation();
-    Supports_Condition* parse_supports_declaration();
-    Supports_Condition* parse_supports_condition_in_parens();
-    At_Root_Block* parse_at_root_block();
-    At_Root_Expression* parse_at_root_expression();
-    At_Rule* parse_at_rule();
-    Warning* parse_warning();
-    Error* parse_error();
-    Debug* parse_debug();
+    Media_Block_Obj parse_media_block();
+    List_Obj parse_media_queries();
+    Media_Query_Obj parse_media_query();
+    Media_Query_Expression_Obj parse_media_expression();
+    Supports_Block_Obj parse_supports_directive();
+    Supports_Condition_Obj parse_supports_condition();
+    Supports_Condition_Obj parse_supports_negation();
+    Supports_Condition_Obj parse_supports_operator();
+    Supports_Condition_Obj parse_supports_interpolation();
+    Supports_Condition_Obj parse_supports_declaration();
+    Supports_Condition_Obj parse_supports_condition_in_parens();
+    At_Root_Block_Obj parse_at_root_block();
+    At_Root_Query_Obj parse_at_root_query();
+    String_Schema_Obj parse_almost_any_value();
+    Directive_Obj parse_special_directive();
+    Directive_Obj parse_prefixed_directive();
+    Directive_Obj parse_directive();
+    Warning_Obj parse_warning();
+    Error_Obj parse_error();
+    Debug_Obj parse_debug();
 
+    // be more like ruby sass
+    Expression_Obj lex_almost_any_value_token();
+    Expression_Obj lex_almost_any_value_chars();
+    Expression_Obj lex_interp_string();
+    Expression_Obj lex_interp_uri();
+    Expression_Obj lex_interpolation();
+
     // these will throw errors
     Token lex_variable();
     Token lex_identifier();
@@ -298,11 +324,39 @@
     Lookahead lookahead_for_selector(const char* start = 0);
     Lookahead lookahead_for_include(const char* start = 0);
 
-    Expression* fold_operands(Expression* base, std::vector<Expression*>& operands, Sass_OP op);
-    Expression* fold_operands(Expression* base, std::vector<Expression*>& operands, std::vector<Sass_OP>& ops);
+    Expression_Obj fold_operands(Expression_Obj base, std::vector<Expression_Obj>& operands, Operand op);
+    Expression_Obj fold_operands(Expression_Obj base, std::vector<Expression_Obj>& operands, std::vector<Operand>& ops, size_t i = 0);
 
     void throw_syntax_error(std::string message, size_t ln = 0);
     void throw_read_error(std::string message, size_t ln = 0);
+
+
+    template <Prelexer::prelexer open, Prelexer::prelexer close>
+    Expression_Obj lex_interp()
+    {
+      if (lex < open >(false)) {
+        String_Schema_Obj schema = SASS_MEMORY_NEW(String_Schema, pstate);
+        // 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);
+          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);
+            } else {
+              return &schema;
+            }
+          }
+        } else {
+          return SASS_MEMORY_NEW(String_Constant, pstate, lexed);
+        }
+      }
+      return 0;
+    }
   };
 
   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
@@ -7,6 +7,7 @@
 #include <dlfcn.h>
 #endif
 
+#include "sass.hpp"
 #include <iostream>
 #include "output.hpp"
 #include "plugins.hpp"
diff --git a/libsass/src/position.cpp b/libsass/src/position.cpp
--- a/libsass/src/position.cpp
+++ b/libsass/src/position.cpp
@@ -1,3 +1,4 @@
+#include "sass.hpp"
 #include "position.hpp"
 
 namespace Sass {
diff --git a/libsass/src/prelexer.cpp b/libsass/src/prelexer.cpp
--- a/libsass/src/prelexer.cpp
+++ b/libsass/src/prelexer.cpp
@@ -1,3 +1,4 @@
+#include "sass.hpp"
 #include <cctype>
 #include <cstddef>
 #include <iostream>
@@ -15,6 +16,251 @@
   namespace Prelexer {
 
 
+    /*
+
+        def string_re(open, close)
+          /#{open}((?:\\.|\#(?!\{)|[^#{close}\\#])*)(#{close}|#\{)/m
+        end
+      end
+
+      # A hash of regular expressions that are used for tokenizing strings.
+      #
+      # The key is a `[Symbol, Boolean]` pair.
+      # The symbol represents which style of quotation to use,
+      # while the boolean represents whether or not the string
+      # is following an interpolated segment.
+      STRING_REGULAR_EXPRESSIONS = {
+        :double => {
+          /#{open}((?:\\.|\#(?!\{)|[^#{close}\\#])*)(#{close}|#\{)/m
+          false => string_re('"', '"'),
+          true => string_re('', '"')
+        },
+        :single => {
+          false => string_re("'", "'"),
+          true => string_re('', "'")
+        },
+        :uri => {
+          false => /url\(#{W}(#{URLCHAR}*?)(#{W}\)|#\{)/,
+          true => /(#{URLCHAR}*?)(#{W}\)|#\{)/
+        },
+        # Defined in https://developer.mozilla.org/en/CSS/@-moz-document as a
+        # non-standard version of http://www.w3.org/TR/css3-conditional/
+        :url_prefix => {
+          false => /url-prefix\(#{W}(#{URLCHAR}*?)(#{W}\)|#\{)/,
+          true => /(#{URLCHAR}*?)(#{W}\)|#\{)/
+        },
+        :domain => {
+          false => /domain\(#{W}(#{URLCHAR}*?)(#{W}\)|#\{)/,
+          true => /(#{URLCHAR}*?)(#{W}\)|#\{)/
+        }
+      }
+    */
+
+    /*
+      /#{open}
+        (
+          \\.
+          |
+          \# (?!\{)
+          |
+          [^#{close}\\#]
+        )*
+        (#{close}|#\{)
+      /m
+      false => string_re('"', '"'),
+      true => string_re('', '"')
+    */
+    extern const char string_double_negates[] = "\"\\#";
+    const char* re_string_double_close(const char* src)
+    {
+      return sequence <
+        // valid chars
+        zero_plus <
+          alternatives <
+            // escaped char
+            sequence <
+              exactly <'\\'>,
+              any_char
+            >,
+            // non interpolate hash
+            sequence <
+              exactly <'#'>,
+              negate <
+                exactly <'{'>
+              >
+            >,
+            // other valid chars
+            neg_class_char <
+              string_double_negates
+            >
+          >
+        >,
+        // quoted string closer
+        // or interpolate opening
+        alternatives <
+          exactly <'"'>,
+          lookahead < exactly< hash_lbrace > >
+        >
+      >(src);
+    }
+
+    const char* re_string_double_open(const char* src)
+    {
+      return sequence <
+        // quoted string opener
+        exactly <'"'>,
+        // valid chars
+        zero_plus <
+          alternatives <
+            // escaped char
+            sequence <
+              exactly <'\\'>,
+              any_char
+            >,
+            // non interpolate hash
+            sequence <
+              exactly <'#'>,
+              negate <
+                exactly <'{'>
+              >
+            >,
+            // other valid chars
+            neg_class_char <
+              string_double_negates
+            >
+          >
+        >,
+        // quoted string closer
+        // or interpolate opening
+        alternatives <
+          exactly <'"'>,
+          lookahead < exactly< hash_lbrace > >
+        >
+      >(src);
+    }
+
+    extern const char string_single_negates[] = "'\\#";
+    const char* re_string_single_close(const char* src)
+    {
+      return sequence <
+        // valid chars
+        zero_plus <
+          alternatives <
+            // escaped char
+            sequence <
+              exactly <'\\'>,
+              any_char
+            >,
+            // non interpolate hash
+            sequence <
+              exactly <'#'>,
+              negate <
+                exactly <'{'>
+              >
+            >,
+            // other valid chars
+            neg_class_char <
+              string_single_negates
+            >
+          >
+        >,
+        // quoted string closer
+        // or interpolate opening
+        alternatives <
+          exactly <'\''>,
+          lookahead < exactly< hash_lbrace > >
+        >
+      >(src);
+    }
+
+    const char* re_string_single_open(const char* src)
+    {
+      return sequence <
+        // quoted string opener
+        exactly <'\''>,
+        // valid chars
+        zero_plus <
+          alternatives <
+            // escaped char
+            sequence <
+              exactly <'\\'>,
+              any_char
+            >,
+            // non interpolate hash
+            sequence <
+              exactly <'#'>,
+              negate <
+                exactly <'{'>
+              >
+            >,
+            // other valid chars
+            neg_class_char <
+              string_single_negates
+            >
+          >
+        >,
+        // quoted string closer
+        // or interpolate opening
+        alternatives <
+          exactly <'\''>,
+          lookahead < exactly< hash_lbrace > >
+        >
+      >(src);
+    }
+
+    /*
+      :uri => {
+        false => /url\(#{W}(#{URLCHAR}*?)(#{W}\)|#\{)/,
+        true => /(#{URLCHAR}*?)(#{W}\)|#\{)/
+      },
+    */
+    const char* re_string_uri_close(const char* src)
+    {
+      return sequence <
+        non_greedy<
+          alternatives<
+            class_char< real_uri_chars >,
+            uri_character,
+            NONASCII,
+            ESCAPE
+          >,
+          alternatives<
+            sequence < optional < W >, exactly <')'> >,
+            lookahead < exactly< hash_lbrace > >
+          >
+        >,
+        optional <
+          sequence < optional < W >, exactly <')'> >
+        >
+      >(src);
+    }
+
+    const char* re_string_uri_open(const char* src)
+    {
+      return sequence <
+        exactly <'u'>,
+        exactly <'r'>,
+        exactly <'l'>,
+        exactly <'('>,
+        W,
+        alternatives<
+          quoted_string,
+          non_greedy<
+            alternatives<
+              class_char< real_uri_chars >,
+              uri_character,
+              NONASCII,
+              ESCAPE
+            >,
+            alternatives<
+              sequence < W, exactly <')'> >,
+              exactly< hash_lbrace >
+            >
+          >
+        >
+      >(src);
+    }
+
     // Match a line comment (/.*?(?=\n|\r\n?|\Z)/.
     const char* line_comment(const char* src)
     {
@@ -153,8 +399,8 @@
              >(src);
     }
 
-    // Match CSS unit identifier.
-    const char* unit_identifier(const char* src)
+    // Match a single CSS unit
+    const char* one_unit(const char* src)
     {
       return sequence <
                optional < exactly <'-'> >,
@@ -169,6 +415,34 @@
              >(src);
     }
 
+    // Match numerator/denominator CSS units
+    const char* multiple_units(const char* src)
+    {
+      return
+        sequence <
+          one_unit,
+          zero_plus <
+            sequence <
+              exactly <'*'>,
+              one_unit
+            >
+          >
+        >(src);
+    }
+
+    // Match complex CSS unit identifiers
+    const char* unit_identifier(const char* src)
+    {
+      return sequence <
+        multiple_units,
+        optional <
+          sequence <
+          exactly <'/'>,
+          multiple_units
+        > >
+      >(src);
+    }
+
     const char* identifier_alnums(const char* src)
     {
       return one_plus< identifier_alnum >(src);
@@ -194,7 +468,12 @@
                  sequence <
                    zero_plus <
                      alternatives <
-                       identifier,
+                       sequence <
+                         optional <
+                           exactly <'$'>
+                         >,
+                         identifier
+                       >,
                        exactly <'-'>
                      >
                    >,
@@ -202,9 +481,13 @@
                    zero_plus <
                      alternatives <
                        digits,
-                       identifier,
+                       sequence <
+                         optional <
+                           exactly <'$'>
+                         >,
+                         identifier
+                       >,
                        quoted_string,
-                       exactly<'+'>,
                        exactly<'-'>
                      >
                    >
@@ -278,24 +561,187 @@
       >(src);
     }
 
-    const char* value_schema(const char* src) {
-      // follows this pattern: ([xyz]*i[xyz]*)+
-      return one_plus< sequence< zero_plus< alternatives< identifier, percentage, dimension, hex, number, quoted_string > >,
-                                 interpolant,
-                                 zero_plus< alternatives< identifier, percentage, dimension, hex, number, quoted_string, exactly<'%'> > > > >(src);
+    const char* sass_value(const char* src) {
+      return alternatives <
+        quoted_string,
+        identifier,
+        percentage,
+        hex,
+        dimension,
+        number
+      >(src);
     }
 
-    /* not used anymore - remove?
-    const char* filename(const char* src) {
-      return one_plus< alternatives< identifier, number, exactly<'.'> > >(src);
+    // this is basically `one_plus < sass_value >`
+    // takes care to not parse invalid combinations
+    const char* value_combinations(const char* src) {
+      // `2px-2px` is invalid combo
+      bool was_number = false;
+      const char* pos = src;
+      while (src) {
+        if ((pos = alternatives < quoted_string, identifier, percentage, hex >(src))) {
+          was_number = false;
+          src = pos;
+        } else if (!was_number && !exactly<'+'>(src) && (pos = alternatives < dimension, number >(src))) {
+          was_number = true;
+          src = pos;
+        } else {
+          break;
+        }
+      }
+      return src;
     }
-    */
 
+    // must be at least one interpolant
+    // can be surrounded by sass values
+    // make sure to never parse (dim)(dim)
+    // since this wrongly consumes `2px-1px`
+    // `2px1px` is valid number (unit `px1px`)
+    const char* value_schema(const char* src)
+    {
+      return sequence <
+        one_plus <
+          sequence <
+            optional < value_combinations >,
+            interpolant,
+            optional < value_combinations >
+          >
+        >
+      >(src);
+    }
+
     // Match CSS '@' keywords.
     const char* at_keyword(const char* src) {
       return sequence<exactly<'@'>, identifier>(src);
     }
 
+    /*
+        tok(%r{
+          (
+            \\.
+          |
+            (?!url\()
+            [^"'/\#!;\{\}] # "
+          |
+            /(?![\*\/])
+          |
+            \#(?!\{)
+          |
+            !(?![a-z]) # TODO: never consume "!" when issue 1126 is fixed.
+          )+
+        }xi) || tok(COMMENT) || tok(SINGLE_LINE_COMMENT) || interp_string || interp_uri ||
+                interpolation(:warn_for_color)
+    */
+    const char* re_almost_any_value_token(const char* src) {
+
+      return alternatives <
+        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
+              >
+            >
+          >
+        >,
+        block_comment,
+        line_comment,
+        interpolant,
+        space,
+        sequence <
+          exactly<'u'>,
+          exactly<'r'>,
+          exactly<'l'>,
+          exactly<'('>,
+          zero_plus <
+            alternatives <
+              class_char< real_uri_chars >,
+              uri_character,
+              NONASCII,
+              ESCAPE
+            >
+          >,
+          // false => /url\(#{W}(#{URLCHAR}*?)(#{W}\)|#\{)/,
+          // true => /(#{URLCHAR}*?)(#{W}\)|#\{)/
+          exactly<')'>
+        >
+      >(src);
+    }
+
+    /*
+      DIRECTIVES = Set[:mixin, :include, :function, :return, :debug, :warn, :for,
+        :each, :while, :if, :else, :extend, :import, :media, :charset, :content,
+        :_moz_document, :at_root, :error]
+    */
+    const char* re_special_directive(const char* src) {
+      return alternatives <
+        word < mixin_kwd >,
+        word < include_kwd >,
+        word < function_kwd >,
+        word < return_kwd >,
+        word < debug_kwd >,
+        word < warn_kwd >,
+        word < for_kwd >,
+        word < each_kwd >,
+        word < while_kwd >,
+        word < if_kwd >,
+        word < else_kwd >,
+        word < extend_kwd >,
+        word < import_kwd >,
+        word < media_kwd >,
+        word < charset_kwd >,
+        word < content_kwd >,
+        // exactly < moz_document_kwd >,
+        word < at_root_kwd >,
+        word < error_kwd >
+      >(src);
+    }
+
+    const char* re_prefixed_directive(const char* src) {
+      return sequence <
+        optional <
+          sequence <
+            exactly <'-'>,
+            one_plus < alnum >,
+            exactly <'-'>
+          >
+        >,
+        exactly < supports_kwd >
+      >(src);
+    }
+
     const char* re_reference_combinator(const char* src) {
       return sequence <
         optional <
@@ -434,7 +880,7 @@
       return one_plus< alternatives< alnum,
                                      exactly<'-'>,
                                      exactly<'_'>,
-                                     exactly<'\\'> > >(src);
+                                     escape_seq > >(src);
     }
 
     const char* kwd_warn(const char* src) {
@@ -512,7 +958,7 @@
     }
 
     const char* hyphens_and_identifier(const char* src) {
-      return sequence< zero_plus< exactly< '-' > >, identifier >(src);
+      return sequence< zero_plus< exactly< '-' > >, identifier_alnums >(src);
     }
     const char* hyphens_and_name(const char* src) {
       return sequence< zero_plus< exactly< '-' > >, name >(src);
@@ -522,11 +968,11 @@
     }
     // Match CSS id names.
     const char* id_name(const char* src) {
-      return sequence<exactly<'#'>, name>(src);
+      return sequence<exactly<'#'>, identifier_alnums >(src);
     }
     // Match CSS class names.
     const char* class_name(const char* src) {
-      return sequence<exactly<'.'>, identifier>(src);
+      return sequence<exactly<'.'>, identifier >(src);
     }
     // Attribute name in an attribute selector.
     const char* attribute_name(const char* src) {
@@ -535,10 +981,13 @@
     }
     // match placeholder selectors
     const char* placeholder(const char* src) {
-      return sequence<exactly<'%'>, identifier>(src);
+      return sequence<exactly<'%'>, identifier_alnums >(src);
     }
     // Match CSS numeric constants.
 
+    const char* op(const char* src) {
+      return class_char<op_chars>(src);
+    }
     const char* sign(const char* src) {
       return class_char<sign_chars>(src);
     }
@@ -603,23 +1052,19 @@
     // Match CSS uri specifiers.
 
     const char* uri_prefix(const char* src) {
-      return exactly<url_kwd>(src);
-    }
-    const char* uri_value(const char* src)
-    {
-      return
-      sequence <
-        negate <
-          exactly < '$' >
+      return sequence <
+        exactly <
+          url_kwd
         >,
         zero_plus <
-          alternatives <
-            alnum,
-            interpolant,
-            exactly <'/'>,
-            class_char < uri_chars >
+          sequence <
+            exactly <'-'>,
+            one_plus <
+              alpha
+            >
           >
-        >
+        >,
+        exactly <'('>
       >(src);
     }
 
@@ -752,6 +1197,22 @@
       return sequence<exactly<'$'>, identifier>(src);
     }
 
+    // parse `calc`, `-a-calc` and `--b-c-calc`
+    // but do not parse `foocalc` or `foo-calc`
+    const char* calc_fn_call(const char* src) {
+      return sequence <
+        optional < sequence <
+          hyphens,
+          one_plus < sequence <
+            strict_identifier,
+            hyphens
+          > >
+        > >,
+        exactly < calc_fn_kwd >,
+        word_boundary
+      >(src);
+    }
+
     // Match Sass boolean keywords.
     const char* kwd_true(const char* src) {
       return word<true_kwd>(src);
@@ -1094,6 +1555,83 @@
       >(src);
     }
 
+    const char* re_selector_list(const char* src) {
+      return alternatives <
+        // partial bem selector
+        sequence <
+          ampersand,
+          one_plus <
+            exactly < '-' >
+          >,
+          word_boundary,
+          optional_spaces
+        >,
+        // main selector matching
+        one_plus <
+          alternatives <
+            // consume whitespace and comments
+            spaces, block_comment, line_comment,
+            // match `/deep/` selector (pass-trough)
+            // there is no functionality for it yet
+            schema_reference_combinator,
+            // match selector ops /[*&%,\[\]]/
+            class_char < selector_lookahead_ops >,
+            // match selector combinators /[>+~]/
+            class_char < selector_combinator_ops >,
+            // match attribute compare operators
+            sequence <
+              exactly <'('>,
+              optional_spaces,
+              optional <re_selector_list>,
+              optional_spaces,
+              exactly <')'>
+            >,
+            alternatives <
+              exact_match, class_match, dash_match,
+              prefix_match, suffix_match, substring_match
+            >,
+            // main selector match
+            sequence <
+              // allow namespace prefix
+              optional < namespace_schema >,
+              // modifiers prefixes
+              alternatives <
+                sequence <
+                  exactly <'#'>,
+                  // not for interpolation
+                  negate < exactly <'{'> >
+                >,
+                // class match
+                exactly <'.'>,
+                // single or double colon
+                optional < pseudo_prefix >
+              >,
+              // accept hypens in token
+              one_plus < sequence <
+                // can start with hyphens
+                zero_plus < exactly<'-'> >,
+                // now the main token
+                alternatives <
+                  kwd_optional,
+                  exactly <'*'>,
+                  quoted_string,
+                  interpolant,
+                  identifier,
+                  variable,
+                  percentage,
+                  binomial,
+                  dimension,
+                  alnum
+                >
+              > >,
+              // can also end with hyphens
+              zero_plus < exactly<'-'> >
+            >
+          >
+        >
+      >(src);
+    }
+
     const char* type_selector(const char* src) {
       return sequence< optional<namespace_schema>, identifier>(src);
     }
@@ -1107,34 +1645,44 @@
       return sequence< number, optional_spaces, exactly<'/'>, optional_spaces, number >(src);
     }
 
-    template <size_t size, prelexer mx, prelexer pad>
-    const char* padded_token(const char* src)
-    {
-      size_t got = 0;
-      const char* pos = src;
-      while (got < size) {
-        if (!mx(pos)) break;
-        ++ pos; ++ got;
-      }
-      while (got < size) {
-        if (!pad(pos)) break;
-        ++ pos; ++ got;
-      }
-      return got ? pos : 0;
-    }
+    // lexer special_fn: these functions cannot be overloaded
+    // (/((-[\w-]+-)?(calc|element)|expression|progid:[a-z\.]*)\(/i)
+    const char* re_special_fun(const char* src) {
 
-    template <size_t min, size_t max, prelexer mx>
-    const char* minmax_range(const char* src)
-    {
-      size_t got = 0;
-      const char* pos = src;
-      while (got < max) {
-        if (!mx(pos)) break;
-        ++ pos; ++ got;
+      // match this first as we test prefix hyphens
+      if (const char* calc = calc_fn_call(src)) {
+        return calc;
       }
-      if (got < min) return 0;
-      if (got > max) return 0;
-      return pos;
+
+      return sequence <
+        optional <
+          sequence <
+            exactly <'-'>,
+            one_plus <
+              alternatives <
+                alpha,
+                exactly <'+'>,
+                exactly <'-'>
+              >
+            >
+          >
+        >,
+        alternatives <
+          word < expression_kwd >,
+          sequence <
+            sequence <
+              exactly < progid_kwd >,
+              exactly <':'>
+            >,
+            zero_plus <
+              alternatives <
+                char_range <'a', 'z'>,
+                exactly <'.'>
+              >
+            >
+          >
+        >
+      >(src);
     }
 
   }
diff --git a/libsass/src/prelexer.hpp b/libsass/src/prelexer.hpp
--- a/libsass/src/prelexer.hpp
+++ b/libsass/src/prelexer.hpp
@@ -162,13 +162,19 @@
       return src;
     }
 
+    // equivalent of STRING_REGULAR_EXPRESSIONS
+    const char* re_string_double_open(const char* src);
+    const char* re_string_double_close(const char* src);
+    const char* re_string_single_open(const char* src);
+    const char* re_string_single_close(const char* src);
+    const char* re_string_uri_open(const char* src);
+    const char* re_string_uri_close(const char* src);
+
     // Match a line comment.
     const char* line_comment(const char* src);
-    const char* line_comment_prefix(const char* src);
 
     // Match a block comment.
     const char* block_comment(const char* src);
-    const char* block_comment_prefix(const char* src);
     // Match either.
     const char* comment(const char* src);
     // Match double- and single-quoted strings.
@@ -200,6 +206,8 @@
     const char* strict_identifier_alpha(const char* src);
     const char* strict_identifier_alnum(const char* src);
     // Match a CSS unit identifier.
+    const char* one_unit(const char* src);
+    const char* multiple_units(const char* src);
     const char* unit_identifier(const char* src);
     // const char* strict_identifier_alnums(const char* src);
     // Match reference selector.
@@ -210,11 +218,17 @@
     // Match interpolant schemas
     const char* identifier_schema(const char* src);
     const char* value_schema(const char* src);
+    const char* sass_value(const char* src);
     // const char* filename(const char* src);
     // const char* filename_schema(const char* src);
     // const char* url_schema(const char* src);
     // const char* url_value(const char* src);
     const char* vendor_prefix(const char* src);
+
+    const char* re_special_directive(const char* src);
+    const char* re_prefixed_directive(const char* src);
+    const char* re_almost_any_value_token(const char* src);
+
     // Match CSS '@' keywords.
     const char* at_keyword(const char* src);
     const char* kwd_import(const char* src);
@@ -252,6 +266,7 @@
     const char* re_nothing(const char* src);
     const char* re_type_selector2(const char* src);
 
+    const char* re_special_fun(const char* src);
 
     const char* kwd_warn(const char* src);
     const char* kwd_err(const char* src);
@@ -259,6 +274,7 @@
 
     const char* kwd_null(const char* src);
 
+    const char* re_selector_list(const char* src);
     const char* re_type_selector(const char* src);
     const char* re_static_expression(const char* src);
 
@@ -282,6 +298,7 @@
     // Match placeholder selectors.
     const char* placeholder(const char* src);
     // Match CSS numeric constants.
+    const char* op(const char* src);
     const char* sign(const char* src);
     const char* unsigned_number(const char* src);
     const char* number(const char* src);
@@ -296,7 +313,6 @@
     // const char* rgb_prefix(const char* src);
     // Match CSS uri specifiers.
     const char* uri_prefix(const char* src);
-    const char* uri_value(const char* src);
     // Match CSS "!important" keyword.
     const char* kwd_important(const char* src);
     // Match CSS "!optional" keyword.
@@ -329,6 +345,7 @@
 
     // Match SCSS variable names.
     const char* variable(const char* src);
+    const char* calc_fn_call(const char* src);
 
     // IE stuff
     const char* ie_progid(const char* src);
@@ -381,6 +398,18 @@
       }
       return 0;
     }
+    template<prelexer mx, prelexer skip>
+    const char* find_first_in_interval(const char* beg, const char* end) {
+      bool esc = false;
+      while ((beg < end) && *beg) {
+        if (esc) esc = false;
+        else if (*beg == '\\') esc = true;
+        else if (const char* pos = skip(beg)) beg = pos;
+        else if (mx(beg)) return beg;
+        ++beg;
+      }
+      return 0;
+    }
     template <prelexer mx>
     unsigned int count_interval(const char* beg, const char* end) {
       unsigned int counter = 0;
@@ -405,10 +434,42 @@
     }
 
     template <size_t size, prelexer mx, prelexer pad>
-    const char* padded_token(const char* src);
+    const char* padded_token(const char* src)
+    {
+      size_t got = 0;
+      const char* pos = src;
+      while (got < size) {
+        if (!mx(pos)) break;
+        ++ pos; ++ got;
+      }
+      while (got < size) {
+        if (!pad(pos)) break;
+        ++ pos; ++ got;
+      }
+      return got ? pos : 0;
+    }
 
     template <size_t min, size_t max, prelexer mx>
-    const char* minmax_range(const char* src);
+    const char* minmax_range(const char* src)
+    {
+      size_t got = 0;
+      const char* pos = src;
+      while (got < max) {
+        if (!mx(pos)) break;
+        ++ pos; ++ got;
+      }
+      if (got < min) return 0;
+      if (got > max) return 0;
+      return pos;
+    }
+
+    template <char min, char max>
+    const char* char_range(const char* src)
+    {
+      if (*src < min) return 0;
+      if (*src > max) return 0;
+      return src + 1;
+    }
 
   }
 }
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
@@ -1,7 +1,7 @@
+#include "sass.hpp"
 #include "remove_placeholders.hpp"
 #include "context.hpp"
 #include "inspect.hpp"
-#include "to_string.hpp"
 #include <iostream>
 
 namespace Sass {
@@ -10,45 +10,75 @@
     : ctx(ctx)
     { }
 
-    void Remove_Placeholders::operator()(Block* b) {
+    void Remove_Placeholders::operator()(Block_Ptr b) {
         for (size_t i = 0, L = b->length(); i < L; ++i) {
-            (*b)[i]->perform(this);
+            Statement_Ptr st = &b->at(i);
+            st->perform(this);
         }
     }
 
-    void Remove_Placeholders::operator()(Ruleset* r) {
+    Selector_List_Ptr Remove_Placeholders::remove_placeholders(Selector_List_Ptr sl)
+    {
+      Selector_List_Ptr new_sl = SASS_MEMORY_NEW(Selector_List, sl->pstate());
+
+      for (size_t i = 0, L = sl->length(); i < L; ++i) {
+          if (!sl->at(i)->contains_placeholder()) {
+              new_sl->append(sl->at(i));
+          }
+      }
+
+      return new_sl;
+
+    }
+
+
+    void Remove_Placeholders::operator()(Ruleset_Ptr r) {
         // Create a new selector group without placeholders
-        Selector_List* sl = static_cast<Selector_List*>(r->selector());
+        Selector_List_Obj sl = SASS_MEMORY_CAST(Selector_List, r->selector());
 
         if (sl) {
-            Selector_List* new_sl = SASS_MEMORY_NEW(ctx.mem, Selector_List, sl->pstate());
-
-            for (size_t i = 0, L = sl->length(); i < L; ++i) {
-                if (!(*sl)[i]->contains_placeholder()) {
-                    *new_sl << (*sl)[i];
+          // Set the new placeholder selector list
+          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);
+                      // also clean superflous parent selectors
+                      // probably not really the correct place
+                      clean->remove_parent_selectors();
+                      ws->selector(clean);
+                    }
+                  }
                 }
+              }
+              cs = cs->tail();
             }
-
-            // Set the new placeholder selector list
-            r->selector(new_sl);
+          }
         }
 
         // Iterate into child blocks
-        Block* b = r->block();
+        Block_Obj b = r->block();
 
         for (size_t i = 0, L = b->length(); i < L; ++i) {
-            if ((*b)[i]) (*b)[i]->perform(this);
+            if (b->at(i)) {
+                Statement_Obj st = b->at(i);
+                st->perform(this);
+            }
         }
     }
 
-    void Remove_Placeholders::operator()(Media_Block* m) {
-        Block* b = m->block();
-        for (size_t i = 0, L = b->length(); i < L; ++i) {
-            if ((*b)[i]) (*b)[i]->perform(this);
-        }
+    void Remove_Placeholders::operator()(Media_Block_Ptr m) {
+        operator()(&m->block());
     }
+    void Remove_Placeholders::operator()(Supports_Block_Ptr m) {
+        operator()(&m->block());
+    }
 
-    void Remove_Placeholders::operator()(At_Rule* a) {
+    void Remove_Placeholders::operator()(Directive_Ptr a) {
         if (a->block()) a->block()->perform(this);
     }
 
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
@@ -15,18 +15,20 @@
 
         Context&          ctx;
 
-        void fallback_impl(AST_Node* n) {}
+        void fallback_impl(AST_Node_Ptr n) {}
 
     public:
-        Remove_Placeholders(Context&);
-        virtual ~Remove_Placeholders() { }
+      Selector_List_Ptr remove_placeholders(Selector_List_Ptr);
 
-        using Operation<void>::operator();
+    public:
+        Remove_Placeholders(Context&);
+        ~Remove_Placeholders() { }
 
-        void operator()(Block*);
-        void operator()(Ruleset*);
-        void operator()(Media_Block*);
-        void operator()(At_Rule*);
+        void operator()(Block_Ptr);
+        void operator()(Ruleset_Ptr);
+        void operator()(Media_Block_Ptr);
+        void operator()(Supports_Block_Ptr);
+        void operator()(Directive_Ptr);
 
         template <typename U>
         void fallback(U x) { return fallback_impl(x); }
diff --git a/libsass/src/sass.cpp b/libsass/src/sass.cpp
--- a/libsass/src/sass.cpp
+++ b/libsass/src/sass.cpp
@@ -1,3 +1,4 @@
+#include "sass.hpp"
 #include <cstdlib>
 #include <cstring>
 #include <vector>
@@ -10,18 +11,42 @@
 extern "C" {
   using namespace Sass;
 
+  // Allocate libsass heap memory
+  // Don't forget string termination!
+  void* ADDCALL sass_alloc_memory(size_t size)
+  {
+    void* ptr = malloc(size);
+    if (ptr == NULL)
+      out_of_memory();
+    return ptr;
+  }
+
+  char* ADDCALL sass_copy_c_string(const char* str)
+  {
+    size_t len = strlen(str) + 1;
+    char* cpy = (char*) sass_alloc_memory(len);
+    std::memcpy(cpy, str, len);
+    return cpy;
+  }
+
+  // Deallocate libsass heap memory
+  void ADDCALL sass_free_memory(void* ptr)
+  {
+    if (ptr) free (ptr);
+  }
+
   // caller must free the returned memory
   char* ADDCALL sass_string_quote (const char *str, const char quote_mark)
   {
     std::string quoted = quote(str, quote_mark);
-    return sass_strdup(quoted.c_str());
+    return sass_copy_c_string(quoted.c_str());
   }
 
   // caller must free the returned memory
   char* ADDCALL sass_string_unquote (const char *str)
   {
     std::string unquoted = unquote(str);
-    return sass_strdup(unquoted.c_str());
+    return sass_copy_c_string(unquoted.c_str());
   }
 
   // Make sure to free the returned value!
@@ -29,13 +54,40 @@
   char* ADDCALL sass_resolve_file (const char* file, const char* paths[])
   {
     std::string resolved(File::find_file(file, paths));
-    return sass_strdup(resolved.c_str());
+    return sass_copy_c_string(resolved.c_str());
   }
 
   // Get compiled libsass version
   const char* ADDCALL libsass_version(void)
   {
     return LIBSASS_VERSION;
+  }
+
+  // Get compiled libsass version
+  const char* ADDCALL libsass_language_version(void)
+  {
+    return LIBSASS_LANGUAGE_VERSION;
+  }
+
+}
+
+namespace Sass {
+
+  // helper to aid dreaded MSVC debug mode
+  char* sass_copy_string(std::string str)
+  {
+    // In MSVC the following can lead to segfault:
+    // sass_copy_c_string(stream.str().c_str());
+    // Reason is that the string returned by str() is disposed before
+    // sass_copy_c_string is invoked. The string is actually a stack
+    // object, so indeed nobody is holding on to it. So it seems
+    // perfectly fair to release it right away. So the const char*
+    // by c_str will point to invalid memory. I'm not sure if this is
+    // the behavior for all compiler, but I'm pretty sure we would
+    // have gotten more issues reported if that would be the case.
+    // Wrapping it in a functions seems the cleanest approach as the
+    // function must hold on to the stack variable until it's done.
+    return sass_copy_c_string(str.c_str());
   }
 
 }
diff --git a/libsass/src/sass.hpp b/libsass/src/sass.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/sass.hpp
@@ -0,0 +1,136 @@
+// must be the first include in all compile units
+#ifndef SASS_SASS_H
+#define SASS_SASS_H
+
+// undefine extensions macro to tell sys includes
+// that we do not want any macros to be exported
+// mainly fixes an issue on SmartOS (SEC macro)
+#undef __EXTENSIONS__
+
+#ifdef _MSC_VER
+#pragma warning(disable : 4005)
+#endif
+
+// aplies to MSVC and MinGW
+#ifdef _WIN32
+// we do not want the ERROR macro
+# define NOGDI
+// we do not want the min/max macro
+# define NOMINMAX
+// we do not want the IN/OUT macro
+# define _NO_W32_PSEUDO_MODIFIERS
+#endif
+
+
+// should we be case insensitive
+// when dealing with files or paths
+#ifndef FS_CASE_SENSITIVE
+# ifdef _WIN32
+#  define FS_CASE_SENSITIVE 0
+# else
+#  define FS_CASE_SENSITIVE 1
+# endif
+#endif
+
+// path separation char
+#ifndef PATH_SEP
+# ifdef _WIN32
+#  define PATH_SEP ';'
+# else
+#  define PATH_SEP ':'
+# endif
+#endif
+
+
+// include C-API header
+#include "sass/base.h"
+
+// For C++ helper
+#include <string>
+
+// output behaviours
+namespace Sass {
+
+  // create some C++ aliases for the most used options
+  const static Sass_Output_Style NESTED = SASS_STYLE_NESTED;
+  const static Sass_Output_Style COMPACT = SASS_STYLE_COMPACT;
+  const static Sass_Output_Style EXPANDED = SASS_STYLE_EXPANDED;
+  const static Sass_Output_Style COMPRESSED = SASS_STYLE_COMPRESSED;
+  // only used internal to trigger ruby inspect behavior
+  const static Sass_Output_Style INSPECT = SASS_STYLE_INSPECT;
+  const static Sass_Output_Style TO_SASS = SASS_STYLE_TO_SASS;
+
+  // helper to aid dreaded MSVC debug mode
+  // see implementation for more details
+  char* sass_copy_string(std::string str);
+
+}
+
+// input behaviours
+enum Sass_Input_Style {
+  SASS_CONTEXT_NULL,
+  SASS_CONTEXT_FILE,
+  SASS_CONTEXT_DATA,
+  SASS_CONTEXT_FOLDER
+};
+
+// simple linked list
+struct string_list {
+  string_list* next;
+  char* string;
+};
+
+// sass config options structure
+struct Sass_Inspect_Options {
+
+  // Output style for the generated css code
+  // A value from above SASS_STYLE_* constants
+  enum Sass_Output_Style output_style;
+
+  // Precision for fractional numbers
+  int precision;
+
+  // initialization list (constructor with defaults)
+  Sass_Inspect_Options(Sass_Output_Style style = Sass::NESTED,
+                       int precision = 5)
+  : output_style(style), precision(precision)
+  { }
+
+};
+
+// sass config options structure
+struct Sass_Output_Options : Sass_Inspect_Options {
+
+  // String to be used for indentation
+  const char* indent;
+  // String to be used to for line feeds
+  const char* linefeed;
+
+  // Emit comments in the generated CSS indicating
+  // the corresponding source line.
+  bool source_comments;
+
+  // initialization list (constructor with defaults)
+  Sass_Output_Options(struct Sass_Inspect_Options opt,
+                      const char* indent = "  ",
+                      const char* linefeed = "\n",
+                      bool source_comments = false)
+  : Sass_Inspect_Options(opt),
+    indent(indent), linefeed(linefeed),
+    source_comments(source_comments)
+  { }
+
+  // initialization list (constructor with defaults)
+  Sass_Output_Options(Sass_Output_Style style = Sass::NESTED,
+                      int precision = 5,
+                      const char* indent = "  ",
+                      const char* linefeed = "\n",
+                      bool source_comments = false)
+  : Sass_Inspect_Options(style, precision),
+    indent(indent), linefeed(linefeed),
+    source_comments(source_comments)
+  { }
+
+};
+
+#endif
diff --git a/libsass/src/sass2scss.cpp b/libsass/src/sass2scss.cpp
--- a/libsass/src/sass2scss.cpp
+++ b/libsass/src/sass2scss.cpp
@@ -528,6 +528,13 @@
 			// reset converter state
 			converter.selector = false;
 
+			// looks like some undocumented behavior ...
+			// https://github.com/mgreter/sass2scss/issues/29
+			if (sass.substr(pos_left, 1) == "\\") {
+				converter.selector = true;
+				sass[pos_left] = ' ';
+			}
+
 			// check if we have sass property syntax
 			if (sass.substr(pos_left, 1) == ":" && sass.substr(pos_left, 2) != "::")
 			{
@@ -567,6 +574,12 @@
 					}
 				}
 
+				// check if we have a BEM property (one colon and no selector)
+				if (sass.substr(pos_left, 1) == ":" && converter.selector == true) {
+					size_t pos_wspace = sass.find_first_of(SASS2SCSS_FIND_WHITESPACE, pos_left);
+					sass = indent + sass.substr(pos_left + 1, pos_wspace) + ":";
+				}
+
 			}
 
 			// terminate some statements immediately
@@ -574,13 +587,19 @@
 				sass.substr(pos_left, 5) == "@warn" ||
 				sass.substr(pos_left, 6) == "@debug" ||
 				sass.substr(pos_left, 6) == "@error" ||
-				sass.substr(pos_left, 8) == "@charset"
+				sass.substr(pos_left, 8) == "@charset" ||
+				sass.substr(pos_left, 10) == "@namespace"
 			) { sass = indent + sass.substr(pos_left); }
 			// replace some specific sass shorthand directives (if not fallowed by a white space character)
-			else if (sass.substr(pos_left, 1) == "=" && sass.find_first_of(SASS2SCSS_FIND_WHITESPACE, pos_left) != pos_left + 1)
+			else if (sass.substr(pos_left, 1) == "=")
 			{ sass = indent + "@mixin " + sass.substr(pos_left + 1); }
-			else if (sass.substr(pos_left, 1) == "+" && sass.find_first_of(SASS2SCSS_FIND_WHITESPACE, pos_left) != pos_left + 1)
-			{ sass = indent + "@include " + sass.substr(pos_left + 1); }
+			else if (sass.substr(pos_left, 1) == "+")
+			{
+				// must be followed by a mixin call (no whitespace afterwards or at ending directly)
+				if (sass[pos_left+1] != 0 && sass[pos_left+1] != ' ' && sass[pos_left+1] != '\t') {
+					sass = indent + "@include " + sass.substr(pos_left + 1);
+				}
+			}
 
 			// add quotes for import if needed
 			else if (sass.substr(pos_left, 7) == "@import")
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
@@ -1,3 +1,4 @@
+#include "sass.hpp"
 #include <cstring>
 #include <stdexcept>
 #include <sstream>
@@ -5,82 +6,88 @@
 #include <vector>
 
 #include "sass.h"
+#include "ast.hpp"
 #include "file.hpp"
 #include "json.hpp"
 #include "util.hpp"
 #include "context.hpp"
 #include "sass_context.hpp"
+#include "sass_functions.hpp"
 #include "ast_fwd_decl.hpp"
 #include "error_handling.hpp"
 
 #define LFEED "\n"
 
-extern "C" {
-  using namespace Sass;
-
-  static void copy_options(struct Sass_Options* to, struct Sass_Options* from) { *to = *from; }
-
-  #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); } \
-    void ADDCALL sass_option_set_##option (struct Sass_Options* options, type option) \
-    { free(options->option); options->option = option || def ? sass_strdup(option ? option : def) : 0; }
-
-  #define IMPLEMENT_SASS_CONTEXT_GETTER(type, option) \
-    type ADDCALL sass_context_get_##option (struct Sass_Context* ctx) { return ctx->option; }
-  #define IMPLEMENT_SASS_CONTEXT_TAKER(type, option) \
-    type sass_context_take_##option (struct Sass_Context* ctx) \
-    { type foo = ctx->option; ctx->option = 0; return foo; }
+// C++ helper
+namespace Sass {
+  // see sass_copy_c_string(std::string str)
+  static inline JsonNode* json_mkstream(const std::stringstream& stream)
+  {
+    // hold on to string on stack!
+    std::string str(stream.str());
+    return json_mkstring(str.c_str());
+  }
 
-  static int handle_errors(Sass_Context* c_ctx) {
+  static int handle_error(Sass_Context* c_ctx) {
     try {
-     throw;
+      throw;
     }
     catch (Exception::Base& e) {
       std::stringstream msg_stream;
       std::string cwd(Sass::File::get_cwd());
-      std::string rel_path(Sass::File::abs2rel(e.pstate.path, cwd, cwd));
 
-      std::string msg_prefix("Error: ");
+      std::string msg_prefix(e.errtype());
       bool got_newline = false;
-      msg_stream << msg_prefix;
+      msg_stream << msg_prefix << ": ";
       const char* msg = e.what();
-      while(msg && *msg) {
+      while (msg && *msg) {
         if (*msg == '\r') {
           got_newline = true;
-        } else if (*msg == '\n') {
+        }
+        else if (*msg == '\n') {
           got_newline = true;
-        } else if (got_newline) {
-          msg_stream << std::string(msg_prefix.size(), ' ');
+        }
+        else if (got_newline) {
+          msg_stream << std::string(msg_prefix.size() + 2, ' ');
           got_newline = false;
         }
         msg_stream << *msg;
-        ++ msg;
+        ++msg;
       }
       if (!got_newline) msg_stream << "\n";
-      msg_stream << std::string(msg_prefix.size(), ' ');
-      msg_stream << " on line " << e.pstate.line+1 << " of " << rel_path << "\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 {
+        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";
+      }
 
       // 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;
         const char* line_beg = e.pstate.src;
         while (line_beg && *line_beg && line) {
-          if (*line_beg == '\n') -- line;
-          ++ line_beg;
+          if (*line_beg == '\n') --line;
+          ++line_beg;
         }
         const char* line_end = line_beg;
         while (line_end && *line_end && *line_end != '\n') {
           if (*line_end == '\n') break;
           if (*line_end == '\r') break;
-          line_end ++;
+          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;
+          (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";
       }
@@ -88,18 +95,18 @@
       JsonNode* json_err = json_mkobject();
       json_append_member(json_err, "status", json_mknumber(1));
       json_append_member(json_err, "file", json_mkstring(e.pstate.path));
-      json_append_member(json_err, "line", json_mknumber((double)(e.pstate.line+1)));
-      json_append_member(json_err, "column", json_mknumber((double)(e.pstate.column+1)));
+      json_append_member(json_err, "line", json_mknumber((double)(e.pstate.line + 1)));
+      json_append_member(json_err, "column", json_mknumber((double)(e.pstate.column + 1)));
       json_append_member(json_err, "message", json_mkstring(e.what()));
-      json_append_member(json_err, "formatted", json_mkstring(msg_stream.str().c_str()));
-
-      c_ctx->error_json = json_stringify(json_err, "  ");;
-      c_ctx->error_message = sass_strdup(msg_stream.str().c_str());
-      c_ctx->error_text = sass_strdup(e.what());
+      json_append_member(json_err, "formatted", json_mkstream(msg_stream));
+      try { c_ctx->error_json = json_stringify(json_err, "  "); }
+      catch (...) {}
+      c_ctx->error_message = sass_copy_string(msg_stream.str());
+      c_ctx->error_text = sass_copy_c_string(e.what());
       c_ctx->error_status = 1;
-      c_ctx->error_file = sass_strdup(e.pstate.path);
-      c_ctx->error_line = e.pstate.line+1;
-      c_ctx->error_column = e.pstate.column+1;
+      c_ctx->error_file = sass_copy_c_string(e.pstate.path);
+      c_ctx->error_line = e.pstate.line + 1;
+      c_ctx->error_column = e.pstate.column + 1;
       c_ctx->error_src = e.pstate.src;
       c_ctx->output_string = 0;
       c_ctx->source_map_string = 0;
@@ -111,9 +118,11 @@
       msg_stream << "Unable to allocate memory: " << ba.what() << std::endl;
       json_append_member(json_err, "status", json_mknumber(2));
       json_append_member(json_err, "message", json_mkstring(ba.what()));
-      c_ctx->error_json = json_stringify(json_err, "  ");;
-      c_ctx->error_message = sass_strdup(msg_stream.str().c_str());
-      c_ctx->error_text = sass_strdup(ba.what());
+      json_append_member(json_err, "formatted", json_mkstream(msg_stream));
+      try { c_ctx->error_json = json_stringify(json_err, "  "); }
+      catch (...) {}
+      c_ctx->error_message = sass_copy_string(msg_stream.str());
+      c_ctx->error_text = sass_copy_c_string(ba.what());
       c_ctx->error_status = 2;
       c_ctx->output_string = 0;
       c_ctx->source_map_string = 0;
@@ -122,12 +131,14 @@
     catch (std::exception& e) {
       std::stringstream msg_stream;
       JsonNode* json_err = json_mkobject();
-      msg_stream << "Error: " << e.what() << std::endl;
+      msg_stream << "Internal Error: " << e.what() << std::endl;
       json_append_member(json_err, "status", json_mknumber(3));
       json_append_member(json_err, "message", json_mkstring(e.what()));
-      c_ctx->error_json = json_stringify(json_err, "  ");;
-      c_ctx->error_message = sass_strdup(msg_stream.str().c_str());
-      c_ctx->error_text = sass_strdup(e.what());
+      json_append_member(json_err, "formatted", json_mkstream(msg_stream));
+      try { c_ctx->error_json = json_stringify(json_err, "  "); }
+      catch (...) {}
+      c_ctx->error_message = sass_copy_string(msg_stream.str());
+      c_ctx->error_text = sass_copy_c_string(e.what());
       c_ctx->error_status = 3;
       c_ctx->output_string = 0;
       c_ctx->source_map_string = 0;
@@ -136,12 +147,14 @@
     catch (std::string& e) {
       std::stringstream msg_stream;
       JsonNode* json_err = json_mkobject();
-      msg_stream << "Error: " << e << std::endl;
+      msg_stream << "Internal Error: " << e << std::endl;
       json_append_member(json_err, "status", json_mknumber(4));
       json_append_member(json_err, "message", json_mkstring(e.c_str()));
-      c_ctx->error_json = json_stringify(json_err, "  ");;
-      c_ctx->error_message = sass_strdup(msg_stream.str().c_str());
-      c_ctx->error_text = sass_strdup(e.c_str());
+      json_append_member(json_err, "formatted", json_mkstream(msg_stream));
+      try { c_ctx->error_json = json_stringify(json_err, "  "); }
+      catch (...) {}
+      c_ctx->error_message = sass_copy_string(msg_stream.str());
+      c_ctx->error_text = sass_copy_c_string(e.c_str());
       c_ctx->error_status = 4;
       c_ctx->output_string = 0;
       c_ctx->source_map_string = 0;
@@ -150,12 +163,14 @@
     catch (const char* e) {
       std::stringstream msg_stream;
       JsonNode* json_err = json_mkobject();
-      msg_stream << "Error: " << e << std::endl;
+      msg_stream << "Internal Error: " << e << std::endl;
       json_append_member(json_err, "status", json_mknumber(4));
       json_append_member(json_err, "message", json_mkstring(e));
-      c_ctx->error_json = json_stringify(json_err, "  ");;
-      c_ctx->error_message = sass_strdup(msg_stream.str().c_str());
-      c_ctx->error_text = sass_strdup(e);
+      json_append_member(json_err, "formatted", json_mkstream(msg_stream));
+      try { c_ctx->error_json = json_stringify(json_err, "  "); }
+      catch (...) {}
+      c_ctx->error_message = sass_copy_string(msg_stream.str());
+      c_ctx->error_text = sass_copy_c_string(e);
       c_ctx->error_status = 4;
       c_ctx->output_string = 0;
       c_ctx->source_map_string = 0;
@@ -167,9 +182,10 @@
       msg_stream << "Unknown error occurred" << std::endl;
       json_append_member(json_err, "status", json_mknumber(5));
       json_append_member(json_err, "message", json_mkstring("unknown"));
-      c_ctx->error_json = json_stringify(json_err, "  ");;
-      c_ctx->error_message = sass_strdup(msg_stream.str().c_str());
-      c_ctx->error_text = sass_strdup("unknown");
+      try { c_ctx->error_json = json_stringify(json_err, "  "); }
+      catch (...) {}
+      c_ctx->error_message = sass_copy_string(msg_stream.str());
+      c_ctx->error_text = sass_copy_c_string("unknown");
       c_ctx->error_status = 5;
       c_ctx->output_string = 0;
       c_ctx->source_map_string = 0;
@@ -178,45 +194,100 @@
     return c_ctx->error_status;
   }
 
-  // generic compilation function (not exported, use file/data compile instead)
-  static Sass_Compiler* sass_prepare_context (Sass_Context* c_ctx, Context* cpp_ctx) throw()
+  // allow one error handler to throw another error
+  // this can happen with invalid utf8 and json lib
+  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()
   {
+
+    // assert valid pointer
+    if (compiler == 0) return 0;
+    // The cpp context must be set by now
+    Context* cpp_ctx = compiler->cpp_ctx;
+    Sass_Context* c_ctx = compiler->c_ctx;
+    // We will take care to wire up the rest
+    compiler->cpp_ctx->c_compiler = compiler;
+    compiler->state = SASS_COMPILER_PARSED;
+
     try {
 
-      // convert include path linked list to static array
-      struct string_list* inc = c_ctx->include_paths;
-      // very poor loop to get the length of the linked list
-      size_t inc_size = 0; while (inc) { inc_size ++; inc = inc->next; }
-      // create char* array to hold all paths plus null terminator
-      const char** include_paths = (const char**) calloc(inc_size + 1, sizeof(char*));
-      if (include_paths == 0) throw(std::bad_alloc());
-      // reset iterator
-      inc = c_ctx->include_paths;
-      // copy over the paths
-      for (size_t i = 0; inc; i++) {
-        include_paths[i] = inc->string;
-        inc = inc->next;
-      }
+      // get input/output path from options
+      std::string input_path = safe_str(c_ctx->input_path);
+      std::string output_path = safe_str(c_ctx->output_path);
 
-      // convert plugin path linked list to static array
-      struct string_list* imp = c_ctx->plugin_paths;
-      // very poor loop to get the length of the linked list
-      size_t imp_size = 0; while (imp) { imp_size ++; imp = imp->next; }
-      // create char* array to hold all paths plus null terminator
-      const char** plugin_paths = (const char**) calloc(imp_size + 1, sizeof(char*));
-      if (plugin_paths == 0) throw(std::bad_alloc());
-      // reset iterator
-      imp = c_ctx->plugin_paths;
-      // copy over the paths
-      for (size_t i = 0; imp; i++) {
-        plugin_paths[i] = imp->string;
-        imp = imp->next;
-      }
+      // maybe skip some entries of included files
+      // we do not include stdin for data contexts
+      bool skip = c_ctx->type == SASS_CONTEXT_DATA;
 
-      // free intermediate data
-      free(include_paths);
-      free(plugin_paths);
+      // dispatch parse call
+      Block_Obj root(cpp_ctx->parse());
+      // abort on errors
+      if (!root) return 0;
 
+      // skip all prefixed files? (ToDo: check srcmap)
+      // IMO source-maps should point to headers already
+      // therefore don't skip it for now. re-enable or
+      // remove completely once this is tested
+      size_t headers = cpp_ctx->head_imports;
+
+      // copy the included files on to the context (dont forget to free later)
+      if (copy_strings(cpp_ctx->get_included_files(skip, headers), &c_ctx->included_files) == NULL)
+        throw(std::bad_alloc());
+
+      // return parsed block
+      return root;
+
+    }
+    // pass errors to generic error handler
+    catch (...) { handle_errors(c_ctx); }
+
+    // error
+    return 0;
+
+  }
+
+}
+
+extern "C" {
+  using namespace Sass;
+
+  static void sass_clear_options (struct Sass_Options* options);
+  static void sass_reset_options (struct Sass_Options* options);
+  static void copy_options(struct Sass_Options* to, struct Sass_Options* from) {
+    // do not overwrite ourself
+    if (to == from) return;
+    // free assigned memory
+    sass_clear_options(to);
+    // move memory
+    *to = *from;
+    // Reset pointers on source
+    sass_reset_options(from);
+  }
+
+  #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); } \
+    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_CONTEXT_GETTER(type, option) \
+    type ADDCALL sass_context_get_##option (struct Sass_Context* ctx) { return ctx->option; }
+  #define IMPLEMENT_SASS_CONTEXT_TAKER(type, option) \
+    type sass_context_take_##option (struct Sass_Context* ctx) \
+    { type foo = ctx->option; ctx->option = 0; return foo; }
+
+
+  // generic compilation function (not exported, use file/data compile instead)
+  static Sass_Compiler* sass_prepare_context (Sass_Context* c_ctx, Context* cpp_ctx) throw()
+  {
+    try {
       // register our custom functions
       if (c_ctx->c_functions) {
         auto this_func_data = c_ctx->c_functions;
@@ -276,58 +347,6 @@
 
   }
 
-  static Block* sass_parse_block (Sass_Compiler* compiler) throw()
-  {
-
-    // assert valid pointer
-    if (compiler == 0) return 0;
-    // The cpp context must be set by now
-    Context* cpp_ctx = compiler->cpp_ctx;
-    Sass_Context* c_ctx = compiler->c_ctx;
-    // We will take care to wire up the rest
-    compiler->cpp_ctx->c_compiler = compiler;
-    compiler->state = SASS_COMPILER_PARSED;
-
-    try {
-
-      // get input/output path from options
-      std::string input_path = safe_str(c_ctx->input_path);
-      std::string output_path = safe_str(c_ctx->output_path);
-
-      // parsed root block
-      Block* root = 0;
-
-      // maybe skip some entries of included files
-      // we do not include stdin for data contexts
-      bool skip = c_ctx->type == SASS_CONTEXT_DATA;
-
-      // dispatch parse call
-      root = cpp_ctx->parse();
-      // abort on errors
-      if (!root) return 0;
-
-      // skip all prefixed files? (ToDo: check srcmap)
-      // IMO source-maps should point to headers already
-      // therefore don't skip it for now. re-enable or
-      // remove completely once this is tested
-      size_t headers = cpp_ctx->head_imports;
-
-      // copy the included files on to the context (dont forget to free later)
-      if (copy_strings(cpp_ctx->get_included_files(skip, headers), &c_ctx->included_files) == NULL)
-        throw(std::bad_alloc());
-
-      // return parsed block
-      return root;
-
-    }
-    // pass errors to generic error handler
-    catch (...) { handle_errors(c_ctx); }
-
-    // error
-    return 0;
-
-  }
-
   // generic compilation function (not exported, use file/data compile instead)
   static int sass_compile_context (Sass_Context* c_ctx, Context* cpp_ctx)
   {
@@ -365,6 +384,7 @@
 
   Sass_File_Context* ADDCALL sass_make_file_context(const char* input_path)
   {
+    SharedObj::setTaint(true); // needed for static colors
     struct Sass_File_Context* ctx = (struct Sass_File_Context*) calloc(1, sizeof(struct Sass_File_Context));
     if (ctx == 0) { std::cerr << "Error allocating memory for file context" << std::endl; return 0; }
     ctx->type = SASS_CONTEXT_FILE;
@@ -398,14 +418,14 @@
   struct Sass_Compiler* ADDCALL sass_make_data_compiler (struct Sass_Data_Context* data_ctx)
   {
     if (data_ctx == 0) return 0;
-    Context* cpp_ctx = new Data_Context(data_ctx);
+    Context* cpp_ctx = new Data_Context(*data_ctx);
     return sass_prepare_context(data_ctx, cpp_ctx);
   }
 
   struct Sass_Compiler* ADDCALL sass_make_file_compiler (struct Sass_File_Context* file_ctx)
   {
     if (file_ctx == 0) return 0;
-    Context* cpp_ctx = new File_Context(file_ctx);
+    Context* cpp_ctx = new File_Context(*file_ctx);
     return sass_prepare_context(file_ctx, cpp_ctx);
   }
 
@@ -416,10 +436,11 @@
       return data_ctx->error_status;
     try {
       if (data_ctx->source_string == 0) { throw(std::runtime_error("Data context has no source string")); }
-      if (*data_ctx->source_string == 0) { throw(std::runtime_error("Data context has empty source string")); }
+      // empty source string is a valid case, even if not really usefull (different than with file context)
+      // if (*data_ctx->source_string == 0) { throw(std::runtime_error("Data context has empty source string")); }
     }
     catch (...) { return handle_errors(data_ctx) | 1; }
-    Context* cpp_ctx = new Data_Context(data_ctx);
+    Context* cpp_ctx = new Data_Context(*data_ctx);
     return sass_compile_context(data_ctx, cpp_ctx);
   }
 
@@ -433,7 +454,7 @@
       if (*file_ctx->input_path == 0) { throw(std::runtime_error("File context has empty input path")); }
     }
     catch (...) { return handle_errors(file_ctx) | 1; }
-    Context* cpp_ctx = new File_Context(file_ctx);
+    Context* cpp_ctx = new File_Context(*file_ctx);
     return sass_compile_context(file_ctx, cpp_ctx);
   }
 
@@ -447,7 +468,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;
   }
@@ -459,12 +480,12 @@
     if (compiler->state != SASS_COMPILER_PARSED) return -1;
     if (compiler->c_ctx == NULL) return 1;
     if (compiler->cpp_ctx == NULL) return 1;
-    if (compiler->root == NULL) return 1;
+    if (compiler->root.isNull()) return 1;
     if (compiler->c_ctx->error_status)
       return compiler->c_ctx->error_status;
     compiler->state = SASS_COMPILER_EXECUTED;
     Context* cpp_ctx = compiler->cpp_ctx;
-    Block* root = compiler->root;
+    Block_Obj root = compiler->root;
     // compile the parsed root block
     try { compiler->c_ctx->output_string = cpp_ctx->render(root); }
     // pass catched errors to generic error handler
@@ -476,6 +497,24 @@
   }
 
   // helper function, not exported, only accessible locally
+  static void sass_reset_options (struct Sass_Options* options)
+  {
+    // free pointer before
+    // or copy/move them
+    options->input_path = 0;
+    options->output_path = 0;
+    options->plugin_path = 0;
+    options->include_path = 0;
+    options->source_map_file = 0;
+    options->source_map_root = 0;
+    options->c_functions = 0;
+    options->c_importers = 0;
+    options->c_headers = 0;
+    options->plugin_paths = 0;
+    options->include_paths = 0;
+  }
+
+  // helper function, not exported, only accessible locally
   static void sass_clear_options (struct Sass_Options* options)
   {
     if (options == 0) return;
@@ -527,12 +566,25 @@
         cur = next;
       }
     }
+    // Free options strings
+    free(options->input_path);
+    free(options->output_path);
+    free(options->plugin_path);
+    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;
+    options->plugin_path = 0;
+    options->include_path = 0;
+    options->source_map_file = 0;
+    options->source_map_root = 0;
     options->c_functions = 0;
     options->c_importers = 0;
     options->c_headers = 0;
@@ -545,19 +597,13 @@
   static void sass_clear_context (struct Sass_Context* ctx)
   {
     if (ctx == 0) return;
-    // release the allocated memory (mostly via sass_strdup)
+    // release the allocated memory (mostly via sass_copy_c_string)
     if (ctx->output_string)     free(ctx->output_string);
     if (ctx->source_map_string) free(ctx->source_map_string);
     if (ctx->error_message)     free(ctx->error_message);
     if (ctx->error_text)        free(ctx->error_text);
     if (ctx->error_json)        free(ctx->error_json);
     if (ctx->error_file)        free(ctx->error_file);
-    if (ctx->input_path)        free(ctx->input_path);
-    if (ctx->output_path)       free(ctx->output_path);
-    if (ctx->plugin_path)       free(ctx->plugin_path);
-    if (ctx->include_path)      free(ctx->include_path);
-    if (ctx->source_map_file)   free(ctx->source_map_file);
-    if (ctx->source_map_root)   free(ctx->source_map_root);
     free_string_array(ctx->included_files);
     // play safe and reset properties
     ctx->output_string = 0;
@@ -566,12 +612,11 @@
     ctx->error_text = 0;
     ctx->error_json = 0;
     ctx->error_file = 0;
-    ctx->input_path = 0;
-    ctx->output_path = 0;
-    ctx->include_path = 0;
-    ctx->source_map_file = 0;
-    ctx->source_map_root = 0;
     ctx->included_files = 0;
+    // debug leaked memory
+    #ifdef DEBUG_SHARED_PTR
+      SharedObj::dumpMemLeaks();
+    #endif
     // now clear the options
     sass_clear_options(ctx);
   }
@@ -583,10 +628,17 @@
     }
     Context* cpp_ctx = compiler->cpp_ctx;
     if (cpp_ctx) delete(cpp_ctx);
-    compiler->cpp_ctx = 0;
+    compiler->cpp_ctx = NULL;
+    compiler->c_ctx = NULL;
+    compiler->root = NULL;
     free(compiler);
   }
 
+  void ADDCALL sass_delete_options (struct Sass_Options* options)
+  {
+    sass_clear_options(options); free(options);
+  }
+
   // Deallocate all associated memory with file context
   void ADDCALL sass_delete_file_context (struct Sass_File_Context* ctx)
   {
@@ -633,6 +685,7 @@
   IMPLEMENT_SASS_OPTION_ACCESSOR(bool, source_comments);
   IMPLEMENT_SASS_OPTION_ACCESSOR(bool, source_map_embed);
   IMPLEMENT_SASS_OPTION_ACCESSOR(bool, source_map_contents);
+  IMPLEMENT_SASS_OPTION_ACCESSOR(bool, source_map_file_urls);
   IMPLEMENT_SASS_OPTION_ACCESSOR(bool, omit_source_map_url);
   IMPLEMENT_SASS_OPTION_ACCESSOR(bool, is_indented_syntax_src);
   IMPLEMENT_SASS_OPTION_ACCESSOR(Sass_Function_List, c_functions);
@@ -675,7 +728,7 @@
 
     struct string_list* include_path = (struct string_list*) calloc(1, sizeof(struct string_list));
     if (include_path == 0) return;
-    include_path->string = path ? sass_strdup(path) : 0;
+    include_path->string = path ? sass_copy_c_string(path) : 0;
     struct string_list* last = options->include_paths;
     if (!options->include_paths) {
       options->include_paths = include_path;
@@ -693,7 +746,7 @@
 
     struct string_list* plugin_path = (struct string_list*) calloc(1, sizeof(struct string_list));
     if (plugin_path == 0) return;
-    plugin_path->string = path ? sass_strdup(path) : 0;
+    plugin_path->string = path ? sass_copy_c_string(path) : 0;
     struct string_list* last = options->plugin_paths;
     if (!options->plugin_paths) {
       options->plugin_paths = plugin_path;
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
@@ -2,36 +2,12 @@
 #define SASS_SASS_CONTEXT_H
 
 #include "sass.h"
+#include "sass.hpp"
 #include "context.hpp"
 #include "ast_fwd_decl.hpp"
 
-// Input behaviours
-enum Sass_Input_Style {
-  SASS_CONTEXT_NULL,
-  SASS_CONTEXT_FILE,
-  SASS_CONTEXT_DATA,
-  SASS_CONTEXT_FOLDER
-};
-
-// simple linked list
-struct string_list {
-  string_list* next;
-  char* string;
-};
-
 // sass config options structure
-struct Sass_Options {
-
-  // Precision for fractional numbers
-  int precision;
-
-  // Output style for the generated css code
-  // A value from above SASS_STYLE_* constants
-  enum Sass_Output_Style output_style;
-
-  // Emit comments in the generated CSS indicating
-  // the corresponding source line.
-  bool source_comments;
+struct Sass_Options : Sass_Output_Options {
 
   // embed sourceMappingUrl as data uri
   bool source_map_embed;
@@ -39,6 +15,9 @@
   // embed include contents in maps
   bool source_map_contents;
 
+  // create file urls for sources
+  bool source_map_file_urls;
+
   // Disable sourceMappingUrl in css output
   bool omit_source_map_url;
 
@@ -59,11 +38,6 @@
   // information in source-maps etc.
   char* output_path;
 
-  // String to be used for indentation
-  const char* indent;
-  // String to be used to for line feeds
-  const char* linefeed;
-
   // Colon-separated list of paths
   // Semicolon-separated on Windows
   // Maybe use array interface instead?
@@ -150,7 +124,7 @@
   // Sass::Context
   Sass::Context* cpp_ctx;
   // Sass::Block
-  Sass::Block* root;
+  Sass::Block_Obj root;
 };
 
 #endif
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
@@ -1,3 +1,4 @@
+#include "sass.hpp"
 #include <cstring>
 #include "util.hpp"
 #include "context.hpp"
@@ -71,8 +72,8 @@
   {
     Sass_Import* v = (Sass_Import*) calloc(1, sizeof(Sass_Import));
     if (v == 0) return 0;
-    v->imp_path = imp_path ? sass_strdup(imp_path) : 0;
-    v->abs_path = abs_path ? sass_strdup(abs_path) : 0;
+    v->imp_path = imp_path ? sass_copy_c_string(imp_path) : 0;
+    v->abs_path = abs_path ? sass_copy_c_string(abs_path) : 0;
     v->source = source;
     v->srcmap = srcmap;
     v->error = 0;
@@ -92,7 +93,7 @@
   {
     if (import == 0) return 0;
     if (import->error) free(import->error);
-    import->error = error ? sass_strdup(error) : 0;
+    import->error = error ? sass_copy_c_string(error) : 0;
     import->line = line ? line : -1;
     import->column = col ? col : -1;
     return import;
diff --git a/libsass/src/sass_interface.cpp b/libsass/src/sass_interface.cpp
deleted file mode 100644
--- a/libsass/src/sass_interface.cpp
+++ /dev/null
@@ -1,216 +0,0 @@
-#include <string>
-#include <cstdlib>
-#include <cstring>
-#include <sstream>
-#include <iostream>
-
-#include "util.hpp"
-#include "context.hpp"
-#include "inspect.hpp"
-#include "error_handling.hpp"
-#include "sass/base.h"
-#include "sass/interface.h"
-
-#define LFEED "\n"
-
-extern "C" {
-
-  sass_context* sass_new_context()
-  { return (sass_context*) calloc(1, sizeof(sass_context)); }
-
-  void sass_free_context(sass_context* ctx)
-  {
-    if (ctx->output_string)     free(ctx->output_string);
-    if (ctx->source_map_string) free(ctx->source_map_string);
-    if (ctx->error_message)     free(ctx->error_message);
-    if (ctx->c_functions)       free(ctx->c_functions);
-
-    Sass::free_string_array(ctx->included_files);
-
-    free(ctx);
-  }
-
-  sass_file_context* sass_new_file_context()
-  { return (sass_file_context*) calloc(1, sizeof(sass_file_context)); }
-
-  void sass_free_file_context(sass_file_context* ctx)
-  {
-    if (ctx->output_string)     free(ctx->output_string);
-    if (ctx->source_map_string) free(ctx->source_map_string);
-    if (ctx->error_message)     free(ctx->error_message);
-    if (ctx->c_functions)       free(ctx->c_functions);
-
-    Sass::free_string_array(ctx->included_files);
-
-    free(ctx);
-  }
-
-  sass_folder_context* sass_new_folder_context()
-  { return (sass_folder_context*) calloc(1, sizeof(sass_folder_context)); }
-
-  void sass_free_folder_context(sass_folder_context* ctx)
-  {
-    Sass::free_string_array(ctx->included_files);
-    free(ctx);
-  }
-
-  int sass_compile(sass_context* c_ctx)
-  {
-    using namespace Sass;
-    try {
-      std::string input_path = safe_str(c_ctx->input_path);
-      int lastindex = static_cast<int>(input_path.find_last_of("."));
-      std::string output_path;
-      if (!c_ctx->output_path) {
-        if (input_path != "") {
-          output_path = (lastindex > -1 ? input_path.substr(0, lastindex) : input_path) + ".css";
-        }
-      }
-      else {
-          output_path = c_ctx->output_path;
-      }
-      Data_Context cpp_ctx(
-        (Sass_Data_Context*) 0
-      );
-      if (c_ctx->c_functions) {
-        Sass_Function_List this_func_data = c_ctx->c_functions;
-        while ((this_func_data) && (*this_func_data)) {
-          cpp_ctx.c_functions.push_back(*this_func_data);
-          ++this_func_data;
-        }
-      }
-      Block* root = cpp_ctx.parse();
-      c_ctx->output_string = cpp_ctx.render(root);
-      c_ctx->source_map_string = cpp_ctx.render_srcmap();
-      c_ctx->error_message = 0;
-      c_ctx->error_status = 0;
-
-      if (copy_strings(cpp_ctx.get_included_files(true), &c_ctx->included_files, 1) == NULL)
-        throw(std::bad_alloc());
-    }
-    catch (Exception::InvalidSass& e) {
-      std::stringstream msg_stream;
-      msg_stream << e.pstate.path << ":" << e.pstate.line << ": " << e.what() << std::endl;
-      c_ctx->error_message = sass_strdup(msg_stream.str().c_str());
-      c_ctx->error_status = 1;
-      c_ctx->output_string = 0;
-      c_ctx->source_map_string = 0;
-    }
-    catch(std::bad_alloc& ba) {
-      std::stringstream msg_stream;
-      msg_stream << "Unable to allocate memory: " << ba.what() << std::endl;
-      c_ctx->error_message = sass_strdup(msg_stream.str().c_str());
-      c_ctx->error_status = 1;
-      c_ctx->output_string = 0;
-      c_ctx->source_map_string = 0;
-    }
-    catch (std::exception& e) {
-      std::stringstream msg_stream;
-      msg_stream << "Error: " << e.what() << std::endl;
-      c_ctx->error_message = sass_strdup(msg_stream.str().c_str());
-      c_ctx->error_status = 1;
-      c_ctx->output_string = 0;
-      c_ctx->source_map_string = 0;
-    }
-    catch (std::string& e) {
-      std::stringstream msg_stream;
-      msg_stream << "Error: " << e << std::endl;
-      c_ctx->error_message = sass_strdup(msg_stream.str().c_str());
-      c_ctx->error_status = 1;
-      c_ctx->output_string = 0;
-      c_ctx->source_map_string = 0;
-    }
-    catch (...) {
-      // couldn't find the specified file in the include paths; report an error
-      std::stringstream msg_stream;
-      msg_stream << "Unknown error occurred" << std::endl;
-      c_ctx->error_message = sass_strdup(msg_stream.str().c_str());
-      c_ctx->error_status = 1;
-      c_ctx->output_string = 0;
-      c_ctx->source_map_string = 0;
-    }
-    return 0;
-  }
-
-  int sass_compile_file(sass_file_context* c_ctx)
-  {
-    using namespace Sass;
-    try {
-      std::string input_path = safe_str(c_ctx->input_path);
-      int lastindex = static_cast<int>(input_path.find_last_of("."));
-      std::string output_path;
-      if (!c_ctx->output_path) {
-          output_path = (lastindex > -1 ? input_path.substr(0, lastindex) : input_path) + ".css";
-      }
-      else {
-          output_path = c_ctx->output_path;
-      }
-      File_Context cpp_ctx(
-        (Sass_File_Context*) 0
-      );
-      if (c_ctx->c_functions) {
-        Sass_Function_List this_func_data = c_ctx->c_functions;
-        while ((this_func_data) && (*this_func_data)) {
-          cpp_ctx.c_functions.push_back(*this_func_data);
-          ++this_func_data;
-        }
-      }
-      Block* root = cpp_ctx.parse();
-      c_ctx->output_string = cpp_ctx.render(root);
-      c_ctx->source_map_string = cpp_ctx.render_srcmap();
-      c_ctx->error_message = 0;
-      c_ctx->error_status = 0;
-
-      if (copy_strings(cpp_ctx.get_included_files(false), &c_ctx->included_files) == NULL)
-        throw(std::bad_alloc());
-    }
-    catch (Exception::InvalidSass& e) {
-      std::stringstream msg_stream;
-      msg_stream << e.pstate.path << ":" << e.pstate.line << ": " << e.what() << std::endl;
-      c_ctx->error_message = sass_strdup(msg_stream.str().c_str());
-      c_ctx->error_status = 1;
-      c_ctx->output_string = 0;
-      c_ctx->source_map_string = 0;
-    }
-    catch(std::bad_alloc& ba) {
-      std::stringstream msg_stream;
-      msg_stream << "Unable to allocate memory: " << ba.what() << std::endl;
-      c_ctx->error_message = sass_strdup(msg_stream.str().c_str());
-      c_ctx->error_status = 1;
-      c_ctx->output_string = 0;
-      c_ctx->source_map_string = 0;
-    }
-    catch (std::exception& e) {
-      std::stringstream msg_stream;
-      msg_stream << "Error: " << e.what() << std::endl;
-      c_ctx->error_message = sass_strdup(msg_stream.str().c_str());
-      c_ctx->error_status = 1;
-      c_ctx->output_string = 0;
-      c_ctx->source_map_string = 0;
-    }
-    catch (std::string& e) {
-      std::stringstream msg_stream;
-      msg_stream << "Error: " << e << std::endl;
-      c_ctx->error_message = sass_strdup(msg_stream.str().c_str());
-      c_ctx->error_status = 1;
-      c_ctx->output_string = 0;
-      c_ctx->source_map_string = 0;
-    }
-    catch (...) {
-      // couldn't find the specified file in the include paths; report an error
-      std::stringstream msg_stream;
-      msg_stream << "Unknown error occurred" << std::endl;
-      c_ctx->error_message = sass_strdup(msg_stream.str().c_str());
-      c_ctx->error_status = 1;
-      c_ctx->output_string = 0;
-      c_ctx->source_map_string = 0;
-    }
-    return 0;
-  }
-
-  int sass_compile_folder(sass_folder_context* c_ctx)
-  {
-    return 1;
-  }
-
-}
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
@@ -1,5 +1,5 @@
+#include "sass.hpp"
 #include "node.hpp"
-#include "to_string.hpp"
 
 namespace Sass {
 
@@ -38,7 +38,6 @@
     end
   */
   Node paths(const Node& arrs, Context& ctx) {
-    To_String to_string(&ctx);
 
     Node loopStart = Node::createCollection();
     loopStart.collection()->push_back(Node::createCollection());
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
@@ -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 (one == two) {
+      if (nodesEqual(one, two, true)) {
         out = one;
         return true;
       }
@@ -221,28 +221,28 @@
 
     std::map<unsigned int, KeyType> order;
 
-    std::map<KeyType, std::vector<EnumType> > grouped;
+    std::map<size_t, std::vector<EnumType> > grouped;
 
     for (typename std::vector<EnumType>::iterator enumIter = enumeration.begin(), enumIterEnd = enumeration.end(); enumIter != enumIterEnd; enumIter++) {
       EnumType& e = *enumIter;
 
       KeyType key = keyFunc(e);
 
-      if (grouped.find(key) == grouped.end()) {
+      if (grouped.find(key->hash()) == grouped.end()) {
         order.insert(std::make_pair((unsigned int)order.size(), key));
 
         std::vector<EnumType> newCollection;
         newCollection.push_back(e);
-        grouped.insert(std::make_pair(key, newCollection));
+        grouped.insert(std::make_pair(key->hash(), newCollection));
       } else {
-        std::vector<EnumType>& collection = grouped.at(key);
+        std::vector<EnumType>& collection = grouped.at(key->hash());
         collection.push_back(e);
       }
     }
 
     for (unsigned int index = 0; index < order.size(); index++) {
       KeyType& key = order.at(index);
-      std::vector<EnumType>& values = grouped.at(key);
+      std::vector<EnumType>& values = grouped.at(key->hash());
 
       std::pair<KeyType, std::vector<EnumType> > grouping = std::make_pair(key, values);
 
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
@@ -1,3 +1,4 @@
+#include "sass.hpp"
 #include <cstdlib>
 #include <cstring>
 #include "util.hpp"
@@ -90,7 +91,7 @@
     if (v == 0) return 0;
     v->number.tag = SASS_NUMBER;
     v->number.value = val;
-    v->number.unit = unit ? sass_strdup(unit) : 0;
+    v->number.unit = unit ? sass_copy_c_string(unit) : 0;
     if (v->number.unit == 0) { free(v); return 0; }
     return v;
   }
@@ -113,7 +114,7 @@
     if (v == 0) return 0;
     v->string.quoted = false;
     v->string.tag = SASS_STRING;
-    v->string.value = val ? sass_strdup(val) : 0;
+    v->string.value = val ? sass_copy_c_string(val) : 0;
     if (v->string.value == 0) { free(v); return 0; }
     return v;
   }
@@ -124,7 +125,7 @@
     if (v == 0) return 0;
     v->string.quoted = true;
     v->string.tag = SASS_STRING;
-    v->string.value = val ? sass_strdup(val) : 0;
+    v->string.value = val ? sass_copy_c_string(val) : 0;
     if (v->string.value == 0) { free(v); return 0; }
     return v;
   }
@@ -165,7 +166,7 @@
     union Sass_Value* v = (Sass_Value*) calloc(1, sizeof(Sass_Value));
     if (v == 0) return 0;
     v->error.tag = SASS_ERROR;
-    v->error.message = msg ? sass_strdup(msg) : 0;
+    v->error.message = msg ? sass_copy_c_string(msg) : 0;
     if (v->error.message == 0) { free(v); return 0; }
     return v;
   }
@@ -175,7 +176,7 @@
     union Sass_Value* v = (Sass_Value*) calloc(1, sizeof(Sass_Value));
     if (v == 0) return 0;
     v->warning.tag = SASS_WARNING;
-    v->warning.message = msg ? sass_strdup(msg) : 0;
+    v->warning.message = msg ? sass_copy_c_string(msg) : 0;
     if (v->warning.message == 0) { free(v); return 0; }
     return v;
   }
@@ -274,58 +275,60 @@
 
   union Sass_Value* ADDCALL sass_value_stringify (const union Sass_Value* v, bool compressed, int precision)
   {
-    Memory_Manager mem;
-    Value* val = sass_value_to_ast_node(mem, v);
-    std::string str(val->to_string(compressed, precision));
+    Value_Obj val = sass_value_to_ast_node(v);
+    Sass_Inspect_Options options(compressed ? COMPRESSED : NESTED, precision);
+    std::string str(val->to_string(options));
     return sass_make_qstring(str.c_str());
   }
 
   union Sass_Value* ADDCALL sass_value_op (enum Sass_OP op, const union Sass_Value* a, const union Sass_Value* b)
   {
 
-    Sass::Value* rv = 0;
-    Memory_Manager mem;
+    Sass::Value_Ptr rv = 0;
 
     try {
 
-      Value* lhs = sass_value_to_ast_node(mem, a);
-      Value* rhs = sass_value_to_ast_node(mem, b);
+      Value_Obj lhs = sass_value_to_ast_node(a);
+      Value_Obj rhs = sass_value_to_ast_node(b);
+      struct Sass_Inspect_Options options(NESTED, 5);
 
       // 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) && !Eval::eq(lhs, rhs));
-        case Sass_OP::GTE: return sass_make_boolean(!Eval::lt(lhs, rhs));
-        case Sass_OP::LT:  return sass_make_boolean(Eval::lt(lhs, rhs));
-        case Sass_OP::LTE: return sass_make_boolean(Eval::lt(lhs, rhs) || Eval::eq(lhs, rhs));
+        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;
       }
 
       if (sass_value_is_number(a) && sass_value_is_number(b)) {
-        const Number* l_n = dynamic_cast<const Number*>(lhs);
-        const Number* r_n = dynamic_cast<const Number*>(rhs);
-        rv = Eval::op_numbers(mem, op, *l_n, *r_n);
+        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);
       }
       else if (sass_value_is_number(a) && sass_value_is_color(a)) {
-        const Number* l_n = dynamic_cast<const Number*>(lhs);
-        const Color* r_c = dynamic_cast<const Color*>(rhs);
-        rv = Eval::op_number_color(mem, op, *l_n, *r_c);
+        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);
       }
       else if (sass_value_is_color(a) && sass_value_is_number(b)) {
-        const Color* l_c = dynamic_cast<const Color*>(lhs);
-        const Number* r_n = dynamic_cast<const Number*>(rhs);
-        rv = Eval::op_color_number(mem, op, *l_c, *r_n);
+        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);
       }
       else if (sass_value_is_color(a) && sass_value_is_color(b)) {
-        const Color* l_c = dynamic_cast<const Color*>(lhs);
-        const Color* r_c = dynamic_cast<const Color*>(rhs);
-        rv = Eval::op_colors(mem, op, *l_c, *r_c);
+        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);
       }
       else /* convert other stuff to string and apply operation */ {
-        Value* l_v = dynamic_cast<Value*>(lhs);
-        Value* r_v = dynamic_cast<Value*>(rhs);
-        rv = Eval::op_strings(mem, op, *l_v, *r_v);
+        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);
       }
 
       // ToDo: maybe we should should return null value?
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
@@ -1,3 +1,4 @@
+#include "sass.hpp"
 #include <string>
 #include <sstream>
 #include <iostream>
@@ -16,7 +17,7 @@
 
   std::string SourceMap::render_srcmap(Context &ctx) {
 
-    const bool include_sources = ctx.c_options->source_map_contents;
+    const bool include_sources = ctx.c_options.source_map_contents;
     const std::vector<std::string> links = ctx.srcmap_links;
     const std::vector<Resource>& sources(ctx.resources);
 
@@ -24,20 +25,32 @@
 
     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);
+
     // pass-through sourceRoot option
     if (!ctx.source_map_root.empty()) {
       JsonNode* root = json_mkstring(ctx.source_map_root.c_str());
       json_append_member(json_srcmap, "sourceRoot", root);
     }
 
-    const char *include = file.c_str();
-    JsonNode *json_include = json_mkstring(include);
-    json_append_member(json_srcmap, "file", json_include);
-
     JsonNode *json_includes = json_mkarray();
     for (size_t i = 0; i < source_index.size(); ++i) {
-      const char *include = links[source_index[i]].c_str();
-      JsonNode *json_include = json_mkstring(include);
+      std::string include(links[source_index[i]]);
+      if (ctx.c_options.source_map_file_urls) {
+        include = File::rel2abs(include);
+        // check for windows abs path
+        if (include[0] == '/') {
+          // ends up with three slashes
+          include = "file://" + include;
+        } else {
+          // needs an additional slash
+          include = "file:///" + include;
+        }
+      }
+      const char* inc = include.c_str();
+      JsonNode *json_include = json_mkstring(inc);
       json_append_element(json_includes, json_include);
     }
     json_append_member(json_srcmap, "sources", json_includes);
@@ -53,15 +66,15 @@
         json_append_member(json_srcmap, "sourcesContent", json_contents);
     }
 
-    std::string mappings = serialize_mappings();
-    JsonNode *json_mappings = json_mkstring(mappings.c_str());
-    json_append_member(json_srcmap, "mappings", json_mappings);
-
     JsonNode *json_names = json_mkarray();
     // so far we have no implementation for names
     // no problem as we do not alter any identifiers
     json_append_member(json_srcmap, "names", json_names);
 
+    std::string mappings = serialize_mappings();
+    JsonNode *json_mappings = json_mkstring(mappings.c_str());
+    json_append_member(json_srcmap, "mappings", json_mappings);
+
     char *str = json_stringify(json_srcmap, "\t");
     std::string result = std::string(str);
     free(str);
@@ -159,12 +172,12 @@
     current_position += offset;
   }
 
-  void SourceMap::add_open_mapping(AST_Node* node)
+  void SourceMap::add_open_mapping(const AST_Node_Ptr node)
   {
     mappings.push_back(Mapping(node->pstate(), current_position));
   }
 
-  void SourceMap::add_close_mapping(AST_Node* node)
+  void SourceMap::add_close_mapping(const AST_Node_Ptr node)
   {
     mappings.push_back(Mapping(node->pstate() + node->pstate().offset, current_position));
   }
diff --git a/libsass/src/source_map.hpp b/libsass/src/source_map.hpp
--- a/libsass/src/source_map.hpp
+++ b/libsass/src/source_map.hpp
@@ -28,8 +28,8 @@
     void prepend(const Offset& offset);
     void append(const OutputBuffer& out);
     void prepend(const OutputBuffer& out);
-    void add_open_mapping(AST_Node* node);
-    void add_close_mapping(AST_Node* node);
+    void add_open_mapping(const AST_Node_Ptr node);
+    void add_close_mapping(const AST_Node_Ptr node);
 
     std::string render_srcmap(Context &ctx);
     ParserState remap(const ParserState& pstate);
diff --git a/libsass/src/subset_map.cpp b/libsass/src/subset_map.cpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/subset_map.cpp
@@ -0,0 +1,57 @@
+#include "sass.hpp"
+#include "ast.hpp"
+#include "subset_map.hpp"
+
+namespace Sass {
+
+  void Subset_Map::put(const Compound_Selector_Obj& sel, const Subset_Map_Val& 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));
+    }
+  }
+
+  std::vector<Subset_Map_Val> 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());
+    std::vector<size_t> indices;
+    for (size_t i = 0, S = sel->length(); i < S; ++i) {
+      if (!hash_.count((*sel)[i])) {
+        continue;
+      }
+      const std::vector<std::pair<Compound_Selector_Obj, size_t> >& subsets = hash_[(*sel)[i]];
+      for (const std::pair<Compound_Selector_Obj, size_t>& item : subsets) {
+        bool include = true;
+        for (const Simple_Selector_Obj& it : item.first->elements()) {
+          auto found = dict.find(it);
+          if (found == dict.end()) {
+            include = false;
+            break;
+          }
+        }
+        if (include) indices.push_back(item.second);
+      }
+    }
+    sort(indices.begin(), indices.end());
+    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;
+    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)
+  {
+    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
@@ -7,7 +7,9 @@
 #include <algorithm>
 #include <iterator>
 
+#include "ast_fwd_decl.hpp"
 
+
 // #include <iostream>
 // #include <sstream>
 // template<typename T>
@@ -56,89 +58,18 @@
 
 namespace Sass {
 
-  template<typename F, typename S, typename T>
-  struct triple {
-    F first;
-    S second;
-    T third;
-
-    triple(const F& f, const S& s, const T& t) : first(f), second(s), third(t) { }
-  };
-
-  template<typename F, typename S, typename T>
-  triple<F, S, T> make_triple(const F& f, const S& s, const T& t)
-  { return triple<F, S, T>(f, s, t); }
-
-  template<typename K, typename V>
   class Subset_Map {
   private:
-    std::vector<V> values_;
-    std::map<K, std::vector<triple<std::vector<K>, std::set<K>, size_t> > > hash_;
+    std::vector<Subset_Map_Val> values_;
+    std::map<Simple_Selector_Obj, std::vector<std::pair<Compound_Selector_Obj, size_t> > > hash_;
   public:
-    void put(const std::vector<K>& s, const V& value);
-    std::vector<std::pair<V, std::vector<K> > > get_kv(const std::vector<K>& s);
-    std::vector<V> get_v(const std::vector<K>& s);
+    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);
     bool empty() { return values_.empty(); }
     void clear() { values_.clear(); hash_.clear(); }
-    const std::vector<V> values(void) { return values_; }
+    const std::vector<Subset_Map_Val> values(void) { return values_; }
   };
-
-  template<typename K, typename V>
-  void Subset_Map<K, V>::put(const std::vector<K>& s, const V& value)
-  {
-    if (s.empty()) throw "internal error: subset map keys may not be empty";
-    size_t index = values_.size();
-    values_.push_back(value);
-    std::set<K> ss;
-    for (size_t i = 0, S = s.size(); i < S; ++i)
-    { ss.insert(s[i]); }
-    for (size_t i = 0, S = s.size(); i < S; ++i)
-    {
-      hash_[s[i]];
-      hash_[s[i]].push_back(make_triple(s, ss, index));
-    }
-  }
-
-  template<typename K, typename V>
-  std::vector<std::pair<V, std::vector<K> > > Subset_Map<K, V>::get_kv(const std::vector<K>& s)
-  {
-    std::vector<K> sorted = s;
-    sort(sorted.begin(), sorted.end());
-    std::vector<std::pair<size_t, std::vector<K> > > indices;
-    for (size_t i = 0, S = s.size(); i < S; ++i) {
-      if (!hash_.count(s[i])) {
-        continue;
-      }
-      std::vector<triple<std::vector<K>, std::set<K>, size_t> > subsets = hash_[s[i]];
-      // std::cerr << "length of subsets: " << subsets.size() << std::endl;
-      for (size_t j = 0, T = subsets.size(); j < T; ++j) {
-        if (!includes(sorted.begin(), sorted.end(), subsets[j].second.begin(), subsets[j].second.end())) {
-          // std::cout << vector_to_string(s) << " doesn't include " << set_to_string(subsets[j].second) << std::endl;
-          continue;
-        }
-        indices.push_back(std::make_pair(subsets[j].third, subsets[j].first));
-        // std::cerr << "pushed " << subsets[j].third << " and " << vector_to_string(subsets[j].first) << " onto indices" << std::endl;
-      }
-    }
-    sort(indices.begin(), indices.end());
-    typename std::vector<std::pair<size_t, std::vector<K> > >::iterator indices_end = unique(indices.begin(), indices.end());
-    indices.resize(distance(indices.begin(), indices_end));
-
-    std::vector<std::pair<V, std::vector<K> > > results;
-    for (size_t i = 0, S = indices.size(); i < S; ++i) {
-      results.push_back(std::make_pair(values_[indices[i].first], indices[i].second));
-    }
-    return results;
-  }
-
-  template<typename K, typename V>
-  std::vector<V> Subset_Map<K, V>::get_v(const std::vector<K>& s)
-  {
-    std::vector<std::pair<V, std::vector<K> > > kvs = get_kv(s);
-    std::vector<V> results;
-    for (size_t i = 0, S = kvs.size(); i < S; ++i) results.push_back(kvs[i].first);
-    return results;
-  }
 
 }
 
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
@@ -1,27 +1,28 @@
+#include "sass.hpp"
 #include "to_c.hpp"
 #include "ast.hpp"
 
 namespace Sass {
 
-  union Sass_Value* To_C::fallback_impl(AST_Node* n)
+  union Sass_Value* To_C::fallback_impl(AST_Node_Ptr n)
   { return sass_make_error("unknown type for C-API"); }
 
-  union Sass_Value* To_C::operator()(Boolean* b)
+  union Sass_Value* To_C::operator()(Boolean_Ptr b)
   { return sass_make_boolean(b->value()); }
 
-  union Sass_Value* To_C::operator()(Number* n)
+  union Sass_Value* To_C::operator()(Number_Ptr n)
   { return sass_make_number(n->value(), n->unit().c_str()); }
 
-  union Sass_Value* To_C::operator()(Custom_Warning* w)
+  union Sass_Value* To_C::operator()(Custom_Warning_Ptr w)
   { return sass_make_warning(w->message().c_str()); }
 
-  union Sass_Value* To_C::operator()(Custom_Error* e)
+  union Sass_Value* To_C::operator()(Custom_Error_Ptr e)
   { return sass_make_error(e->message().c_str()); }
 
-  union Sass_Value* To_C::operator()(Color* c)
+  union Sass_Value* To_C::operator()(Color_Ptr c)
   { return sass_make_color(c->r(), c->g(), c->b(), c->a()); }
 
-  union Sass_Value* To_C::operator()(String_Constant* s)
+  union Sass_Value* To_C::operator()(String_Constant_Ptr s)
   {
     if (s->quote_mark()) {
       return sass_make_qstring(s->value().c_str());
@@ -30,10 +31,10 @@
     }
   }
 
-  union Sass_Value* To_C::operator()(String_Quoted* s)
+  union Sass_Value* To_C::operator()(String_Quoted_Ptr s)
   { return sass_make_qstring(s->value().c_str()); }
 
-  union Sass_Value* To_C::operator()(List* l)
+  union Sass_Value* To_C::operator()(List_Ptr l)
   {
     union Sass_Value* v = sass_make_list(l->length(), l->separator());
     for (size_t i = 0, L = l->length(); i < L; ++i) {
@@ -42,7 +43,7 @@
     return v;
   }
 
-  union Sass_Value* To_C::operator()(Map* m)
+  union Sass_Value* To_C::operator()(Map_Ptr m)
   {
     union Sass_Value* v = sass_make_map(m->length());
     int i = 0;
@@ -54,7 +55,7 @@
     return v;
   }
 
-  union Sass_Value* To_C::operator()(Arguments* a)
+  union Sass_Value* To_C::operator()(Arguments_Ptr a)
   {
     union Sass_Value* v = sass_make_list(a->length(), SASS_COMMA);
     for (size_t i = 0, L = a->length(); i < L; ++i) {
@@ -63,11 +64,11 @@
     return v;
   }
 
-  union Sass_Value* To_C::operator()(Argument* a)
+  union Sass_Value* To_C::operator()(Argument_Ptr a)
   { return a->value()->perform(this); }
 
   // not strictly necessary because of the fallback
-  union Sass_Value* To_C::operator()(Null* n)
+  union Sass_Value* To_C::operator()(Null_Ptr n)
   { return sass_make_null(); }
 
 };
diff --git a/libsass/src/to_c.hpp b/libsass/src/to_c.hpp
--- a/libsass/src/to_c.hpp
+++ b/libsass/src/to_c.hpp
@@ -8,31 +8,29 @@
 namespace Sass {
 
   class To_C : public Operation_CRTP<union Sass_Value*, To_C> {
-    // import all the class-specific methods and override as desired
-    using Operation<union Sass_Value*>::operator();
     // override this to define a catch-all
-    union Sass_Value* fallback_impl(AST_Node* n);
+    union Sass_Value* fallback_impl(AST_Node_Ptr n);
 
   public:
 
     To_C() { }
-    virtual ~To_C() { }
+    ~To_C() { }
 
-    union Sass_Value* operator()(Boolean*);
-    union Sass_Value* operator()(Number*);
-    union Sass_Value* operator()(Color*);
-    union Sass_Value* operator()(String_Constant*);
-    union Sass_Value* operator()(String_Quoted*);
-    union Sass_Value* operator()(Custom_Warning*);
-    union Sass_Value* operator()(Custom_Error*);
-    union Sass_Value* operator()(List*);
-    union Sass_Value* operator()(Map*);
-    union Sass_Value* operator()(Null*);
-    union Sass_Value* operator()(Arguments*);
-    union Sass_Value* operator()(Argument*);
+    union Sass_Value* operator()(Boolean_Ptr);
+    union Sass_Value* operator()(Number_Ptr);
+    union Sass_Value* operator()(Color_Ptr);
+    union Sass_Value* operator()(String_Constant_Ptr);
+    union Sass_Value* operator()(String_Quoted_Ptr);
+    union Sass_Value* operator()(Custom_Warning_Ptr);
+    union Sass_Value* operator()(Custom_Error_Ptr);
+    union Sass_Value* operator()(List_Ptr);
+    union Sass_Value* operator()(Map_Ptr);
+    union Sass_Value* operator()(Null_Ptr);
+    union Sass_Value* operator()(Arguments_Ptr);
+    union Sass_Value* operator()(Argument_Ptr);
 
     // dispatch to fallback implementation
-    union Sass_Value* fallback(AST_Node* x)
+    union Sass_Value* fallback(AST_Node_Ptr x)
     { return fallback_impl(x); }
   };
 
diff --git a/libsass/src/to_string.cpp b/libsass/src/to_string.cpp
deleted file mode 100644
--- a/libsass/src/to_string.cpp
+++ /dev/null
@@ -1,48 +0,0 @@
-#include <cmath>
-#include <sstream>
-#include <iomanip>
-#include <iostream>
-
-#include "ast.hpp"
-#include "inspect.hpp"
-#include "context.hpp"
-#include "to_string.hpp"
-
-namespace Sass {
-
-  To_String::To_String(Context* ctx, bool in_declaration, bool in_debug)
-  : ctx(ctx), in_declaration(in_declaration), in_debug(in_debug) { }
-  To_String::~To_String() { }
-
-  inline std::string To_String::fallback_impl(AST_Node* n)
-  {
-    Emitter emitter(ctx);
-    Inspect i(emitter);
-    i.in_declaration = in_declaration;
-    i.in_debug = in_debug;
-    if (n) n->perform(&i);
-    return i.get_buffer();
-  }
-
-  inline std::string To_String::operator()(String_Schema* s)
-  {
-    std::string acc("");
-    for (size_t i = 0, L = s->length(); i < L; ++i) {
-      acc += s->elements()[i]->perform(this);
-    }
-    return acc;
-  }
-
-  inline std::string To_String::operator()(String_Quoted* s)
-  {
-    return s->value();
-  }
-
-  inline std::string To_String::operator()(String_Constant* s)
-  {
-    return s->value();
-  }
-
-  inline std::string To_String::operator()(Null* n)
-  { return in_debug ? "null" : ""; }
-}
diff --git a/libsass/src/to_string.hpp b/libsass/src/to_string.hpp
deleted file mode 100644
--- a/libsass/src/to_string.hpp
+++ /dev/null
@@ -1,38 +0,0 @@
-#ifndef SASS_TO_STRING_H
-#define SASS_TO_STRING_H
-
-#include <string>
-
-#include "operation.hpp"
-
-namespace Sass {
-
-  class Context;
-  class Null;
-
-  class To_String : public Operation_CRTP<std::string, To_String> {
-    // import all the class-specific methods and override as desired
-    using Operation<std::string>::operator();
-    // override this to define a catch-all
-    std::string fallback_impl(AST_Node* n);
-
-    Context* ctx;
-    bool in_declaration;
-    bool in_debug;
-
-  public:
-
-    To_String(Context* ctx = 0, bool in_declaration = true, bool in_debug = false);
-    virtual ~To_String();
-
-    std::string operator()(Null* n);
-    std::string operator()(String_Schema*);
-    std::string operator()(String_Quoted*);
-    std::string operator()(String_Constant*);
-
-    template <typename U>
-    std::string fallback(U n) { return fallback_impl(n); }
-  };
-}
-
-#endif
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
@@ -1,10 +1,10 @@
+#include "sass.hpp"
 #include "ast.hpp"
 #include "to_value.hpp"
-#include "to_string.hpp"
 
 namespace Sass {
 
-  Value* To_Value::fallback_impl(AST_Node* n)
+  Value_Ptr To_Value::fallback_impl(AST_Node_Ptr n)
   {
     // throw a runtime error if this happens
     // we want a well defined set of possible nodes
@@ -14,96 +14,94 @@
   }
 
   // Custom_Error is a valid value
-  Value* To_Value::operator()(Custom_Error* e)
+  Value_Ptr To_Value::operator()(Custom_Error_Ptr e)
   {
     return e;
   }
 
   // Custom_Warning is a valid value
-  Value* To_Value::operator()(Custom_Warning* w)
+  Value_Ptr To_Value::operator()(Custom_Warning_Ptr w)
   {
     return w;
   }
 
   // Boolean is a valid value
-  Value* To_Value::operator()(Boolean* b)
+  Value_Ptr To_Value::operator()(Boolean_Ptr b)
   {
     return b;
   }
 
   // Number is a valid value
-  Value* To_Value::operator()(Number* n)
+  Value_Ptr To_Value::operator()(Number_Ptr n)
   {
     return n;
   }
 
   // Color is a valid value
-  Value* To_Value::operator()(Color* c)
+  Value_Ptr To_Value::operator()(Color_Ptr c)
   {
     return c;
   }
 
   // String_Constant is a valid value
-  Value* To_Value::operator()(String_Constant* s)
+  Value_Ptr To_Value::operator()(String_Constant_Ptr s)
   {
     return s;
   }
 
   // String_Quoted is a valid value
-  Value* To_Value::operator()(String_Quoted* s)
+  Value_Ptr To_Value::operator()(String_Quoted_Ptr s)
   {
     return s;
   }
 
   // List is a valid value
-  Value* To_Value::operator()(List* l)
+  Value_Ptr To_Value::operator()(List_Ptr l)
   {
-    List* ll = SASS_MEMORY_NEW(mem, List,
+    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 << (*l)[i]->perform(this);
+      ll->append((*l)[i]->perform(this));
     }
-    return ll;
+    return ll.detach();
   }
 
   // Map is a valid value
-  Value* To_Value::operator()(Map* m)
+  Value_Ptr To_Value::operator()(Map_Ptr m)
   {
     return m;
   }
 
   // Null is a valid value
-  Value* To_Value::operator()(Null* n)
+  Value_Ptr To_Value::operator()(Null_Ptr n)
   {
     return n;
   }
 
   // Argument returns its value
-  Value* To_Value::operator()(Argument* arg)
+  Value_Ptr To_Value::operator()(Argument_Ptr arg)
   {
     if (!arg->name().empty()) return 0;
     return arg->value()->perform(this);
   }
 
   // Selector_List is converted to a string
-  Value* To_Value::operator()(Selector_List* s)
+  Value_Ptr To_Value::operator()(Selector_List_Ptr s)
   {
-    To_String to_string(&ctx);
-    return SASS_MEMORY_NEW(mem, String_Quoted,
+    return SASS_MEMORY_NEW(String_Quoted,
                            s->pstate(),
-                           s->perform(&to_string));
+                           s->to_string(ctx.c_options));
   }
 
   // Binary_Expression is converted to a string
-  Value* To_Value::operator()(Binary_Expression* s)
+  Value_Ptr To_Value::operator()(Binary_Expression_Ptr s)
   {
-    To_String to_string(&ctx);
-    return SASS_MEMORY_NEW(mem, String_Quoted,
+    return SASS_MEMORY_NEW(String_Quoted,
                            s->pstate(),
-                           s->perform(&to_string));
+                           s->to_string(ctx.c_options));
   }
 
 };
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
@@ -7,42 +7,41 @@
 
 namespace Sass {
 
-  class To_Value : public Operation_CRTP<Value*, To_Value> {
+  class To_Value : public Operation_CRTP<Value_Ptr, To_Value> {
 
-    Value* fallback_impl(AST_Node* n);
+    Value_Ptr fallback_impl(AST_Node_Ptr n);
 
   private:
 
     Context& ctx;
-    Memory_Manager& mem;
 
   public:
 
-    To_Value(Context& ctx, Memory_Manager& mem)
-    : ctx(ctx), mem(mem)
+    To_Value(Context& ctx)
+    : ctx(ctx)
     { }
-    virtual ~To_Value() { }
-    using Operation<Value*>::operator();
+    ~To_Value() { }
+    using Operation<Value_Ptr>::operator();
 
-    Value* operator()(Argument*);
-    Value* operator()(Boolean*);
-    Value* operator()(Number*);
-    Value* operator()(Color*);
-    Value* operator()(String_Constant*);
-    Value* operator()(String_Quoted*);
-    Value* operator()(Custom_Warning*);
-    Value* operator()(Custom_Error*);
-    Value* operator()(List*);
-    Value* operator()(Map*);
-    Value* operator()(Null*);
+    Value_Ptr operator()(Argument_Ptr);
+    Value_Ptr operator()(Boolean_Ptr);
+    Value_Ptr operator()(Number_Ptr);
+    Value_Ptr operator()(Color_Ptr);
+    Value_Ptr operator()(String_Constant_Ptr);
+    Value_Ptr operator()(String_Quoted_Ptr);
+    Value_Ptr operator()(Custom_Warning_Ptr);
+    Value_Ptr operator()(Custom_Error_Ptr);
+    Value_Ptr operator()(List_Ptr);
+    Value_Ptr operator()(Map_Ptr);
+    Value_Ptr operator()(Null_Ptr);
 
     // convert to string via `To_String`
-    Value* operator()(Selector_List*);
-    Value* operator()(Binary_Expression*);
+    Value_Ptr operator()(Selector_List_Ptr);
+    Value_Ptr operator()(Binary_Expression_Ptr);
 
     // fallback throws error
     template <typename U>
-    Value* fallback(U x) { return fallback_impl(x); }
+    Value_Ptr fallback(U x) { return fallback_impl(x); }
   };
 
 }
diff --git a/libsass/src/units.cpp b/libsass/src/units.cpp
--- a/libsass/src/units.cpp
+++ b/libsass/src/units.cpp
@@ -1,10 +1,7 @@
+#include "sass.hpp"
 #include <stdexcept>
 #include "units.hpp"
 
-#ifdef IN
-#undef IN
-#endif
-
 namespace Sass {
 
   /* the conversion matrix can be readed the following way */
@@ -47,93 +44,133 @@
   const double resolution_conversion_factors[3][3] =
   {
              /*  dpi        dpcm       dppx     */
-    /* dpi  */ { 1,         2.54,      96       },
-    /* dpcm */ { 1/2.54,    1,         96/2.54  },
-    /* dppx */ { 1/96.0,    2.54/96,   1        }
+    /* dpi  */ { 1,         1/2.54,    1/96.0   },
+    /* dpcm */ { 2.54,      1,         2.54/96  },
+    /* dppx */ { 96,        96/2.54,   1        }
   };
 
-  SassUnitType get_unit_type(SassUnit unit)
+  UnitClass get_unit_type(UnitType unit)
   {
     switch (unit & 0xFF00)
     {
-      case SassUnitType::LENGTH:      return SassUnitType::LENGTH; break;
-      case SassUnitType::ANGLE:       return SassUnitType::ANGLE; break;
-      case SassUnitType::TIME:        return SassUnitType::TIME; break;
-      case SassUnitType::FREQUENCY:   return SassUnitType::FREQUENCY; break;
-      case SassUnitType::RESOLUTION:  return SassUnitType::RESOLUTION; break;
-      default:                        return SassUnitType::INCOMMENSURABLE; break;
+      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;
     }
   };
 
-  SassUnit string_to_unit(const std::string& s)
+  std::string get_unit_class(UnitType unit)
   {
+    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;
+    }
+  };
+
+  UnitType string_to_unit(const std::string& s)
+  {
     // size units
-    if      (s == "px")   return SassUnit::PX;
-    else if (s == "pt")   return SassUnit::PT;
-    else if (s == "pc")   return SassUnit::PC;
-    else if (s == "mm")   return SassUnit::MM;
-    else if (s == "cm")   return SassUnit::CM;
-    else if (s == "in")   return SassUnit::IN;
+    if      (s == "px")   return UnitType::PX;
+    else if (s == "pt")   return UnitType::PT;
+    else if (s == "pc")   return UnitType::PC;
+    else if (s == "mm")   return UnitType::MM;
+    else if (s == "cm")   return UnitType::CM;
+    else if (s == "in")   return UnitType::IN;
     // angle units
-    else if (s == "deg")  return SassUnit::DEG;
-    else if (s == "grad") return SassUnit::GRAD;
-    else if (s == "rad")  return SassUnit::RAD;
-    else if (s == "turn") return SassUnit::TURN;
+    else if (s == "deg")  return UnitType::DEG;
+    else if (s == "grad") return UnitType::GRAD;
+    else if (s == "rad")  return UnitType::RAD;
+    else if (s == "turn") return UnitType::TURN;
     // time units
-    else if (s == "s")    return SassUnit::SEC;
-    else if (s == "ms")   return SassUnit::MSEC;
+    else if (s == "s")    return UnitType::SEC;
+    else if (s == "ms")   return UnitType::MSEC;
     // frequency units
-    else if (s == "Hz")   return SassUnit::HERTZ;
-    else if (s == "kHz")  return SassUnit::KHERTZ;
+    else if (s == "Hz")   return UnitType::HERTZ;
+    else if (s == "kHz")  return UnitType::KHERTZ;
     // resolutions units
-    else if (s == "dpi")  return SassUnit::DPI;
-    else if (s == "dpcm") return SassUnit::DPCM;
-    else if (s == "dppx") return SassUnit::DPPX;
+    else if (s == "dpi")  return UnitType::DPI;
+    else if (s == "dpcm") return UnitType::DPCM;
+    else if (s == "dppx") return UnitType::DPPX;
     // for unknown units
-    else return SassUnit::UNKNOWN;
+    else return UnitType::UNKNOWN;
   }
 
-  const char* unit_to_string(SassUnit unit)
+  const char* unit_to_string(UnitType unit)
   {
     switch (unit) {
       // size units
-      case SassUnit::PX:      return "px"; break;
-      case SassUnit::PT:      return "pt"; break;
-      case SassUnit::PC:      return "pc"; break;
-      case SassUnit::MM:      return "mm"; break;
-      case SassUnit::CM:      return "cm"; break;
-      case SassUnit::IN:      return "in"; break;
+      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;
       // angle units
-      case SassUnit::DEG:     return "deg"; break;
-      case SassUnit::GRAD:    return "grad"; break;
-      case SassUnit::RAD:     return "rad"; break;
-      case SassUnit::TURN:    return "turn"; break;
+      case UnitType::DEG:     return "deg"; break;
+      case UnitType::GRAD:    return "grad"; break;
+      case UnitType::RAD:     return "rad"; break;
+      case UnitType::TURN:    return "turn"; break;
       // time units
-      case SassUnit::SEC:     return "s"; break;
-      case SassUnit::MSEC:    return "ms"; break;
+      case UnitType::SEC:     return "s"; break;
+      case UnitType::MSEC:    return "ms"; break;
       // frequency units
-      case SassUnit::HERTZ:   return "Hz"; break;
-      case SassUnit::KHERTZ:  return "kHz"; break;
+      case UnitType::HERTZ:   return "Hz"; break;
+      case UnitType::KHERTZ:  return "kHz"; break;
       // resolutions units
-      case SassUnit::DPI:     return "dpi"; break;
-      case SassUnit::DPCM:    return "dpcm"; break;
-      case SassUnit::DPPX:    return "dppx"; break;
+      case UnitType::DPI:     return "dpi"; break;
+      case UnitType::DPCM:    return "dpcm"; break;
+      case UnitType::DPPX:    return "dppx"; break;
       // for unknown units
       default:                return ""; break;
     }
   }
 
+  std::string unit_to_class(const std::string& s)
+  {
+    if      (s == "px")   return "LENGTH";
+    else if (s == "pt")   return "LENGTH";
+    else if (s == "pc")   return "LENGTH";
+    else if (s == "mm")   return "LENGTH";
+    else if (s == "cm")   return "LENGTH";
+    else if (s == "in")   return "LENGTH";
+    // angle units
+    else if (s == "deg")  return "ANGLE";
+    else if (s == "grad") return "ANGLE";
+    else if (s == "rad")  return "ANGLE";
+    else if (s == "turn") return "ANGLE";
+    // time units
+    else if (s == "s")    return "TIME";
+    else if (s == "ms")   return "TIME";
+    // frequency units
+    else if (s == "Hz")   return "FREQUENCY";
+    else if (s == "kHz")  return "FREQUENCY";
+    // resolutions units
+    else if (s == "dpi")  return "RESOLUTION";
+    else if (s == "dpcm") return "RESOLUTION";
+    else if (s == "dppx") return "RESOLUTION";
+    // for unknown units
+    return "CUSTOM:" + s;
+  }
+
   // throws incompatibleUnits exceptions
   double conversion_factor(const std::string& s1, const std::string& s2, bool strict)
   {
     // assert for same units
     if (s1 == s2) return 1;
     // get unit enum from string
-    SassUnit u1 = string_to_unit(s1);
-    SassUnit u2 = string_to_unit(s2);
+    UnitType u1 = string_to_unit(s1);
+    UnitType u2 = string_to_unit(s2);
     // query unit group types
-    SassUnitType t1 = get_unit_type(u1);
-    SassUnitType t2 = get_unit_type(u2);
+    UnitClass t1 = get_unit_type(u1);
+    UnitClass t2 = get_unit_type(u2);
     // get absolute offset
     // used for array acces
     size_t i1 = u1 - t1;
@@ -144,17 +181,17 @@
     // only process known units
     if (u1 != UNKNOWN && u2 != UNKNOWN) {
       switch (t1) {
-        case SassUnitType::LENGTH:              return size_conversion_factors[i1][i2]; break;
-        case SassUnitType::ANGLE:             return angle_conversion_factors[i1][i2]; break;
-        case SassUnitType::TIME:              return time_conversion_factors[i1][i2]; break;
-        case SassUnitType::FREQUENCY:         return frequency_conversion_factors[i1][i2]; break;
-        case SassUnitType::RESOLUTION:        return resolution_conversion_factors[i1][i2]; break;
+        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 SassUnitType::INCOMMENSURABLE:   return 0; break;
+        case UnitClass::INCOMMENSURABLE:   return 0; break;
       }
     }
     // fallback
-    return 1;
+    return 0;
   }
 
 }
diff --git a/libsass/src/units.hpp b/libsass/src/units.hpp
--- a/libsass/src/units.hpp
+++ b/libsass/src/units.hpp
@@ -7,9 +7,9 @@
 
 namespace Sass {
 
-  const double PI = acos(-1);
+  const double PI = std::acos(-1);
 
-  enum SassUnitType {
+  enum UnitClass {
     LENGTH = 0x000,
     ANGLE = 0x100,
     TIME = 0x200,
@@ -18,10 +18,10 @@
     INCOMMENSURABLE = 0x500
   };
 
-  enum SassUnit {
+  enum UnitType {
 
     // size units
-    IN = SassUnitType::LENGTH,
+    IN = UnitClass::LENGTH,
     CM,
     PC,
     MM,
@@ -58,9 +58,11 @@
   extern const double frequency_conversion_factors[2][2];
   extern const double resolution_conversion_factors[3][3];
 
-  enum SassUnit string_to_unit(const std::string&);
-  const char* unit_to_string(SassUnit unit);
-  enum SassUnitType get_unit_type(SassUnit 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);
 
@@ -68,14 +70,16 @@
   {
     public:
       const char* msg;
-      incompatibleUnits(SassUnit a, SassUnit b)
+      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) << "'";
-        msg = ss.str().c_str();
+        // hold on to string on stack!
+        std::string str(ss.str());
+        msg = str.c_str();
       }
       virtual const char* what() const throw()
       {
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
@@ -32,13 +32,13 @@
 
 namespace utf8
 {
-    namespace unchecked 
+    namespace unchecked
     {
         template <typename octet_iterator>
         octet_iterator append(uint32_t cp, octet_iterator result)
         {
             if (cp < 0x80)                        // one octet
-                *(result++) = static_cast<uint8_t>(cp);  
+                *(result++) = static_cast<uint8_t>(cp);
             else if (cp < 0x800) {                // two octets
                 *(result++) = static_cast<uint8_t>((cp >> 6)          | 0xc0);
                 *(result++) = static_cast<uint8_t>((cp & 0x3f)        | 0x80);
@@ -70,28 +70,28 @@
                     cp = ((cp << 6) & 0x7ff) + ((*it) & 0x3f);
                     break;
                 case 3:
-                    ++it; 
+                    ++it;
                     cp = ((cp << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff);
                     ++it;
                     cp += (*it) & 0x3f;
                     break;
                 case 4:
                     ++it;
-                    cp = ((cp << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff);                
+                    cp = ((cp << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff);
                     ++it;
                     cp += (utf8::internal::mask8(*it) << 6) & 0xfff;
                     ++it;
-                    cp += (*it) & 0x3f; 
+                    cp += (*it) & 0x3f;
                     break;
             }
             ++it;
-            return cp;        
+            return cp;
         }
 
         template <typename octet_iterator>
         uint32_t peek_next(octet_iterator it)
         {
-            return utf8::unchecked::next(it);    
+            return utf8::unchecked::next(it);
         }
 
         template <typename octet_iterator>
@@ -121,14 +121,14 @@
         distance (octet_iterator first, octet_iterator last)
         {
             typename std::iterator_traits<octet_iterator>::difference_type dist;
-            for (dist = 0; first < last; ++dist) 
+            for (dist = 0; first < last; ++dist)
                 utf8::unchecked::next(first);
             return dist;
         }
 
         template <typename u16bit_iterator, typename octet_iterator>
         octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result)
-        {       
+        {
             while (start != end) {
                 uint32_t cp = utf8::internal::mask16(*start++);
             // Take care of surrogate pairs first
@@ -138,7 +138,7 @@
                 }
                 result = utf8::unchecked::append(cp, result);
             }
-            return result;         
+            return result;
         }
 
         template <typename u16bit_iterator, typename octet_iterator>
@@ -176,7 +176,7 @@
 
         // The iterator class
         template <typename octet_iterator>
-          class iterator : public std::iterator <std::bidirectional_iterator_tag, uint32_t> { 
+          class iterator : public std::iterator <std::bidirectional_iterator_tag, uint32_t> {
             octet_iterator it;
             public:
             iterator () {}
@@ -188,15 +188,15 @@
                 octet_iterator temp = it;
                 return utf8::unchecked::next(temp);
             }
-            bool operator == (const iterator& rhs) const 
-            { 
+            bool operator == (const iterator& rhs) const
+            {
                 return (it == rhs.it);
             }
             bool operator != (const iterator& rhs) const
             {
                 return !(operator == (rhs));
             }
-            iterator& operator ++ () 
+            iterator& operator ++ ()
             {
                 ::std::advance(it, utf8::internal::sequence_length(it));
                 return *this;
@@ -206,7 +206,7 @@
                 iterator temp = *this;
                 ::std::advance(it, utf8::internal::sequence_length(it));
                 return temp;
-            }  
+            }
             iterator& operator -- ()
             {
                 utf8::unchecked::prior(it);
@@ -221,7 +221,7 @@
           }; // class iterator
 
     } // namespace utf8::unchecked
-} // namespace utf8 
+} // namespace utf8
 
 
 #endif // header guard
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
@@ -1,3 +1,4 @@
+#include "sass.hpp"
 #include <string>
 #include <vector>
 #include <cstdlib>
@@ -68,6 +69,8 @@
       }
     }
 
+    #ifdef _WIN32
+
     // utf16 functions
     using std::wstring;
 
@@ -92,6 +95,8 @@
                      back_inserter(utf16));
       return utf16;
     }
+
+    #endif
 
   }
 }
diff --git a/libsass/src/util.cpp b/libsass/src/util.cpp
--- a/libsass/src/util.cpp
+++ b/libsass/src/util.cpp
@@ -1,3 +1,4 @@
+#include "sass.hpp"
 #include "sass.h"
 #include "ast.hpp"
 #include "util.hpp"
@@ -11,38 +12,17 @@
 
 namespace Sass {
 
-  #define out_of_memory() do {            \
-      std::cerr << "Out of memory.\n";    \
-      exit(EXIT_FAILURE);                 \
-    } while (0)
-
-  double round(double val)
+  double round(double val, size_t precision)
   {
+    // 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);
     // work around some compiler issue
     // cygwin has it not defined in std
     using namespace std;
-
-    // This was later repatched in 3.4.20
-    // which is as yet unreleased.
-    // https://github.com/sass/sass/commit/4e3e1d5684cc29073a507578fc977434ff488c93
-    if (fmod(val, 1) - 0.5 > -0.00001) return std::ceil(val);
     return ::round(val);
-
-    // Use this version once sass-spec is at 3.4.20
-    // if (fmod(val, 1) - 0.5 > -0.00001) return ::round(val);
-    // return value > 0 ? std::ceil(val) : std::floor(val);
   }
 
-  /* Sadly, sass_strdup is not portable. */
-  char *sass_strdup(const char *str)
-  {
-    char *ret = (char*) malloc(strlen(str) + 1);
-    if (ret == NULL)
-      out_of_memory();
-    strcpy(ret, str);
-    return ret;
-  }
-
   /* Locale unspecific atof function. */
   double sass_atof(const char *str)
   {
@@ -55,7 +35,7 @@
       if(found != NULL){
         // substitution is required. perform the substitution on a copy
         // of the string. This is slower but it is thread safe.
-        char *copy = sass_strdup(str);
+        char *copy = sass_copy_c_string(str);
         *(copy + (found - str)) = separator;
         double res = atof(copy);
         free(copy);
@@ -104,94 +84,6 @@
     return *array = arr;
   }
 
-  std::string string_eval_escapes(const std::string& s)
-  {
-
-    std::string out("");
-    bool esc = false;
-    for (size_t i = 0, L = s.length(); i < L; ++i) {
-      if(s[i] == '\\' && esc == false) {
-        esc = true;
-
-        // escape length
-        size_t len = 1;
-
-        // parse as many sequence chars as possible
-        // ToDo: Check if ruby aborts after possible max
-        while (i + len < L && s[i + len] && isxdigit(s[i + len])) ++ len;
-
-        // hex string?
-        if (len > 1) {
-
-          // convert the extracted hex string to code point value
-          // ToDo: Maybe we could do this without creating a substring
-          uint32_t cp = strtol(s.substr (i + 1, len - 1).c_str(), NULL, 16);
-
-          if (cp == 0) cp = 0xFFFD;
-
-          // assert invalid code points
-          if (cp >= 1) {
-
-            // use a very simple approach to convert via utf8 lib
-            // maybe there is a more elegant way; maybe we shoud
-            // convert the whole output from string to a stream!?
-            // allocate memory for utf8 char and convert to utf8
-            unsigned char u[5] = {0,0,0,0,0}; utf8::append(cp, u);
-            for(size_t m = 0; u[m] && m < 5; m++) out.push_back(u[m]);
-
-            // skip some more chars?
-            i += len - 1; esc = false;
-            if (cp == 10) out += ' ';
-
-          }
-
-        }
-
-      }
-      else {
-        out += s[i];
-        esc = false;
-      }
-    }
-    return out;
-
-  }
-
-  // double escape every escape sequences
-  // escape unescaped quotes and backslashes
-  std::string string_escape(const std::string& str)
-  {
-    std::string out("");
-    for (auto i : str) {
-      // escape some characters
-      if (i == '"') out += '\\';
-      if (i == '\'') out += '\\';
-      if (i == '\\') out += '\\';
-      out += i;
-    }
-    return out;
-  }
-
-  // unescape every escape sequence
-  // only removes unescaped backslashes
-  std::string string_unescape(const std::string& str)
-  {
-    std::string out("");
-    bool esc = false;
-    for (auto i : str) {
-      if (esc || i != '\\') {
-        esc = false;
-        out += i;
-      } else {
-        esc = true;
-      }
-    }
-    // open escape sequence at end
-    // maybe it should thow an error
-    if (esc) { out += '\\'; }
-    return out;
-  }
-
   // read css string (handle multiline DELIM)
   std::string read_css_string(const std::string& str)
   {
@@ -211,29 +103,10 @@
       }
       out.push_back(i);
     }
-    if (esc) out += '\\';
-    return out;
-  }
-
-  // evacuate unescaped quoted
-  // leave everything else untouched
-  std::string evacuate_quotes(const std::string& str)
-  {
-    std::string out("");
-    bool esc = false;
-    for (auto i : str) {
-      if (!esc) {
-        // ignore next character
-        if (i == '\\') esc = true;
-        // evacuate unescaped quotes
-        else if (i == '"') out += '\\';
-        else if (i == '\'') out += '\\';
-      }
-      // get escaped char now
-      else { esc = false; }
-      // remove nothing
-      out += i;
-    }
+    // happens when parsing does not correctly skip
+    // over escaped sequences for ie. interpolations
+    // one example: foo\#{interpolate}
+    // if (esc) out += '\\';
     return out;
   }
 
@@ -272,13 +145,20 @@
     return out;
   }
 
-  // bell character is replaces with space
+  // bell characters are replaced with spaces
+  void newline_to_space(std::string& str)
+  {
+    std::replace(str.begin(), str.end(), '\n', ' ');
+  }
+
+  // bell characters are replaced with spaces
+  // also eats spaces after line-feeds (ltrim)
   std::string string_to_output(const std::string& str)
   {
     std::string out("");
     bool lf = false;
     for (auto i : str) {
-      if (i == 10) {
+      if (i == '\n') {
         out += ' ';
         lf = true;
       } else if (!(lf && isspace(i))) {
@@ -321,38 +201,6 @@
     else return text;
   }
 
-   std::string normalize_wspace(const std::string& str)
-  {
-    bool ws = false;
-    bool esc = false;
-    std::string text = "";
-    for(const char& i : str) {
-      if (!esc && i == '\\') {
-        esc = true;
-        ws = false;
-        text += i;
-      } else if (esc) {
-        esc = false;
-        ws = false;
-        text += i;
-      } else if (
-        i == ' ' ||
-        i == '\r' ||
-        i == '\n' ||
-        i == '	'
-      ) {
-        // only add one space
-        if (!ws) text += ' ';
-        ws = true;
-      } else {
-        ws = false;
-        text += i;
-      }
-    }
-    if (esc) text += '\\';
-    return text;
-  }
-
   // find best quote_mark by detecting if the string contains any single
   // or double quotes. When a single quote is found, we not we want a double
   // quote as quote_mark. Otherwise we check if the string cotains any double
@@ -373,7 +221,7 @@
     return quote_mark;
   }
 
-  std::string unquote(const std::string& s, char* qd, bool keep_utf8_sequences)
+  std::string unquote(const std::string& s, char* qd, bool keep_utf8_sequences, bool strict)
   {
 
     // not enough room for quotes
@@ -426,7 +274,7 @@
           // assert invalid code points
           if (cp == 0) cp = 0xFFFD;
           // replace bell character
-          // if (cp == 10) cp = 32;
+          // 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
@@ -451,6 +299,9 @@
       //   error("Unescaped delimiter in string to unquote found. [" + s + "]", ParserState("[UNQUOTE]"));
       // }
       else {
+        if (strict && !skipped) {
+          if (s[i] == q) return s;
+        }
         skipped = false;
         unq.push_back(s[i]);
       }
@@ -462,7 +313,7 @@
 
   }
 
-  std::string quote(const std::string& s, char q, bool keep_linefeed_whitespace)
+  std::string quote(const std::string& s, char q)
   {
 
     // autodetect with fallback to given quote
@@ -488,13 +339,27 @@
 
       int cp = utf8::next(it, end);
 
+      // in case of \r, check if the next in sequence
+      // is \n and then advance the iterator and skip \r
+      if (cp == '\r' && it < end && utf8::peek_next(it, end) == '\n') {
+        cp = utf8::next(it, end);
+      }
+
       if (cp == '\n') {
         quoted.push_back('\\');
         quoted.push_back('a');
         // we hope we can remove this flag once we figure out
         // why ruby sass has these different output behaviors
-        if (keep_linefeed_whitespace)
+        // gsub(/\n(?![a-fA-F0-9\s])/, "\\a").gsub("\n", "\\a ")
+        using namespace Prelexer;
+        if (alternatives <
+          Prelexer::char_range<'a', 'f'>,
+          Prelexer::char_range<'A', 'F'>,
+          Prelexer::char_range<'0', '9'>,
+          space
+        >(it) != NULL) {
           quoted.push_back(' ');
+        }
       } else if (cp < 127) {
         quoted.push_back((char) cp);
       } else {
@@ -573,30 +438,15 @@
       return normalized[0] == '.' ? normalized.insert(0, prefix) : normalized;
     }
 
-    // compress a color sixtuplet if possible
-    // input: "#CC9900" -> output: "#C90"
-    std::string normalize_sixtuplet(const std::string& col) {
-      if(
-        col.substr(1, 1) == col.substr(2, 1) &&
-        col.substr(3, 1) == col.substr(4, 1) &&
-        col.substr(5, 1) == col.substr(6, 1)
-      ) {
-        return std::string("#" + col.substr(1, 1)
-                          + col.substr(3, 1)
-                          + col.substr(5, 1));
-      } else {
-        return std::string(col);
-      }
-    }
-
-    bool isPrintable(Ruleset* r, Sass_Output_Style style) {
+    bool isPrintable(Ruleset_Ptr r, Sass_Output_Style style) {
       if (r == NULL) {
         return false;
       }
 
-      Block* b = r->block();
+      Block_Obj b = r->block();
 
-      bool hasSelectors = static_cast<Selector_List*>(r->selector())->length() > 0;
+      Selector_List_Ptr sl = SASS_MEMORY_CAST(Selector_List, r->selector());
+      bool hasSelectors = sl ? sl->length() > 0 : false;
 
       if (!hasSelectors) {
         return false;
@@ -605,25 +455,25 @@
       bool hasDeclarations = false;
       bool hasPrintableChildBlocks = false;
       for (size_t i = 0, L = b->length(); i < L; ++i) {
-        Statement* stm = (*b)[i];
-        if (dynamic_cast<At_Rule*>(stm)) {
+        Statement_Obj stm = b->at(i);
+        if (dynamic_cast<Directive_Ptr>(&stm)) {
           return true;
-        } else if (dynamic_cast<Has_Block*>(stm)) {
-          Block* pChildBlock = ((Has_Block*)stm)->block();
-          if (isPrintable(pChildBlock, style)) {
+        } else if (Declaration_Ptr d = dynamic_cast<Declaration_Ptr>(&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)) {
             hasPrintableChildBlocks = true;
           }
-        } else if (Comment* c = dynamic_cast<Comment*>(stm)) {
+        } else if (Comment_Ptr c = dynamic_cast<Comment_Ptr>(&stm)) {
           // keep for uncompressed
-          if (style != SASS_STYLE_COMPRESSED) {
+          if (style != COMPRESSED) {
             hasDeclarations = true;
           }
           // output style compressed
           if (c->is_important()) {
             hasDeclarations = c->is_important();
           }
-        } else if (Declaration* d = dynamic_cast<Declaration*>(stm)) {
-          return isPrintable(d, style);
         } else {
           hasDeclarations = true;
         }
@@ -636,49 +486,43 @@
       return false;
     }
 
-    bool isPrintable(String_Constant* s, Sass_Output_Style style)
+    bool isPrintable(String_Constant_Ptr s, Sass_Output_Style style)
     {
       return ! s->value().empty();
     }
 
-    bool isPrintable(String_Quoted* s, Sass_Output_Style style)
+    bool isPrintable(String_Quoted_Ptr s, Sass_Output_Style style)
     {
       return true;
     }
 
-    bool isPrintable(Declaration* d, Sass_Output_Style style)
+    bool isPrintable(Declaration_Ptr d, Sass_Output_Style style)
     {
-      Expression* val = d->value();
-      if (String_Quoted* sq = dynamic_cast<String_Quoted*>(val)) return isPrintable(sq, style);
-      if (String_Constant* sc = dynamic_cast<String_Constant*>(val)) return isPrintable(sc, style);
+      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);
       return true;
     }
 
-    bool isPrintable(Supports_Block* f, Sass_Output_Style style) {
+    bool isPrintable(Supports_Block_Ptr f, Sass_Output_Style style) {
       if (f == NULL) {
         return false;
       }
 
-      Block* b = f->block();
+      Block_Obj b = f->block();
 
-//      bool hasSelectors = f->selector() && static_cast<Selector_List*>(f->selector())->length() > 0;
+//      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* stm = (*b)[i];
-        if (!stm->is_hoistable()) {
-          // If a statement isn't hoistable, the selectors apply to it. If there are no selectors (a selector list of length 0),
-          // then those statements aren't considered printable. That means there was a placeholder that was removed. If the selector
-          // is NULL, then that means there was never a wrapping selector and it is printable (think of a top level media block with
-          // a declaration in it).
-        }
-        else if (typeid(*stm) == typeid(Declaration) || typeid(*stm) == typeid(At_Rule)) {
+        Statement_Obj stm = b->at(i);
+        if (dynamic_cast<Declaration_Ptr>(&stm) || dynamic_cast<Directive_Ptr>(&stm)) {
           hasDeclarations = true;
         }
-        else if (dynamic_cast<Has_Block*>(stm)) {
-          Block* pChildBlock = ((Has_Block*)stm)->block();
-          if (isPrintable(pChildBlock, style)) {
+        else if (dynamic_cast<Has_Block_Ptr>(&stm)) {
+          Block_Obj pChildBlock = ((Has_Block_Ptr)&stm)->block();
+          if (isPrintable(&pChildBlock, style)) {
             hasPrintableChildBlocks = true;
           }
         }
@@ -691,62 +535,95 @@
       return false;
     }
 
-    bool isPrintable(Media_Block* m, Sass_Output_Style style)
+    bool isPrintable(Media_Block_Ptr m, Sass_Output_Style style)
     {
       if (m == 0) return false;
-      Block* b = m->block();
+      Block_Obj b = m->block();
       if (b == 0) return false;
       for (size_t i = 0, L = b->length(); i < L; ++i) {
-        Statement* stm = (*b)[i];
-        if (typeid(*stm) == typeid(At_Rule)) return true;
-        if (typeid(*stm) == typeid(Declaration)) return true;
-        if (Has_Block* child = dynamic_cast<Has_Block*>(stm)) {
-          if (isPrintable(child->block(), style)) return true;
+        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 (isPrintable(c, style)) {
+            return true;
+          }
         }
+        else if (dynamic_cast<Ruleset_Ptr>(&stm)) {
+          Ruleset_Ptr r = (Ruleset_Ptr) &stm;
+          if (isPrintable(r, style)) {
+            return true;
+          }
+        }
+        else if (dynamic_cast<Supports_Block_Ptr>(&stm)) {
+          Supports_Block_Ptr f = (Supports_Block_Ptr) &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)) {
+            return true;
+          }
+        }
+        else if (dynamic_cast<Has_Block_Ptr>(&stm) && isPrintable(((Has_Block_Ptr)&stm)->block(), style)) {
+          return true;
+        }
       }
       return false;
     }
 
-    bool isPrintable(Block* b, Sass_Output_Style style) {
-      if (b == NULL) {
+    bool isPrintable(Comment_Ptr c, Sass_Output_Style style)
+    {
+      // keep for uncompressed
+      if (style != COMPRESSED) {
+        return true;
+      }
+      // output style compressed
+      if (c->is_important()) {
+        return true;
+      }
+      // not printable
+      return false;
+    };
+
+    bool isPrintable(Block_Obj b, Sass_Output_Style style) {
+      if (!b) {
         return false;
       }
 
       for (size_t i = 0, L = b->length(); i < L; ++i) {
-        Statement* stm = (*b)[i];
-        if (typeid(*stm) == typeid(Declaration) || typeid(*stm) == typeid(At_Rule)) {
+        Statement_Obj stm = b->at(i);
+        if (dynamic_cast<Declaration_Ptr>(&stm) || dynamic_cast<Directive_Ptr>(&stm)) {
           return true;
         }
-        else if (typeid(*stm) == typeid(Comment)) {
-          Comment* c = (Comment*) stm;
-          // keep for uncompressed
-          if (style != SASS_STYLE_COMPRESSED) {
-            return true;
-          }
-          // output style compressed
-          if (c->is_important()) {
+        else if (dynamic_cast<Comment_Ptr>(&stm)) {
+          Comment_Ptr c = (Comment_Ptr) &stm;
+          if (isPrintable(c, style)) {
             return true;
           }
         }
-        else if (typeid(*stm) == typeid(Ruleset)) {
-          Ruleset* r = (Ruleset*) stm;
+        else if (dynamic_cast<Ruleset_Ptr>(&stm)) {
+          Ruleset_Ptr r = (Ruleset_Ptr) &stm;
           if (isPrintable(r, style)) {
             return true;
           }
         }
-        else if (typeid(*stm) == typeid(Supports_Block)) {
-          Supports_Block* f = (Supports_Block*) stm;
+        else if (dynamic_cast<Supports_Block_Ptr>(&stm)) {
+          Supports_Block_Ptr f = (Supports_Block_Ptr) &stm;
           if (isPrintable(f, style)) {
             return true;
           }
         }
-        else if (typeid(*stm) == typeid(Media_Block)) {
-          Media_Block* m = (Media_Block*) stm;
+        else if (dynamic_cast<Media_Block_Ptr>(&stm)) {
+          Media_Block_Ptr m = (Media_Block_Ptr) &stm;
           if (isPrintable(m, style)) {
             return true;
           }
         }
-        else if (dynamic_cast<Has_Block*>(stm) && isPrintable(((Has_Block*)stm)->block(), style)) {
+        else if (dynamic_cast<Has_Block_Ptr>(&stm) && isPrintable(((Has_Block_Ptr)&stm)->block(), style)) {
           return true;
         }
       }
@@ -754,27 +631,9 @@
       return false;
     }
 
-    std::string vecJoin(const std::vector<std::string>& vec, const std::string& sep)
-    {
-      switch (vec.size())
-      {
-        case 0:
-            return std::string("");
-        case 1:
-            return vec[0];
-        default:
-            std::ostringstream os;
-            os << vec[0];
-            for (size_t i = 1; i < vec.size(); i++) {
-              os << sep << vec[i];
-            }
-            return os.str();
-      }
+    bool isAscii(const char chr) {
+      return unsigned(chr) < 128;
     }
-
-     bool isAscii(const char chr) {
-       return unsigned(chr) < 128;
-     }
 
   }
 }
diff --git a/libsass/src/util.hpp b/libsass/src/util.hpp
--- a/libsass/src/util.hpp
+++ b/libsass/src/util.hpp
@@ -4,6 +4,7 @@
 #include <vector>
 #include <string>
 #include <assert.h>
+#include "sass.hpp"
 #include "sass/base.h"
 #include "ast_fwd_decl.hpp"
 
@@ -11,24 +12,24 @@
 
 namespace Sass {
 
-  double round(double val);
-  char* sass_strdup(const char* str);
+  #define out_of_memory() do {            \
+      std::cerr << "Out of memory.\n";    \
+      exit(EXIT_FAILURE);                 \
+    } while (0)
+
+  double round(double val, size_t precision = 0);
   double sass_atof(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 string_escape(const std::string& str);
-  std::string string_unescape(const std::string& str);
-  std::string string_eval_escapes(const std::string& str);
   std::string read_css_string(const std::string& str);
-  std::string evacuate_quotes(const std::string& str);
   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 normalize_wspace(const std::string& str);
+  void newline_to_space(std::string& str);
 
-  std::string quote(const std::string&, char q = 0, bool keep_linefeed_whitespace = false);
-  std::string unquote(const std::string&, char* q = 0, bool keep_utf8_sequences = false);
+  std::string quote(const std::string&, char q = 0);
+  std::string unquote(const std::string&, char* q = 0, bool keep_utf8_sequences = false, bool strict = true);
   char detect_best_quotemark(const char* s, char qm = '"');
 
   bool is_hex_doublet(double n);
@@ -42,18 +43,15 @@
 
     std::string normalize_underscores(const std::string& str);
     std::string normalize_decimals(const std::string& str);
-    std::string normalize_sixtuplet(const std::string& col);
 
-    std::string vecJoin(const std::vector<std::string>& vec, const std::string& sep);
-    bool containsAnyPrintableStatements(Block* b);
-
-    bool isPrintable(Ruleset* r, Sass_Output_Style style = SASS_STYLE_NESTED);
-    bool isPrintable(Supports_Block* r, Sass_Output_Style style = SASS_STYLE_NESTED);
-    bool isPrintable(Media_Block* r, Sass_Output_Style style = SASS_STYLE_NESTED);
-    bool isPrintable(Block* b, Sass_Output_Style style = SASS_STYLE_NESTED);
-    bool isPrintable(String_Constant* s, Sass_Output_Style style = SASS_STYLE_NESTED);
-    bool isPrintable(String_Quoted* s, Sass_Output_Style style = SASS_STYLE_NESTED);
-    bool isPrintable(Declaration* d, Sass_Output_Style style = SASS_STYLE_NESTED);
+    bool isPrintable(Ruleset_Ptr r, Sass_Output_Style style = NESTED);
+    bool isPrintable(Supports_Block_Ptr r, Sass_Output_Style style = NESTED);
+    bool isPrintable(Media_Block_Ptr r, Sass_Output_Style style = NESTED);
+    bool isPrintable(Comment_Ptr b, Sass_Output_Style style = NESTED);
+    bool isPrintable(Block_Obj b, Sass_Output_Style style = NESTED);
+    bool isPrintable(String_Constant_Ptr s, Sass_Output_Style style = NESTED);
+    bool isPrintable(String_Quoted_Ptr s, Sass_Output_Style style = NESTED);
+    bool isPrintable(Declaration_Ptr d, Sass_Output_Style style = NESTED);
     bool isAscii(const char chr);
 
   }
diff --git a/libsass/src/values.cpp b/libsass/src/values.cpp
--- a/libsass/src/values.cpp
+++ b/libsass/src/values.cpp
@@ -1,3 +1,4 @@
+#include "sass.hpp"
 #include "sass.h"
 #include "values.hpp"
 
@@ -6,35 +7,36 @@
 namespace Sass {
 
   // convert value from C++ side to C-API
-  union Sass_Value* ast_node_to_sass_value (const Expression* val)
+  union Sass_Value* ast_node_to_sass_value (const Expression_Ptr val)
   {
     if (val->concrete_type() == Expression::NUMBER)
     {
-      const Number* res = dynamic_cast<const Number*>(val);
+      Number_Ptr_Const res = dynamic_cast<Number_Ptr_Const>(val);
       return sass_make_number(res->value(), res->unit().c_str());
     }
     else if (val->concrete_type() == Expression::COLOR)
     {
-      const Color* col = dynamic_cast<const Color*>(val);
+      Color_Ptr_Const col = dynamic_cast<Color_Ptr_Const>(val);
       return sass_make_color(col->r(), col->g(), col->b(), col->a());
     }
     else if (val->concrete_type() == Expression::LIST)
     {
-      const List* l = dynamic_cast<const List*>(val);
+      List_Ptr_Const l = dynamic_cast<List_Ptr_Const>(val);
       union Sass_Value* list = sass_make_list(l->size(), l->separator());
       for (size_t i = 0, L = l->length(); i < L; ++i) {
-        auto val = ast_node_to_sass_value((*l)[i]);
+        Expression_Obj obj = l->at(i);
+        auto val = ast_node_to_sass_value(&obj);
         sass_list_set_value(list, i, val);
       }
       return list;
     }
     else if (val->concrete_type() == Expression::MAP)
     {
-      const Map* m = dynamic_cast<const Map*>(val);
+      Map_Ptr_Const m = dynamic_cast<Map_Ptr_Const>(val);
       union Sass_Value* map = sass_make_map(m->length());
-      size_t i = 0; for (auto 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)));
+      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)));
         ++ i;
       }
       return map;
@@ -45,16 +47,16 @@
     }
     else if (val->concrete_type() == Expression::BOOLEAN)
     {
-      const Boolean* res = dynamic_cast<const Boolean*>(val);
+      Boolean_Ptr_Const res = dynamic_cast<Boolean_Ptr_Const>(val);
       return sass_make_boolean(res->value());
     }
     else if (val->concrete_type() == Expression::STRING)
     {
-      if (const String_Quoted* qstr = dynamic_cast<const String_Quoted*>(val))
+      if (String_Quoted_Ptr_Const qstr = dynamic_cast<String_Quoted_Ptr_Const>(val))
       {
         return sass_make_qstring(qstr->value().c_str());
       }
-      else if (const String_Constant* cstr = dynamic_cast<const String_Constant*>(val))
+      else if (String_Constant_Ptr_Const cstr = dynamic_cast<String_Constant_Ptr_Const>(val))
       {
         return sass_make_string(cstr->value().c_str());
       }
@@ -63,22 +65,22 @@
   }
 
   // convert value from C-API to C++ side
-  Value* sass_value_to_ast_node (Memory_Manager& mem, const union Sass_Value* val)
+  Value_Ptr sass_value_to_ast_node (const union Sass_Value* val)
   {
     switch (sass_value_get_tag(val)) {
       case SASS_NUMBER:
-        return SASS_MEMORY_NEW(mem, Number,
+        return SASS_MEMORY_NEW(Number,
                                ParserState("[C-VALUE]"),
                                sass_number_get_value(val),
                                sass_number_get_unit(val));
       break;
       case SASS_BOOLEAN:
-        return SASS_MEMORY_NEW(mem, Boolean,
+        return SASS_MEMORY_NEW(Boolean,
                                ParserState("[C-VALUE]"),
                                sass_boolean_get_value(val));
       break;
       case SASS_COLOR:
-        return SASS_MEMORY_NEW(mem, Color,
+        return SASS_MEMORY_NEW(Color,
                                ParserState("[C-VALUE]"),
                                sass_color_get_r(val),
                                sass_color_get_g(val),
@@ -87,46 +89,46 @@
       break;
       case SASS_STRING:
         if (sass_string_is_quoted(val)) {
-          return SASS_MEMORY_NEW(mem, String_Quoted,
+          return SASS_MEMORY_NEW(String_Quoted,
                                  ParserState("[C-VALUE]"),
                                  sass_string_get_value(val));
         } else {
-          return SASS_MEMORY_NEW(mem, String_Constant,
+          return SASS_MEMORY_NEW(String_Constant,
                                  ParserState("[C-VALUE]"),
                                  sass_string_get_value(val));
         }
       break;
       case SASS_LIST: {
-        List* l = SASS_MEMORY_NEW(mem, List,
+        List_Ptr l = SASS_MEMORY_NEW(List,
                                   ParserState("[C-VALUE]"),
                                   sass_list_get_length(val),
                                   sass_list_get_separator(val));
         for (size_t i = 0, L = sass_list_get_length(val); i < L; ++i) {
-          *l << sass_value_to_ast_node(mem, sass_list_get_value(val, i));
+          l->append(sass_value_to_ast_node(sass_list_get_value(val, i)));
         }
         return l;
       }
       break;
       case SASS_MAP: {
-        Map* m = SASS_MEMORY_NEW(mem, Map, ParserState("[C-VALUE]"));
+        Map_Ptr m = SASS_MEMORY_NEW(Map, ParserState("[C-VALUE]"));
         for (size_t i = 0, L = sass_map_get_length(val); i < L; ++i) {
           *m << std::make_pair(
-            sass_value_to_ast_node(mem, sass_map_get_key(val, i)),
-            sass_value_to_ast_node(mem, sass_map_get_value(val, i)));
+            sass_value_to_ast_node(sass_map_get_key(val, i)),
+            sass_value_to_ast_node(sass_map_get_value(val, i)));
         }
         return m;
       }
       break;
       case SASS_NULL:
-        return SASS_MEMORY_NEW(mem, Null, ParserState("[C-VALUE]"));
+        return SASS_MEMORY_NEW(Null, ParserState("[C-VALUE]"));
       break;
       case SASS_ERROR:
-        return SASS_MEMORY_NEW(mem, Custom_Error,
+        return SASS_MEMORY_NEW(Custom_Error,
                                ParserState("[C-VALUE]"),
                                sass_error_get_message(val));
       break;
       case SASS_WARNING:
-        return SASS_MEMORY_NEW(mem, Custom_Warning,
+        return SASS_MEMORY_NEW(Custom_Warning,
                                ParserState("[C-VALUE]"),
                                sass_warning_get_message(val));
       break;
diff --git a/libsass/src/values.hpp b/libsass/src/values.hpp
--- a/libsass/src/values.hpp
+++ b/libsass/src/values.hpp
@@ -5,8 +5,8 @@
 
 namespace Sass {
 
-  union Sass_Value* ast_node_to_sass_value (const Expression* val);
-  Value* sass_value_to_ast_node (Memory_Manager& mem, const union Sass_Value* val);
+  union Sass_Value* ast_node_to_sass_value (const Expression_Ptr val);
+  Value_Ptr sass_value_to_ast_node (const union Sass_Value* val);
 
 }
 #endif
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.3.2"
+        str `shouldBe` "3.4.3"
 #endif
 
     it "should support quoted strings" $ withCString "sample" $ \cstr -> do
