diff --git a/Bindings/Libsass.hs b/Bindings/Libsass.hs
--- a/Bindings/Libsass.hs
+++ b/Bindings/Libsass.hs
@@ -16,4 +16,4 @@
 import           Bindings.Libsass.Values    as Libsass
 import           Foreign.C.String
 
-foreign import ccall unsafe "sass.h" libsass_version :: CString
+foreign import ccall unsafe "sass/base.h" libsass_version :: CString
diff --git a/Bindings/Libsass/Context.hs b/Bindings/Libsass/Context.hs
--- a/Bindings/Libsass/Context.hs
+++ b/Bindings/Libsass/Context.hs
@@ -6,10 +6,10 @@
 import           Foreign.C.String
 import           Foreign.C.Types
 
-foreign import ccall unsafe "sass_context.h" sass_make_options
+foreign import ccall unsafe "sass/context.h" sass_make_options
     :: IO (Ptr SassOptions)
 
-foreign import ccall unsafe "sass_context.h" sass_make_file_context
+foreign import ccall unsafe "sass/context.h" sass_make_file_context
     :: CString
     -> IO (Ptr SassFileContext)
 
@@ -18,341 +18,341 @@
 --
 --   WARNING! The string that this function takes is released by the libsass
 --   during cleanup. You must not deallocate it.
-foreign import ccall unsafe "sass_context.h" sass_make_data_context
+foreign import ccall unsafe "sass/context.h" sass_make_data_context
     :: CString
     -> IO (Ptr SassDataContext)
 
-foreign import ccall safe "sass_context.h" sass_compile_file_context
+foreign import ccall safe "sass/context.h" sass_compile_file_context
     :: Ptr SassFileContext
     -> IO CInt
 
-foreign import ccall safe "sass_context.h" sass_compile_data_context
+foreign import ccall safe "sass/context.h" sass_compile_data_context
     :: Ptr SassDataContext
     -> IO CInt
 
-foreign import ccall unsafe "sass_context.h" sass_make_file_compiler
+foreign import ccall unsafe "sass/context.h" sass_make_file_compiler
     :: Ptr SassFileContext
     -> IO (Ptr SassCompiler)
 
-foreign import ccall unsafe "sass_context.h" sass_make_data_compiler
+foreign import ccall unsafe "sass/context.h" sass_make_data_compiler
     :: Ptr SassDataContext
     -> IO (Ptr SassCompiler)
 
-foreign import ccall safe "sass_context.h" sass_compiler_parse
+foreign import ccall safe "sass/context.h" sass_compiler_parse
     :: Ptr SassCompiler
     -> IO CInt
 
-foreign import ccall safe "sass_context.h" sass_compiler_execute
+foreign import ccall safe "sass/context.h" sass_compiler_execute
     :: Ptr SassCompiler
     -> IO CInt
 
-foreign import ccall unsafe "sass_context.h" sass_delete_compiler
+foreign import ccall unsafe "sass/context.h" sass_delete_compiler
     :: Ptr SassCompiler
     -> IO ()
 
-foreign import ccall unsafe "sass_context.h" sass_delete_file_context
+foreign import ccall unsafe "sass/context.h" sass_delete_file_context
     :: Ptr SassFileContext
     -> IO ()
 
-foreign import ccall unsafe "sass_context.h" sass_delete_data_context
+foreign import ccall unsafe "sass/context.h" sass_delete_data_context
     :: Ptr SassDataContext
     -> IO ()
 
-foreign import ccall unsafe "sass_context.h" sass_file_context_get_context
+foreign import ccall unsafe "sass/context.h" sass_file_context_get_context
     :: Ptr SassFileContext
     -> Ptr SassContext
 
-foreign import ccall unsafe "sass_context.h" sass_data_context_get_context
+foreign import ccall unsafe "sass/context.h" sass_data_context_get_context
     :: Ptr SassDataContext
     -> Ptr SassContext
 
-foreign import ccall unsafe "sass_context.h" sass_context_get_options
+foreign import ccall unsafe "sass/context.h" sass_context_get_options
     :: Ptr SassContext
     -> Ptr SassOptions
 
-foreign import ccall unsafe "sass_context.h" sass_file_context_get_options
+foreign import ccall unsafe "sass/context.h" sass_file_context_get_options
     :: Ptr SassFileContext
     -> Ptr SassOptions
 
-foreign import ccall unsafe "sass_context.h" sass_data_context_get_options
+foreign import ccall unsafe "sass/context.h" sass_data_context_get_options
     :: Ptr SassDataContext
     -> Ptr SassOptions
 
-foreign import ccall unsafe "sass_context.h" sass_file_context_set_options
+foreign import ccall unsafe "sass/context.h" sass_file_context_set_options
     :: Ptr SassFileContext
     -> Ptr SassOptions
     -> IO ()
 
-foreign import ccall unsafe "sass_context.h" sass_data_context_set_options
+foreign import ccall unsafe "sass/context.h" sass_data_context_set_options
     :: Ptr SassDataContext
     -> Ptr SassOptions
     -> IO ()
 
-foreign import ccall unsafe "sass_context.h" sass_option_get_precision
+foreign import ccall unsafe "sass/context.h" sass_option_get_precision
     :: Ptr SassOptions
     -> IO CInt
 
-foreign import ccall unsafe "sass_context.h" sass_option_get_output_style
+foreign import ccall unsafe "sass/context.h" sass_option_get_output_style
     :: Ptr SassOptions
     -> IO CInt -- ^ Returns 'SassOutputStyle'
 
-foreign import ccall unsafe "sass_context.h" sass_option_get_source_comments
+foreign import ccall unsafe "sass/context.h" sass_option_get_source_comments
     :: Ptr SassOptions
     -> IO Bool
 
-foreign import ccall unsafe "sass_context.h" sass_option_get_source_map_embed
+foreign import ccall unsafe "sass/context.h" sass_option_get_source_map_embed
     :: Ptr SassOptions
     -> IO Bool
 
-foreign import ccall unsafe "sass_context.h" sass_option_get_source_map_contents
+foreign import ccall unsafe "sass/context.h" sass_option_get_source_map_contents
     :: Ptr SassOptions
     -> IO Bool
 
-foreign import ccall unsafe "sass_context.h" sass_option_get_omit_source_map_url
+foreign import ccall unsafe "sass/context.h" sass_option_get_omit_source_map_url
     :: Ptr SassOptions
     -> IO Bool
 
-foreign import ccall unsafe "sass_context.h" sass_option_get_is_indented_syntax_src
+foreign import ccall unsafe "sass/context.h" sass_option_get_is_indented_syntax_src
     :: Ptr SassOptions
     -> IO Bool
 
-foreign import ccall unsafe "sass_context.h" sass_option_get_indent
+foreign import ccall unsafe "sass/context.h" sass_option_get_indent
     :: Ptr SassOptions
     -> IO CString
 
-foreign import ccall unsafe "sass_context.h" sass_option_get_linefeed
+foreign import ccall unsafe "sass/context.h" sass_option_get_linefeed
     :: Ptr SassOptions
     -> IO CString
 
-foreign import ccall unsafe "sass_context.h" sass_option_get_input_path
+foreign import ccall unsafe "sass/context.h" sass_option_get_input_path
     :: Ptr SassOptions
     -> IO CString
 
-foreign import ccall unsafe "sass_context.h" sass_option_get_output_path
+foreign import ccall unsafe "sass/context.h" sass_option_get_output_path
     :: Ptr SassOptions
     -> IO CString
 
-foreign import ccall unsafe "sass_context.h" sass_option_get_plugin_path
+foreign import ccall unsafe "sass/context.h" sass_option_get_plugin_path
     :: Ptr SassOptions
     -> IO CString
 
-foreign import ccall unsafe "sass_context.h" sass_option_get_include_path
+foreign import ccall unsafe "sass/context.h" sass_option_get_include_path
     :: Ptr SassOptions
     -> IO CString
 
-foreign import ccall unsafe "sass_context.h" sass_option_get_source_map_file
+foreign import ccall unsafe "sass/context.h" sass_option_get_source_map_file
     :: Ptr SassOptions
     -> IO CString
 
-foreign import ccall unsafe "sass_context.h" sass_option_get_source_map_root
+foreign import ccall unsafe "sass/context.h" sass_option_get_source_map_root
     :: Ptr SassOptions
     -> IO CString
 
-foreign import ccall unsafe "sass_context.h" sass_option_get_c_headers
+foreign import ccall unsafe "sass/context.h" sass_option_get_c_headers
      :: Ptr SassOptions
      -> IO SassImporterList
 
-foreign import ccall unsafe "sass_context.h" sass_option_get_c_importers
+foreign import ccall unsafe "sass/context.h" sass_option_get_c_importers
      :: Ptr SassOptions
      -> IO SassImporterList
 
-foreign import ccall unsafe "sass_context.h" sass_option_get_c_functions
+foreign import ccall unsafe "sass/context.h" sass_option_get_c_functions
      :: Ptr SassOptions
      -> IO SassFunctionList
 
-foreign import ccall unsafe "sass_context.h" sass_option_set_precision
+foreign import ccall unsafe "sass/context.h" sass_option_set_precision
     :: Ptr SassOptions
     -> CInt
     -> IO ()
 
-foreign import ccall unsafe "sass_context.h" sass_option_set_output_style
+foreign import ccall unsafe "sass/context.h" sass_option_set_output_style
     :: Ptr SassOptions
     -> CInt -- ^ 'SassOutputStyle'
     -> IO ()
 
-foreign import ccall unsafe "sass_context.h" sass_option_set_source_comments
+foreign import ccall unsafe "sass/context.h" sass_option_set_source_comments
     :: Ptr SassOptions
     -> Bool
     -> IO ()
 
-foreign import ccall unsafe "sass_context.h" sass_option_set_source_map_embed
+foreign import ccall unsafe "sass/context.h" sass_option_set_source_map_embed
     :: Ptr SassOptions
     -> Bool
     -> IO ()
 
-foreign import ccall unsafe "sass_context.h" sass_option_set_source_map_contents
+foreign import ccall unsafe "sass/context.h" sass_option_set_source_map_contents
     :: Ptr SassOptions
     -> Bool
     -> IO ()
 
-foreign import ccall unsafe "sass_context.h" sass_option_set_omit_source_map_url
+foreign import ccall unsafe "sass/context.h" sass_option_set_omit_source_map_url
     :: Ptr SassOptions
     -> Bool
     -> IO ()
 
-foreign import ccall unsafe "sass_context.h" sass_option_set_is_indented_syntax_src
+foreign import ccall unsafe "sass/context.h" sass_option_set_is_indented_syntax_src
     :: Ptr SassOptions
     -> Bool
     -> IO ()
 
-foreign import ccall unsafe "sass_context.h" sass_option_set_indent
+foreign import ccall unsafe "sass/context.h" sass_option_set_indent
     :: Ptr SassOptions
     -> CString
     -> IO ()
 
-foreign import ccall unsafe "sass_context.h" sass_option_set_linefeed
+foreign import ccall unsafe "sass/context.h" sass_option_set_linefeed
     :: Ptr SassOptions
     -> CString
     -> IO ()
 
-foreign import ccall unsafe "sass_context.h" sass_option_set_input_path
+foreign import ccall unsafe "sass/context.h" sass_option_set_input_path
     :: Ptr SassOptions
     -> CString
     -> IO ()
 
-foreign import ccall unsafe "sass_context.h" sass_option_set_output_path
+foreign import ccall unsafe "sass/context.h" sass_option_set_output_path
     :: Ptr SassOptions
     -> CString
     -> IO ()
 
-foreign import ccall unsafe "sass_context.h" sass_option_set_plugin_path
+foreign import ccall unsafe "sass/context.h" sass_option_set_plugin_path
     :: Ptr SassOptions
     -> CString
     -> IO ()
 
-foreign import ccall unsafe "sass_context.h" sass_option_set_include_path
+foreign import ccall unsafe "sass/context.h" sass_option_set_include_path
     :: Ptr SassOptions
     -> CString
     -> IO ()
 
-foreign import ccall unsafe "sass_context.h" sass_option_set_source_map_file
+foreign import ccall unsafe "sass/context.h" sass_option_set_source_map_file
     :: Ptr SassOptions
     -> CString
     -> IO ()
 
-foreign import ccall unsafe "sass_context.h" sass_option_set_source_map_root
+foreign import ccall unsafe "sass/context.h" sass_option_set_source_map_root
     :: Ptr SassOptions
     -> CString
     -> IO ()
 
-foreign import ccall unsafe "sass_context.h" sass_option_set_c_headers
+foreign import ccall unsafe "sass/context.h" sass_option_set_c_headers
     :: Ptr SassOptions
     -> SassImporterList
     -> IO ()
 
-foreign import ccall unsafe "sass_context.h" sass_option_set_c_importers
+foreign import ccall unsafe "sass/context.h" sass_option_set_c_importers
     :: Ptr SassOptions
     -> SassImporterList
     -> IO ()
 
-foreign import ccall unsafe "sass_context.h" sass_option_set_c_functions
+foreign import ccall unsafe "sass/context.h" sass_option_set_c_functions
     :: Ptr SassOptions
     -> SassFunctionList
     -> IO ()
 
-foreign import ccall unsafe "sass_context.h" sass_context_get_output_string
+foreign import ccall unsafe "sass/context.h" sass_context_get_output_string
     :: Ptr SassContext
     -> IO CString
 
-foreign import ccall unsafe "sass_context.h" sass_context_get_error_status
+foreign import ccall unsafe "sass/context.h" sass_context_get_error_status
     :: Ptr SassContext
     -> IO CInt
 
-foreign import ccall unsafe "sass_context.h" sass_context_get_error_json
+foreign import ccall unsafe "sass/context.h" sass_context_get_error_json
     :: Ptr SassContext
     -> IO CString
 
-foreign import ccall unsafe "sass_context.h" sass_context_get_error_text
+foreign import ccall unsafe "sass/context.h" sass_context_get_error_text
     :: Ptr SassContext
     -> IO CString
 
-foreign import ccall unsafe "sass_context.h" sass_context_get_error_message
+foreign import ccall unsafe "sass/context.h" sass_context_get_error_message
     :: Ptr SassContext
     -> IO CString
 
-foreign import ccall unsafe "sass_context.h" sass_context_get_error_file
+foreign import ccall unsafe "sass/context.h" sass_context_get_error_file
     :: Ptr SassContext
     -> IO CString
 
-foreign import ccall unsafe "sass_context.h" sass_context_get_error_src
+foreign import ccall unsafe "sass/context.h" sass_context_get_error_src
     :: Ptr SassContext
     -> IO CString
 
-foreign import ccall unsafe "sass_context.h" sass_context_get_error_line
+foreign import ccall unsafe "sass/context.h" sass_context_get_error_line
     :: Ptr SassContext
     -> IO CSize
 
-foreign import ccall unsafe "sass_context.h" sass_context_get_error_column
+foreign import ccall unsafe "sass/context.h" sass_context_get_error_column
     :: Ptr SassContext
     -> IO CSize
 
-foreign import ccall unsafe "sass_context.h" sass_context_get_source_map_string
+foreign import ccall unsafe "sass/context.h" sass_context_get_source_map_string
     :: Ptr SassContext
     -> IO CString
 
-foreign import ccall unsafe "sass_context.h" sass_context_get_included_files
+foreign import ccall unsafe "sass/context.h" sass_context_get_included_files
     :: Ptr SassContext
     -> IO (Ptr CString)
 
-foreign import ccall unsafe "sass_context.h" sass_context_get_included_files_size
+foreign import ccall unsafe "sass/context.h" sass_context_get_included_files_size
     :: Ptr SassContext
     -> IO CSize
 
-foreign import ccall unsafe "sass_context.h" sass_context_take_error_json
+foreign import ccall unsafe "sass/context.h" sass_context_take_error_json
     :: Ptr SassContext
     -> IO CString
 
-foreign import ccall unsafe "sass_context.h" sass_context_take_error_text
+foreign import ccall unsafe "sass/context.h" sass_context_take_error_text
     :: Ptr SassContext
     -> IO CString
 
-foreign import ccall unsafe "sass_context.h" sass_context_take_error_message
+foreign import ccall unsafe "sass/context.h" sass_context_take_error_message
     :: Ptr SassContext
     -> IO CString
 
-foreign import ccall unsafe "sass_context.h" sass_context_take_error_file
+foreign import ccall unsafe "sass/context.h" sass_context_take_error_file
     :: Ptr SassContext
     -> IO CString
 
-foreign import ccall unsafe "sass_context.h" sass_context_take_output_string
+foreign import ccall unsafe "sass/context.h" sass_context_take_output_string
     :: Ptr SassContext
     -> IO CString
 
-foreign import ccall unsafe "sass_context.h" sass_context_take_source_map_string
+foreign import ccall unsafe "sass/context.h" sass_context_take_source_map_string
     :: Ptr SassContext
     -> IO CString
 
-foreign import ccall unsafe "sass_context.h" sass_context_take_included_files
+foreign import ccall unsafe "sass/context.h" sass_context_take_included_files
     :: Ptr SassContext
     -> IO (Ptr CString)
 
-foreign import ccall unsafe "sass_context.h" sass_compiler_get_state
+foreign import ccall unsafe "sass/context.h" sass_compiler_get_state
     :: Ptr SassCompiler
     -> IO CInt -- ^ Retruns 'SassCompilerState'
 
-foreign import ccall unsafe "sass_context.h" sass_compiler_get_context
+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_import_stack_size
+foreign import ccall unsafe "sass/context.h" sass_compiler_get_import_stack_size
     :: Ptr SassCompiler
     -> IO CSize
 
-foreign import ccall unsafe "sass_context.h" sass_compiler_get_last_import
+foreign import ccall unsafe "sass/context.h" sass_compiler_get_last_import
     :: Ptr SassCompiler
     -> IO SassImportEntry
 
-foreign import ccall unsafe "sass_context.h" sass_compiler_get_import_entry
+foreign import ccall unsafe "sass/context.h" sass_compiler_get_import_entry
     :: Ptr SassCompiler
     -> CSize
     -> IO SassImportEntry
 
-foreign import ccall unsafe "sass_context.h" sass_option_push_plugin_path
+foreign import ccall unsafe "sass/context.h" sass_option_push_plugin_path
     :: Ptr SassOptions
     -> CString
     -> IO ()
 
-foreign import ccall unsafe "sass_context.h" sass_option_push_include_path
+foreign import ccall unsafe "sass/context.h" sass_option_push_include_path
     :: Ptr SassOptions
     -> CString
     -> IO ()
diff --git a/Bindings/Libsass/Functions.hs b/Bindings/Libsass/Functions.hs
--- a/Bindings/Libsass/Functions.hs
+++ b/Bindings/Libsass/Functions.hs
@@ -5,152 +5,150 @@
 import           Foreign
 import           Foreign.C
 
-foreign import ccall unsafe "sass_function.h" sass_make_importer_list
+foreign import ccall unsafe "sass/functions.h" sass_make_importer_list
     :: CSize
     -> IO SassImporterList
 
--- Libsass lacks implementation of these functions.
-
--- foreign import ccall unsafe "sass_function.h" sass_importer_get_list_entry
---     :: SassImporterList
---     -> CSize
---     -> IO SassImporterEntry
+foreign import ccall unsafe "sass/functions.h" sass_importer_get_list_entry
+    :: SassImporterList
+    -> CSize
+    -> IO SassImporterEntry
 
--- foreign import ccall unsafe "sass_function.h" sass_importer_set_list_entry
---     :: SassImporterList
---     -> CSize
---     -> SassImporterEntry
---     -> IO ()
+foreign import ccall unsafe "sass/functions.h" sass_importer_set_list_entry
+    :: SassImporterList
+    -> CSize
+    -> SassImporterEntry
+    -> IO ()
 
-foreign import ccall unsafe "sass_function.h" sass_make_importer
+foreign import ccall unsafe "sass/functions.h" sass_make_importer
     :: SassImporterFn
     -> CDouble
     -> Ptr ()
     -> IO SassImporterEntry
 
-foreign import ccall unsafe "sass_function.h" sass_importer_get_function
+foreign import ccall unsafe "sass/functions.h" sass_importer_get_function
     :: SassImporterEntry
     -> IO SassImporterFn
 
-foreign import ccall unsafe "sass_function.h" sass_importer_get_priority
+foreign import ccall unsafe "sass/functions.h" sass_importer_get_priority
     :: SassImporterEntry
     -> IO CDouble
-foreign import ccall unsafe "sass_function.h" sass_importer_get_cookie
+foreign import ccall unsafe "sass/functions.h" sass_importer_get_cookie
     :: SassImporterEntry
     -> IO (Ptr ())
 
-foreign import ccall unsafe "sass_function.h" sass_delete_importer
+foreign import ccall unsafe "sass/functions.h" sass_delete_importer
     :: SassImporterEntry
     -> IO ()
 
-foreign import ccall unsafe "sass_function.h" sass_make_import_list
+foreign import ccall unsafe "sass/functions.h" sass_make_import_list
     :: CSize
     -> IO SassImportList
 
-foreign import ccall unsafe "sass_function.h" sass_make_import_entry
+foreign import ccall unsafe "sass/functions.h" sass_make_import_entry
     :: CString
     -> CString
     -> CString
     -> IO SassImportEntry
 
-foreign import ccall unsafe "sass_function.h" sass_make_import
+foreign import ccall unsafe "sass/functions.h" sass_make_import
     :: CString
     -> CString
     -> CString
     -> CString
     -> IO SassImportEntry
 
-foreign import ccall unsafe "sass_function.h" sass_import_set_error
+foreign import ccall unsafe "sass/functions.h" sass_import_set_error
     :: SassImportEntry
     -> CString
     -> CSize
     -> CSize
     -> IO SassImportEntry
 
-foreign import ccall unsafe "sass_function.h" sass_import_set_list_entry
+foreign import ccall unsafe "sass/functions.h" sass_import_set_list_entry
     :: SassImportList
     -> CSize
     -> SassImportEntry
     -> IO ()
 
-foreign import ccall unsafe "sass_function.h" sass_import_get_list_entry
+foreign import ccall unsafe "sass/functions.h" sass_import_get_list_entry
     :: SassImportList
     -> CSize
     -> IO SassImportEntry
 
-foreign import ccall unsafe "sass_function.h" sass_import_get_path
+foreign import ccall unsafe "sass/functions.h" sass_import_get_imp_path
     :: SassImportEntry
     -> IO CString
 
-foreign import ccall unsafe "sass_function.h" sass_import_get_base
+foreign import ccall unsafe "sass/functions.h" sass_import_get_abs_path
     :: SassImportEntry
     -> IO CString
 
-foreign import ccall unsafe "sass_function.h" sass_import_get_source
+foreign import ccall unsafe "sass/functions.h" sass_import_get_source
     :: SassImportEntry
     -> IO CString
 
-foreign import ccall unsafe "sass_function.h" sass_import_get_srcmap
+foreign import ccall unsafe "sass/functions.h" sass_import_get_srcmap
     :: SassImportEntry
     -> IO CString
 
-foreign import ccall unsafe "sass_function.h" sass_import_take_source
+foreign import ccall unsafe "sass/functions.h" sass_import_take_source
     :: SassImportEntry
     -> IO CString
 
-foreign import ccall unsafe "sass_function.h" sass_import_take_srcmap
+foreign import ccall unsafe "sass/functions.h" sass_import_take_srcmap
     :: SassImportEntry
     -> IO CString
 
-foreign import ccall unsafe "sass_function.h" sass_import_get_error_line
+foreign import ccall unsafe "sass/functions.h" sass_import_get_error_line
     :: SassImportEntry
     -> IO CSize
 
-foreign import ccall unsafe "sass_function.h" sass_import_get_error_column
+foreign import ccall unsafe "sass/functions.h" sass_import_get_error_column
     :: SassImportEntry
     -> IO CSize
 
-foreign import ccall unsafe "sass_function.h" sass_import_get_error_message
+foreign import ccall unsafe "sass/functions.h" sass_import_get_error_message
     :: SassImportEntry
     -> IO CString
 
-foreign import ccall unsafe "sass_function.h" sass_delete_import_list
+foreign import ccall unsafe "sass/functions.h" sass_delete_import_list
     :: SassImportList
     -> IO ()
 
-foreign import ccall unsafe "sass_function.h" sass_delete_import
+foreign import ccall unsafe "sass/functions.h" sass_delete_import
     :: SassImportEntry
     -> IO ()
 
-foreign import ccall unsafe "sass_function.h" sass_make_function_list
+foreign import ccall unsafe "sass/functions.h" sass_make_function_list
     :: CSize
     -> IO SassFunctionList
 
-foreign import ccall unsafe "sass_function.h" sass_make_function
+foreign import ccall unsafe "sass/functions.h" sass_make_function
     :: CString
     -> SassFunctionFn
     -> Ptr ()
     -> IO SassFunctionEntry
 
-foreign import ccall unsafe "sass_function.h" sass_function_get_list_entry
+foreign import ccall unsafe "sass/functions.h" sass_function_get_list_entry
     :: SassFunctionList
     -> CSize
     -> IO SassFunctionEntry
 
-foreign import ccall unsafe "sass_function.h" sass_function_set_list_entry
+foreign import ccall unsafe "sass/functions.h" sass_function_set_list_entry
     :: SassFunctionList
     -> CSize
     -> SassFunctionEntry
     -> IO ()
 
-foreign import ccall unsafe "sass_function.h" sass_function_get_signature
+foreign import ccall unsafe "sass/functions.h" sass_function_get_signature
     :: SassFunctionEntry
     -> IO CString
 
-foreign import ccall unsafe "sass_function.h" sass_function_get_function
+foreign import ccall unsafe "sass/functions.h" sass_function_get_function
     :: SassFunctionEntry
     -> IO SassFunctionFn
 
-foreign import ccall unsafe "sass_function.h" sass_function_get_cookie
+foreign import ccall unsafe "sass/functions.h" sass_function_get_cookie
     :: SassFunctionEntry
     -> IO (Ptr ())
diff --git a/Bindings/Libsass/Types.hs b/Bindings/Libsass/Types.hs
--- a/Bindings/Libsass/Types.hs
+++ b/Bindings/Libsass/Types.hs
@@ -59,7 +59,7 @@
 type SassImporterEntry = Ptr SassImporter
 type SassImporterList = Ptr (Ptr SassImporter)
 
-type SassImporterFnType = 
+type SassImporterFnType =
      CString
   -> SassImporterEntry
   -> Ptr SassCompiler
@@ -125,3 +125,52 @@
     toEnum 0 = SassSeparatorComma
     toEnum 1 = SassSeparatorSpace
     toEnum u = error ("SassSeparator.toEnum: Cannot match " ++ show u)
+
+-- ^ Operator used to combine two 'SassValue's.
+data SassOp = SassAnd
+            | SassOr
+            | SassEq
+            | SassNeq
+            | SassGt
+            | SassGte
+            | SassLt
+            | SassLte
+            | SassAdd
+            | SassSub
+            | SassMul
+            | SassDiv
+            | SassMod
+            | SassNumOps
+            deriving (Eq, Show)
+
+instance Enum SassOp where
+    fromEnum SassAnd    = 0
+    fromEnum SassOr     = 1
+    fromEnum SassEq     = 2
+    fromEnum SassNeq    = 3
+    fromEnum SassGt     = 4
+    fromEnum SassGte    = 5
+    fromEnum SassLt     = 6
+    fromEnum SassLte    = 7
+    fromEnum SassAdd    = 8
+    fromEnum SassSub    = 9
+    fromEnum SassMul    = 10
+    fromEnum SassDiv    = 11
+    fromEnum SassMod    = 12
+    fromEnum SassNumOps = 13
+
+    toEnum 0  = SassAnd
+    toEnum 1  = SassOr
+    toEnum 2  = SassEq
+    toEnum 3  = SassNeq
+    toEnum 4  = SassGt
+    toEnum 5  = SassGte
+    toEnum 6  = SassLt
+    toEnum 7  = SassLte
+    toEnum 8  = SassAdd
+    toEnum 9  = SassSub
+    toEnum 10 = SassMul
+    toEnum 11 = SassDiv
+    toEnum 12 = SassMod
+    toEnum 13 = SassNumOps
+    toEnum u  = error ("SassOps.toEnum: Cannot match " ++ show u)
diff --git a/Bindings/Libsass/Values.hs b/Bindings/Libsass/Values.hs
--- a/Bindings/Libsass/Values.hs
+++ b/Bindings/Libsass/Values.hs
@@ -5,243 +5,255 @@
 import           Foreign
 import           Foreign.C
 
-foreign import ccall unsafe "sass_values.h" sass_value_get_tag
+foreign import ccall unsafe "sass/values.h" sass_value_get_tag
     :: Ptr SassValue
     -> IO CInt -- ^ Returns 'SassTag'
 
-foreign import ccall unsafe "sass_values.h" sass_value_is_null
+foreign import ccall unsafe "sass/values.h" sass_value_is_null
     :: Ptr SassValue
     -> IO Bool
 
-foreign import ccall unsafe "sass_values.h" sass_value_is_number
+foreign import ccall unsafe "sass/values.h" sass_value_is_number
     :: Ptr SassValue
     -> IO Bool
 
-foreign import ccall unsafe "sass_values.h" sass_value_is_string
+foreign import ccall unsafe "sass/values.h" sass_value_is_string
     :: Ptr SassValue
     -> IO Bool
 
-foreign import ccall unsafe "sass_values.h" sass_value_is_boolean
+foreign import ccall unsafe "sass/values.h" sass_value_is_boolean
     :: Ptr SassValue
     -> IO Bool
 
-foreign import ccall unsafe "sass_values.h" sass_value_is_color
+foreign import ccall unsafe "sass/values.h" sass_value_is_color
     :: Ptr SassValue
     -> IO Bool
 
-foreign import ccall unsafe "sass_values.h" sass_value_is_list
+foreign import ccall unsafe "sass/values.h" sass_value_is_list
     :: Ptr SassValue
     -> IO Bool
 
-foreign import ccall unsafe "sass_values.h" sass_value_is_map
+foreign import ccall unsafe "sass/values.h" sass_value_is_map
     :: Ptr SassValue
     -> IO Bool
 
-foreign import ccall unsafe "sass_values.h" sass_value_is_error
+foreign import ccall unsafe "sass/values.h" sass_value_is_error
     :: Ptr SassValue
     -> IO Bool
 
-foreign import ccall unsafe "sass_values.h" sass_value_is_warning
+foreign import ccall unsafe "sass/values.h" sass_value_is_warning
     :: Ptr SassValue
     -> IO Bool
 
-foreign import ccall unsafe "sass_values.h" sass_number_get_value
+foreign import ccall unsafe "sass/values.h" sass_number_get_value
     :: Ptr SassValue
     -> IO CDouble
 
-foreign import ccall unsafe "sass_values.h" sass_number_set_value
+foreign import ccall unsafe "sass/values.h" sass_number_set_value
     :: Ptr SassValue
     -> CDouble
     -> IO ()
 
-foreign import ccall unsafe "sass_values.h" sass_number_get_unit
+foreign import ccall unsafe "sass/values.h" sass_number_get_unit
     :: Ptr SassValue
     -> IO CString
 
-foreign import ccall unsafe "sass_values.h" sass_number_set_unit
+foreign import ccall unsafe "sass/values.h" sass_number_set_unit
     :: Ptr SassValue
     -> CString
     -> IO ()
 
-foreign import ccall unsafe "sass_values.h" sass_string_get_value
+foreign import ccall unsafe "sass/values.h" sass_string_get_value
     :: Ptr SassValue
     -> IO CString
 
-foreign import ccall unsafe "sass_values.h" sass_string_is_quoted
+foreign import ccall unsafe "sass/values.h" sass_string_set_value
     :: Ptr SassValue
-    -> IO Bool
+    -> CString
+    -> IO ()
 
-foreign import ccall unsafe "sass_values.h" sass_string_set_quoted
+foreign import ccall unsafe "sass/values.h" sass_string_is_quoted
     :: Ptr SassValue
-    -> Bool
-    -> IO ()
+    -> IO Bool
 
-foreign import ccall unsafe "sass_values.h" sass_string_set_value
+foreign import ccall unsafe "sass/values.h" sass_string_set_quoted
     :: Ptr SassValue
-    -> CString
+    -> Bool
     -> IO ()
 
-foreign import ccall unsafe "sass_values.h" sass_boolean_get_value
+foreign import ccall unsafe "sass/values.h" sass_boolean_get_value
     :: Ptr SassValue
     -> IO Bool
 
-foreign import ccall unsafe "sass_values.h" sass_boolean_set_value
+foreign import ccall unsafe "sass/values.h" sass_boolean_set_value
     :: Ptr SassValue
     -> Bool
     -> IO ()
 
-foreign import ccall unsafe "sass_values.h" sass_color_get_r
+foreign import ccall unsafe "sass/values.h" sass_color_get_r
     :: Ptr SassValue
     -> IO CDouble
 
-foreign import ccall unsafe "sass_values.h" sass_color_set_r
+foreign import ccall unsafe "sass/values.h" sass_color_set_r
     :: Ptr SassValue
     -> CDouble
     -> IO ()
 
-foreign import ccall unsafe "sass_values.h" sass_color_get_g
+foreign import ccall unsafe "sass/values.h" sass_color_get_g
     :: Ptr SassValue
     -> IO CDouble
 
-foreign import ccall unsafe "sass_values.h" sass_color_set_g
+foreign import ccall unsafe "sass/values.h" sass_color_set_g
     :: Ptr SassValue
     -> CDouble
     -> IO ()
 
-foreign import ccall unsafe "sass_values.h" sass_color_get_b
+foreign import ccall unsafe "sass/values.h" sass_color_get_b
     :: Ptr SassValue
     -> IO CDouble
 
-foreign import ccall unsafe "sass_values.h" sass_color_set_b
+foreign import ccall unsafe "sass/values.h" sass_color_set_b
     :: Ptr SassValue
     -> CDouble
     -> IO ()
 
-foreign import ccall unsafe "sass_values.h" sass_color_get_a
+foreign import ccall unsafe "sass/values.h" sass_color_get_a
     :: Ptr SassValue
     -> IO CDouble
 
-foreign import ccall unsafe "sass_values.h" sass_color_set_a
+foreign import ccall unsafe "sass/values.h" sass_color_set_a
     :: Ptr SassValue
     -> CDouble
     -> IO ()
 
-foreign import ccall unsafe "sass_values.h" sass_list_get_length
+foreign import ccall unsafe "sass/values.h" sass_list_get_length
     :: Ptr SassValue
     -> IO CSize
 
-foreign import ccall unsafe "sass_values.h" sass_list_get_separator
+foreign import ccall unsafe "sass/values.h" sass_list_get_separator
     :: Ptr SassValue
     -> IO CInt -- ^ Retrurns 'SassSeparator'
 
-foreign import ccall unsafe "sass_values.h" sass_list_set_separator
+foreign import ccall unsafe "sass/values.h" sass_list_set_separator
     :: Ptr SassValue
     -> CInt -- ^ 'SassSeparator'
     -> IO ()
 
-foreign import ccall unsafe "sass_values.h" sass_list_get_value
+foreign import ccall unsafe "sass/values.h" sass_list_get_value
     :: Ptr SassValue
     -> CSize
     -> IO (Ptr SassValue)
 
-foreign import ccall unsafe "sass_values.h" sass_list_set_value
+foreign import ccall unsafe "sass/values.h" sass_list_set_value
     :: Ptr SassValue
     -> CSize
     -> Ptr SassValue
     -> IO ()
 
-foreign import ccall unsafe "sass_values.h" sass_map_get_length
+foreign import ccall unsafe "sass/values.h" sass_map_get_length
     :: Ptr SassValue
     -> IO CSize
 
-foreign import ccall unsafe "sass_values.h" sass_map_get_key
+foreign import ccall unsafe "sass/values.h" sass_map_get_key
     :: Ptr SassValue
     -> CSize
     -> IO (Ptr SassValue)
 
-foreign import ccall unsafe "sass_values.h" sass_map_set_key
+foreign import ccall unsafe "sass/values.h" sass_map_set_key
     :: Ptr SassValue
     -> CSize
     -> Ptr SassValue
     -> IO ()
 
-foreign import ccall unsafe "sass_values.h" sass_map_get_value
+foreign import ccall unsafe "sass/values.h" sass_map_get_value
     :: Ptr SassValue
     -> CSize
     -> IO (Ptr SassValue)
 
-foreign import ccall unsafe "sass_values.h" sass_map_set_value
+foreign import ccall unsafe "sass/values.h" sass_map_set_value
     :: Ptr SassValue
     -> CSize
     -> Ptr SassValue
     -> IO ()
 
-foreign import ccall unsafe "sass_values.h" sass_error_get_message
+foreign import ccall unsafe "sass/values.h" sass_error_get_message
     :: Ptr SassValue
     -> IO CString
 
-foreign import ccall unsafe "sass_values.h" sass_error_set_message
+foreign import ccall unsafe "sass/values.h" sass_error_set_message
     :: Ptr SassValue
     -> CString
     -> IO ()
 
-foreign import ccall unsafe "sass_values.h" sass_warning_get_message
+foreign import ccall unsafe "sass/values.h" sass_warning_get_message
     :: Ptr SassValue
     -> IO CString
 
-foreign import ccall unsafe "sass_values.h" sass_warning_set_message
+foreign import ccall unsafe "sass/values.h" sass_warning_set_message
     :: Ptr SassValue
     -> CString
     -> IO ()
 
-foreign import ccall unsafe "sass_values.h" sass_make_null
+foreign import ccall unsafe "sass/values.h" sass_make_null
     :: IO (Ptr SassValue)
 
-foreign import ccall unsafe "sass_values.h" sass_make_boolean
+foreign import ccall unsafe "sass/values.h" sass_make_boolean
     :: Bool
     -> IO (Ptr SassValue)
 
-foreign import ccall unsafe "sass_values.h" sass_make_string
+foreign import ccall unsafe "sass/values.h" sass_make_string
     :: CString
     -> IO (Ptr SassValue)
 
-foreign import ccall unsafe "sass_values.h" sass_make_qstring
+foreign import ccall unsafe "sass/values.h" sass_make_qstring
     :: CString
     -> IO (Ptr SassValue)
 
-foreign import ccall unsafe "sass_values.h" sass_make_number
+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
+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
+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
+foreign import ccall unsafe "sass/values.h" sass_make_map
     :: CSize
     -> IO (Ptr SassValue)
 
-foreign import ccall unsafe "sass_values.h" sass_make_error
+foreign import ccall unsafe "sass/values.h" sass_make_error
     :: CString
     -> IO (Ptr SassValue)
 
-foreign import ccall unsafe "sass_values.h" sass_make_warning
+foreign import ccall unsafe "sass/values.h" sass_make_warning
     :: CString
     -> IO (Ptr SassValue)
 
-foreign import ccall unsafe "sass_values.h" sass_delete_value
+foreign import ccall unsafe "sass/values.h" sass_delete_value
     :: Ptr SassValue
     -> IO ()
 
-foreign import ccall unsafe "sass_values.h" sass_clone_value
+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/Bindings/Libsass/Wrappers.hs b/Bindings/Libsass/Wrappers.hs
--- a/Bindings/Libsass/Wrappers.hs
+++ b/Bindings/Libsass/Wrappers.hs
@@ -12,23 +12,23 @@
     :: SassFunctionFnType
     -> IO SassFunctionFn
 
-foreign import ccall "sass_context.h &sass_delete_compiler"
+foreign import ccall "sass/context.h &sass_delete_compiler"
     p_sass_delete_compiler :: FunPtr (Ptr SassCompiler -> IO ())
 
-foreign import ccall "sass_context.h &sass_delete_file_context"
+foreign import ccall "sass/context.h &sass_delete_file_context"
     p_sass_delete_file_context :: FunPtr (Ptr SassFileContext -> IO ())
 
-foreign import ccall "sass_context.h &sass_delete_data_context"
+foreign import ccall "sass/context.h &sass_delete_data_context"
     p_sass_delete_data_context :: FunPtr (Ptr SassDataContext -> IO ())
 
-foreign import ccall "sass_function.h &sass_delete_import_list"
+foreign import ccall "sass/functions.h &sass_delete_import_list"
     p_sass_delete_import_list :: FunPtr (SassImportList -> IO ())
 
-foreign import ccall "sass_function.h &sass_delete_import"
+foreign import ccall "sass/functions.h &sass_delete_import"
     p_sass_delete_import :: FunPtr (SassImportEntry -> IO ())
 
-foreign import ccall "sass_function.h &sass_delete_importer"
+foreign import ccall "sass/functions.h &sass_delete_importer"
     p_sass_delete_importer :: FunPtr (SassImporterEntry -> IO ())
 
-foreign import ccall  "sass_values.h &sass_delete_value"
+foreign import ccall  "sass/valuess.h &sass_delete_value"
     p_sass_delete_value :: FunPtr (Ptr SassValue -> IO ())
diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,16 @@
 # Change Log
 All notable changes to this project will be documented in this file.
 
+## [0.1.5.0] - 2015-12-19
+### Added
+- Bindings to `sass_value_op`, `sass_import_get_imp_path` and
+  `sass_import_get_abs_path`
+
+### Changed
+- Uses Libsass 3.3.2
+- `sass_import_get_path` and `sass_import_get_base` have been removed from
+  Libsass
+
 ## [0.1.4.0] - 2015-07-10
 ### Fixed
 - Setup copies `libsass.a` even when Cabal-1.18 is used.
@@ -49,6 +59,7 @@
 - Bindings to Libsass C API
 - Basic tests
 
+[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
 [0.1.3.0]: https://github.com/jakubfijalkowski/hlibsass/compare/v0.1.2.1...v0.1.3.0
 [0.1.2.1]: https://github.com/jakubfijalkowski/hlibsass/compare/v0.1.2.0...v0.1.2.1
diff --git a/hlibsass.cabal b/hlibsass.cabal
--- a/hlibsass.cabal
+++ b/hlibsass.cabal
@@ -1,5 +1,5 @@
 name:                hlibsass
-version:             0.1.4.0
+version:             0.1.5.0
 license:             MIT
 license-file:        LICENSE
 author:              Jakub Fijałkowski <fiolek94@gmail.com>
@@ -18,15 +18,19 @@
   For documentation visit <https://github.com/sass/libsass>.
 
 extra-source-files:
-  libsass/*.cpp
-  libsass/*.c
-  libsass/*.h
-  libsass/*.hpp
-  libsass/b64/*.h
-  libsass/posix/*.h
-  libsass/posix/*.c
-  libsass/utf8/*.h
+  libsass/src/*.cpp
+  libsass/src/*.c
+  libsass/src/*.h
+  libsass/src/*.hpp
+  libsass/src/*.am
+  libsass/src/b64/*.h
+  libsass/src/utf8/*.h
+  libsass/src/support/*.pc.in
+  libsass/include/*.h
+  libsass/include/sass/*.h
+  libsass/include/sass/*.h.in
   libsass/Makefile
+  libsass/Makefile.conf
   libsass/LICENSE
   libsass/VERSION
   CHANGELOG.md
diff --git a/libsass/Makefile b/libsass/Makefile
--- a/libsass/Makefile
+++ b/libsass/Makefile
@@ -3,7 +3,9 @@
 RM       ?= rm -f
 CP       ?= cp -a
 MKDIR    ?= mkdir
+RMDIR    ?= rmdir
 WINDRES  ?= windres
+INSTALL  ?= install
 CFLAGS   ?= -Wall
 CXXFLAGS ?= -Wall
 LDFLAGS  ?= -Wall
@@ -33,48 +35,82 @@
 	endif
 endif
 
-ifeq "$(LIBSASS_VERSION)" ""
-	ifneq "$(wildcard ./.git/ )" ""
+ifeq ($(SASS_LIBSASS_PATH),)
+	SASS_LIBSASS_PATH = $(abspath $(CURDIR))
+endif
+
+ifeq ($(LIBSASS_VERSION),)
+	ifneq ($(wildcard ./.git/ ),)
 		LIBSASS_VERSION ?= $(shell git describe --abbrev=4 --dirty --always --tags)
 	endif
 endif
 
-ifeq "$(LIBSASS_VERSION)" ""
-	ifneq ("$(wildcard VERSION)","")
+ifeq ($(LIBSASS_VERSION),)
+	ifneq ($(wildcard VERSION),)
 		LIBSASS_VERSION ?= $(shell $(CAT) VERSION)
 	endif
 endif
 
-ifneq "$(LIBSASS_VERSION)" ""
+ifneq ($(LIBSASS_VERSION),)
 	CFLAGS   += -DLIBSASS_VERSION="\"$(LIBSASS_VERSION)\""
 	CXXFLAGS += -DLIBSASS_VERSION="\"$(LIBSASS_VERSION)\""
 endif
 
 # enable mandatory flag
 ifeq (MinGW,$(UNAME))
+	ifneq ($(BUILD),shared)
+		STATIC_ALL     ?= 1
+	endif
+	STATIC_LIBGCC    ?= 1
+	STATIC_LIBSTDCPP ?= 1
 	CXXFLAGS += -std=gnu++0x
 	LDFLAGS  += -std=gnu++0x
 else
+	STATIC_ALL       ?= 0
+	STATIC_LIBGCC    ?= 0
+	STATIC_LIBSTDCPP ?= 0
 	CXXFLAGS += -std=c++0x
 	LDFLAGS  += -std=c++0x
 endif
 
-ifneq "$(SASS_LIBSASS_PATH)" ""
-	CFLAGS   += -I $(SASS_LIBSASS_PATH)
-	CXXFLAGS += -I $(SASS_LIBSASS_PATH)
+ifneq ($(SASS_LIBSASS_PATH),)
+	CFLAGS   += -I $(SASS_LIBSASS_PATH)/include
+	CXXFLAGS += -I $(SASS_LIBSASS_PATH)/include
+else
+	# this is needed for mingw
+	CFLAGS   += -I include
+	CXXFLAGS += -I include
 endif
 
-ifneq "$(EXTRA_CFLAGS)" ""
+ifneq ($(EXTRA_CFLAGS),)
 	CFLAGS   += $(EXTRA_CFLAGS)
 endif
-ifneq "$(EXTRA_CXXFLAGS)" ""
+ifneq ($(EXTRA_CXXFLAGS),)
 	CXXFLAGS += $(EXTRA_CXXFLAGS)
 endif
-ifneq "$(EXTRA_LDFLAGS)" ""
+ifneq ($(EXTRA_LDFLAGS),)
 	LDFLAGS  += $(EXTRA_LDFLAGS)
 endif
 
-LDLIBS = -lstdc++ -lm
+LDLIBS = -lm
+
+ifneq ($(BUILD),shared)
+	LDLIBS += -lstdc++
+endif
+
+# link statically into lib
+# makes it a lot more portable
+# increases size by about 50KB
+ifeq ($(STATIC_ALL),1)
+	LDFLAGS += -static
+endif
+ifeq ($(STATIC_LIBGCC),1)
+	LDFLAGS += -static-libgcc
+endif
+ifeq ($(STATIC_LIBSTDCPP),1)
+	LDFLAGS += -static-libstdc++
+endif
+
 ifeq ($(UNAME),Darwin)
 	CFLAGS += -stdlib=libc++
 	CXXFLAGS += -stdlib=libc++
@@ -82,8 +118,10 @@
 endif
 
 ifneq (MinGW,$(UNAME))
-	LDFLAGS += -ldl
-	LDLIBS += -ldl
+	ifneq (FreeBSD,$(UNAME))
+		LDFLAGS += -ldl
+		LDLIBS += -ldl
+	endif
 endif
 
 ifneq ($(BUILD),shared)
@@ -104,79 +142,62 @@
 SASSC_BIN = $(SASS_SASSC_PATH)/bin/sassc
 RUBY_BIN = ruby
 
+LIB_STATIC = $(SASS_LIBSASS_PATH)/lib/libsass.a
+LIB_SHARED = $(SASS_LIBSASS_PATH)/lib/libsass.so
+
 ifeq (MinGW,$(UNAME))
+	ifeq (shared,$(BUILD))
+		CFLAGS     += -D ADD_EXPORTS
+		CXXFLAGS   += -D ADD_EXPORTS
+		LIB_SHARED  = $(SASS_LIBSASS_PATH)/lib/libsass.dll
+	endif
+else
+	ifneq (Cygwin,$(UNAME))
+		CFLAGS   += -fPIC
+		CXXFLAGS += -fPIC
+		LDFLAGS  += -fPIC
+	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
 
-SOURCES = \
-	ast.cpp \
-	base64vlq.cpp \
-	bind.cpp \
-	constants.cpp \
-	context.cpp \
-	contextualize.cpp \
-	contextualize_eval.cpp \
-	cssize.cpp \
-	listize.cpp \
-	error_handling.cpp \
-	eval.cpp \
-	expand.cpp \
-	extend.cpp \
-	file.cpp \
-	functions.cpp \
-	inspect.cpp \
-	lexer.cpp \
-	node.cpp \
-	json.cpp \
-	emitter.cpp \
-	output.cpp \
-	parser.cpp \
-	plugins.cpp \
-	position.cpp \
-	prelexer.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 \
-	units.cpp \
-	utf8_string.cpp \
-	util.cpp
-
-CSOURCES = cencode.c
+include Makefile.conf
 
 RESOURCES =
-
-LIBRARIES = lib/libsass.so
-
+STATICLIB = lib/libsass.a
+SHAREDLIB = lib/libsass.so
 ifeq (MinGW,$(UNAME))
+	RESOURCES += res/resource.rc
+	SHAREDLIB  = lib/libsass.dll
 	ifeq (shared,$(BUILD))
 		CFLAGS    += -D ADD_EXPORTS
 		CXXFLAGS  += -D ADD_EXPORTS
-		LIBRARIES += lib/libsass.dll
-		RESOURCES += res/resource.rc
 	endif
 else
-	CFLAGS   += -fPIC
-	CXXFLAGS += -fPIC
-	LDFLAGS  += -fPIC
+	ifneq (Cygwin,$(UNAME))
+		CFLAGS   += -fPIC
+		CXXFLAGS += -fPIC
+		LDFLAGS  += -fPIC
+	endif
 endif
 
-OBJECTS = $(SOURCES:.cpp=.o)
-COBJECTS = $(CSOURCES:.c=.o)
+OBJECTS = $(addprefix src/,$(SOURCES:.cpp=.o))
+COBJECTS = $(addprefix src/,$(CSOURCES:.c=.o))
 RCOBJECTS = $(RESOURCES:.rc=.o)
 
 DEBUG_LVL ?= NONE
 
+CLEANUPS ?=
+CLEANUPS += $(RCOBJECTS)
+CLEANUPS += $(COBJECTS)
+CLEANUPS += $(OBJECTS)
+CLEANUPS += $(LIBSASS_LIB)
+
 all: $(BUILD)
 
 debug: $(BUILD)
@@ -191,9 +212,6 @@
 debug-shared: CXXFLAGS := -g -DDEBUG -DDEBUG_LVL="$(DEBUG_LVL)" $(filter-out -O2,$(CXXFLAGS))
 debug-shared: shared
 
-static: lib/libsass.a
-shared: $(LIBRARIES)
-
 lib:
 	$(MKDIR) lib
 
@@ -220,18 +238,61 @@
 
 install: install-$(BUILD)
 
-install-static: lib/libsass.a
-	install -pm0755 $< $(DESTDIR)$(PREFIX)/$<
+static: $(STATICLIB)
+shared: $(SHAREDLIB)
 
-install-shared: lib/libsass.so
-	install -pm0755 $< $(DESTDIR)$(PREFIX)/$<
+$(DESTDIR)$(PREFIX):
+	$(MKDIR) $(DESTDIR)$(PREFIX)
 
+$(DESTDIR)$(PREFIX)/lib: $(DESTDIR)$(PREFIX)
+	$(MKDIR) $(DESTDIR)$(PREFIX)/lib
+
+$(DESTDIR)$(PREFIX)/include: $(DESTDIR)$(PREFIX)
+	$(MKDIR) $(DESTDIR)$(PREFIX)/include
+
+$(DESTDIR)$(PREFIX)/include/sass: $(DESTDIR)$(PREFIX)/include
+	$(MKDIR) $(DESTDIR)$(PREFIX)/include/sass
+
+$(DESTDIR)$(PREFIX)/include/%.h: include/%.h \
+                                 $(DESTDIR)$(PREFIX)/include \
+                                 $(DESTDIR)$(PREFIX)/include/sass
+	$(INSTALL) -v -m0644 "$<" "$@"
+
+install-headers: $(DESTDIR)$(PREFIX)/include/sass.h \
+                 $(DESTDIR)$(PREFIX)/include/sass2scss.h \
+                 $(DESTDIR)$(PREFIX)/include/sass/base.h \
+                 $(DESTDIR)$(PREFIX)/include/sass/version.h \
+                 $(DESTDIR)$(PREFIX)/include/sass/values.h \
+                 $(DESTDIR)$(PREFIX)/include/sass/context.h \
+                 $(DESTDIR)$(PREFIX)/include/sass/functions.h
+
+$(DESTDIR)$(PREFIX)/lib/%.a: lib/%.a \
+                             $(DESTDIR)$(PREFIX)/lib
+	@$(INSTALL) -v -m0755 "$<" "$@"
+
+$(DESTDIR)$(PREFIX)/lib/%.so: lib/%.so \
+                             $(DESTDIR)$(PREFIX)/lib
+	@$(INSTALL) -v -m0755 "$<" "$@"
+
+$(DESTDIR)$(PREFIX)/lib/%.dll: lib/%.dll \
+                               $(DESTDIR)$(PREFIX)/lib
+	@$(INSTALL) -v -m0755 "$<" "$@"
+
+install-static: $(DESTDIR)$(PREFIX)/lib/libsass.a
+
+install-shared: $(DESTDIR)$(PREFIX)/lib/libsass.so \
+                install-headers
+
 $(SASSC_BIN): $(BUILD)
-	cd $(SASS_SASSC_PATH) && $(MAKE)
+	$(MAKE) -C $(SASS_SASSC_PATH)
 
 sassc: $(SASSC_BIN)
 	$(SASSC_BIN) -v
 
+version: $(SASSC_BIN)
+	$(SASSC_BIN) -h
+	$(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)
 
@@ -241,8 +302,32 @@
 test_issues: $(SASSC_BIN)
 	$(RUBY_BIN) $(SASS_SPEC_PATH)/sass-spec.rb -c $(SASSC_BIN) $(LOG_FLAGS) $(SASS_SPEC_PATH)/spec/issues
 
-clean:
-	$(RM) $(RCOBJECTS) $(COBJECTS) $(OBJECTS) $(LIBRARIES) lib/*.a lib/*.so lib/*.dll lib/*.la
+clean-objects: lib
+	-$(RM) lib/*.a lib/*.so lib/*.dll lib/*.la
+	-$(RMDIR) lib
+clean: clean-objects
+	$(RM) $(CLEANUPS)
 
+clean-all:
+	$(MAKE) -C $(SASS_SASSC_PATH) clean
 
-.PHONY: all debug debug-static debug-shared static shared install install-static install-shared sassc clean
+lib-file: lib-file-$(BUILD)
+lib-opts: lib-opts-$(BUILD)
+
+lib-file-static:
+	@echo $(LIB_STATIC)
+lib-file-shared:
+	@echo $(LIB_SHARED)
+lib-opts-static:
+	@echo -L"$(SASS_LIBSASS_PATH)/lib"
+lib-opts-shared:
+	@echo -L"$(SASS_LIBSASS_PATH)/lib -lsass"
+
+.PHONY: all static shared sassc \
+        version install-headers \
+        clean clean-all clean-objects \
+        debug debug-static debug-shared \
+        install install-static install-shared \
+        lib-opts lib-opts-shared lib-opts-static \
+        lib-file lib-file-shared lib-file-static
+.DELETE_ON_ERROR:
diff --git a/libsass/Makefile.conf b/libsass/Makefile.conf
new file mode 100644
--- /dev/null
+++ b/libsass/Makefile.conf
@@ -0,0 +1,47 @@
+# this is merely a common Makefile multiple implementers can use
+
+SOURCES = \
+	ast.cpp \
+	base64vlq.cpp \
+	bind.cpp \
+	color_maps.cpp \
+	constants.cpp \
+	context.cpp \
+	cssize.cpp \
+	emitter.cpp \
+	environment.cpp \
+	error_handling.cpp \
+	eval.cpp \
+	expand.cpp \
+	extend.cpp \
+	file.cpp \
+	functions.cpp \
+	inspect.cpp \
+	json.cpp \
+	lexer.cpp \
+	listize.cpp \
+	memory_manager.cpp \
+	node.cpp \
+	output.cpp \
+	parser.cpp \
+	plugins.cpp \
+	position.cpp \
+	prelexer.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 \
+	utf8_string.cpp \
+	values.cpp \
+	util.cpp
+
+CSOURCES = cencode.c
diff --git a/libsass/VERSION b/libsass/VERSION
--- a/libsass/VERSION
+++ b/libsass/VERSION
@@ -1,1 +1,1 @@
-3.2.4-18-g3672
+3.3.2
diff --git a/libsass/ast.cpp b/libsass/ast.cpp
deleted file mode 100644
--- a/libsass/ast.cpp
+++ /dev/null
@@ -1,945 +0,0 @@
-#include "ast.hpp"
-#include "context.hpp"
-#include "to_string.hpp"
-#include <set>
-#include <algorithm>
-#include <iostream>
-
-namespace Sass {
-  using namespace std;
-
-  static Null sass_null(Sass::Null(ParserState("null")));
-
-  bool Compound_Selector::operator<(const Compound_Selector& rhs) const
-  {
-    To_String to_string;
-    // ugly
-    return const_cast<Compound_Selector*>(this)->perform(&to_string) <
-           const_cast<Compound_Selector&>(rhs).perform(&to_string);
-  }
-
-  bool Complex_Selector::operator<(const Complex_Selector& rhs) const
-  {
-    To_String to_string;
-    return const_cast<Complex_Selector*>(this)->perform(&to_string) <
-           const_cast<Complex_Selector&>(rhs).perform(&to_string);
-  }
-
-  bool Complex_Selector::operator==(const Complex_Selector& rhs) const {
-    // TODO: We have to access the tail directly using tail_ since ADD_PROPERTY doesn't provide a const version.
-
-    const Complex_Selector* pOne = this;
-    const Complex_Selector* pTwo = &rhs;
-
-    // Consume any empty references at the beginning of the Complex_Selector
-    if (pOne->combinator() == Complex_Selector::ANCESTOR_OF && pOne->head()->is_empty_reference()) {
-      pOne = pOne->tail_;
-    }
-    if (pTwo->combinator() == Complex_Selector::ANCESTOR_OF && pTwo->head()->is_empty_reference()) {
-      pTwo = pTwo->tail_;
-    }
-
-    while (pOne && pTwo) {
-      if (pOne->combinator() != pTwo->combinator()) {
-        return false;
-      }
-
-      if (*(pOne->head()) != *(pTwo->head())) {
-        return false;
-      }
-
-      pOne = pOne->tail_;
-      pTwo = pTwo->tail_;
-    }
-
-    return pOne == NULL && pTwo == NULL;
-  }
-
-  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;
-      else          unified = (*this)[i]->unify_with(unified, ctx);
-    }
-    return unified;
-  }
-
-  bool Simple_Selector::operator==(const Simple_Selector& rhs) const
-  {
-    // Compare the string representations for equality.
-
-    // Cast away const here. To_String should take a const object, but it doesn't.
-    Simple_Selector* pLHS = const_cast<Simple_Selector*>(this);
-    Simple_Selector* pRHS = const_cast<Simple_Selector*>(&rhs);
-
-    To_String to_string;
-    return pLHS->perform(&to_string) == pRHS->perform(&to_string);
-  }
-
-  bool Simple_Selector::operator<(const Simple_Selector& rhs) const {
-    // Use the string representation for ordering.
-
-    // Cast away const here. To_String should take a const object, but it doesn't.
-    Simple_Selector* pLHS = const_cast<Simple_Selector*>(this);
-    Simple_Selector* pRHS = const_cast<Simple_Selector*>(&rhs);
-
-    To_String to_string;
-    return pLHS->perform(&to_string) < pRHS->perform(&to_string);
-  }
-
-  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 need to come 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 = new (ctx.mem) Compound_Selector(*rhs);
-      (*cpy) << this;
-      return cpy;
-    }
-    Compound_Selector* cpy = 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;
-  }
-
-  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 = new (ctx.mem) Compound_Selector(rhs->pstate());
-      (*cpy) << this;
-      return cpy;
-    }
-
-    // if this is a universal selector and rhs is not empty, just return the rhs
-    if (name() == "*")
-    { return new (ctx.mem) Compound_Selector(*rhs); }
-
-
-    Simple_Selector* rhs_0 = (*rhs)[0];
-    // otherwise, this is a tag name
-    if (typeid(*rhs_0) == typeid(Type_Selector))
-    {
-      // if rhs is universal, just return this tagname + rhs's qualifiers
-      if (static_cast<Type_Selector*>(rhs_0)->name() == "*")
-      {
-        Compound_Selector* cpy = new (ctx.mem) Compound_Selector(rhs->pstate());
-        (*cpy) << this;
-        for (size_t i = 1, L = rhs->length(); i < L; ++i)
-        { (*cpy) << (*rhs)[i]; }
-        return cpy;
-      }
-      // if rhs is another tag name and it matches this, return rhs
-      else if (static_cast<Type_Selector*>(rhs_0)->name() == name())
-      { return new (ctx.mem) Compound_Selector(*rhs); }
-      // else the tag names don't match; return nil
-      else
-      { return 0; }
-    }
-    // else it's a tag name and a bunch of qualifiers -- just append them
-    Compound_Selector* cpy = new (ctx.mem) Compound_Selector(rhs->pstate());
-    (*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 Compound_Selector::is_superselector_of(Compound_Selector* rhs)
-  {
-    To_String to_string;
-
-    Simple_Selector* lbase = base();
-    Simple_Selector* rbase = rhs->base();
-
-    // Check if pseudo-elements are the same between the selectors
-
-    set<string> lpsuedoset, rpsuedoset;
-    for (size_t i = 0, L = length(); i < L; ++i)
-    {
-      if ((*this)[i]->is_pseudo_element()) {
-        string pseudo((*this)[i]->perform(&to_string));
-        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()) {
-        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;
-    }
-
-    // Check the Simple_Selectors
-
-    set<string> lset, rset;
-
-    if (!lbase) // no lbase; just see if the left-hand qualifiers are a subset of the right-hand selector
-    {
-      for (size_t i = 0, L = length(); i < L; ++i)
-      {
-        Selector* lhs = (*this)[i];
-        // very special case for wrapped matches selector
-        if (Wrapped_Selector* wrapped = dynamic_cast<Wrapped_Selector*>(lhs)) {
-          if (wrapped->name() == ":matches(" || wrapped->name() == ":-moz-any(") {
-            if (Selector_List* list = dynamic_cast<Selector_List*>(wrapped->selector())) {
-              if (Compound_Selector* comp = dynamic_cast<Compound_Selector*>(rhs)) {
-                if (list->is_superselector_of(comp)) return true;
-              }
-            }
-          }
-        }
-        // match from here on as strings
-        lset.insert(lhs->perform(&to_string));
-      }
-      for (size_t i = 0, L = rhs->length(); i < L; ++i)
-      { rset.insert((*rhs)[i]->perform(&to_string)); }
-      return includes(rset.begin(), rset.end(), lset.begin(), lset.end());
-    }
-    else { // there's an lbase
-      for (size_t i = 1, L = length(); i < L; ++i)
-      { lset.insert((*this)[i]->perform(&to_string)); }
-      if (rbase)
-      {
-        if (lbase->perform(&to_string) != rbase->perform(&to_string)) // if there's an rbase, make sure they match
-        { return false; }
-        else // the bases do match, so compare qualifiers
-        {
-          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());
-        }
-      }
-    }
-    // catch-all
-    return false;
-  }
-
-  bool Compound_Selector::operator==(const Compound_Selector& rhs) const {
-    To_String to_string;
-
-    // Check if pseudo-elements are the same between the selectors
-
-    set<string> lpsuedoset, rpsuedoset;
-    for (size_t i = 0, L = length(); i < L; ++i)
-    {
-      if ((*this)[i]->is_pseudo_element()) {
-        string pseudo((*this)[i]->perform(&to_string));
-        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()) {
-        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;
-    }
-
-    // Check the base
-
-    const Simple_Selector* const lbase = base();
-    const Simple_Selector* const rbase = rhs.base();
-
-    if ((lbase && !rbase) ||
-      (!lbase && rbase) ||
-      ((lbase && rbase) && (*lbase != *rbase))) {
-      return false;
-    }
-
-
-    // Check the rest of the SimpleSelectors
-    // Use string representations. We can't create a set of Simple_Selector pointers because std::set == std::set is going to call ==
-    // on the pointers to determine equality. I don't know of a way to pass in a comparison object. The one you can specify as part of
-    // the template type is used for ordering, but not equality. We also can't just put in non-pointer Simple_Selectors because the
-    // class is intended to be subclassed, and we'd get splicing.
-
-    set<string> lset, rset;
-
-    for (size_t i = 0, L = length(); i < L; ++i)
-    { lset.insert((*this)[i]->perform(&to_string)); }
-    for (size_t i = 0, L = rhs.length(); i < L; ++i)
-    { rset.insert(rhs[i]->perform(&to_string)); }
-
-    return lset == rset;
-  }
-
-  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)
-  {
-    return base()->is_superselector_of(rhs);
-  }
-
-  bool Complex_Selector::is_superselector_of(Complex_Selector* rhs)
-  {
-    Complex_Selector* lhs = this;
-    To_String to_string;
-    // check for selectors with leading or trailing combinators
-    if (!lhs->head() || !rhs->head())
-    { return false; }
-    Complex_Selector* l_innermost = lhs->innermost();
-    if (l_innermost->combinator() != Complex_Selector::ANCESTOR_OF && !l_innermost->tail())
-    { return false; }
-    Complex_Selector* r_innermost = rhs->innermost();
-    if (r_innermost->combinator() != Complex_Selector::ANCESTOR_OF && !r_innermost->tail())
-    { 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->base()); }
-
-    // we have to look one tail deeper, since we cary the
-    // combinator around for it (which is important here)
-    if (rhs->tail() && lhs->tail() && combinator() != Complex_Selector::ANCESTOR_OF) {
-      Complex_Selector* lhs_tail = lhs->tail();
-      Complex_Selector* rhs_tail = rhs->tail();
-      if (lhs_tail->combinator() != rhs_tail->combinator()) return false;
-      if (!lhs_tail->head()->is_superselector_of(rhs_tail->head())) return false;
-    }
-
-
-    bool found = false;
-    Complex_Selector* marker = rhs;
-    for (size_t i = 0, L = rhs->length(); i < L; ++i) {
-      if (i == L-1)
-      { return false; }
-      if (lhs->head()->is_superselector_of(marker->head()))
-      { 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()
-  {
-    // TODO: make this iterative
-    if (!tail()) return 1;
-    return 1 + tail()->length();
-  }
-
-  Compound_Selector* Complex_Selector::base()
-  {
-    if (!tail()) return head();
-    else return tail()->base();
-  }
-
-  Complex_Selector* Complex_Selector::context(Context& ctx)
-  {
-    if (!tail()) return 0;
-    if (!head()) return tail()->context(ctx);
-    Complex_Selector* cpy = new (ctx.mem) Complex_Selector(pstate(), combinator(), head(), tail()->context(ctx));
-    cpy->media_block(media_block());
-    cpy->last_block(last_block());
-    return cpy;
-  }
-
-  Complex_Selector* Complex_Selector::innermost()
-  {
-    if (!tail()) return this;
-    else         return tail()->innermost();
-  }
-
-  Complex_Selector::Combinator Complex_Selector::clear_innermost()
-  {
-    Combinator c;
-    if (!tail() || tail()->length() == 1)
-    { 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 = new (ctx.mem) Complex_Selector(*this);
-    if (tail()) cpy->tail(tail()->clone(ctx));
-    return cpy;
-  }
-
-  Complex_Selector* Complex_Selector::cloneFully(Context& ctx) const
-  {
-    Complex_Selector* cpy = 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 = new (ctx.mem) Compound_Selector(*this);
-    return cpy;
-  }
-
-
-
-  /* not used anymore - remove?
-  Selector_Placeholder* Selector::find_placeholder()
-  {
-    return 0;
-  }*/
-
-  void Selector_List::adjust_after_pushing(Complex_Selector* c)
-  {
-    if (c->has_reference())   has_reference(true);
-    if (c->has_placeholder()) has_placeholder(true);
-
-#ifdef DEBUG
-    To_String to_string;
-    this->mCachedSelector(this->perform(&to_string));
-#endif
-  }
-
-  // it's a superselector if every selector of the right side
-  // list is a superselector of the given left side selector
-  bool Complex_Selector::is_superselector_of(Selector_List *sub)
-  {
-    // Check every rhs selector against left hand list
-    for(size_t i = 0, L = sub->length(); i < L; ++i) {
-      if (!is_superselector_of((*sub)[i])) return false;
-    }
-    return true;
-  }
-
-  // it's a superselector if every selector of the right side
-  // list is a superselector of the given left side selector
-  bool Selector_List::is_superselector_of(Selector_List *sub)
-  {
-    // Check every rhs selector against left hand list
-    for(size_t i = 0, L = sub->length(); i < L; ++i) {
-      if (!is_superselector_of((*sub)[i])) return false;
-    }
-    return true;
-  }
-
-  // it's a superselector if every selector on the right side
-  // is a superselector of any one of the left side selectors
-  bool Selector_List::is_superselector_of(Compound_Selector *sub)
-  {
-    // Check every lhs selector against right hand
-    for(size_t i = 0, L = length(); i < L; ++i) {
-      if ((*this)[i]->is_superselector_of(sub)) return true;
-    }
-    return false;
-  }
-
-  // it's a superselector if every selector on the right side
-  // is a superselector of any one of the left side selectors
-  bool Selector_List::is_superselector_of(Complex_Selector *sub)
-  {
-    // Check every lhs selector against right hand
-    for(size_t i = 0, L = length(); i < L; ++i) {
-      if ((*this)[i]->is_superselector_of(sub)) return true;
-    }
-    return false;
-  }
-
-  /* not used anymore - remove?
-  Selector_Placeholder* Selector_List::find_placeholder()
-  {
-    if (has_placeholder()) {
-      for (size_t i = 0, L = length(); i < L; ++i) {
-        if ((*this)[i]->has_placeholder()) return (*this)[i]->find_placeholder();
-      }
-    }
-    return 0;
-  }*/
-
-  /* not used anymore - remove?
-  Selector_Placeholder* Complex_Selector::find_placeholder()
-  {
-    if (has_placeholder()) {
-      if (head() && head()->has_placeholder()) return head()->find_placeholder();
-      else if (tail() && tail()->has_placeholder()) return tail()->find_placeholder();
-    }
-    return 0;
-  }*/
-
-  /* not used anymore - remove?
-  Selector_Placeholder* Compound_Selector::find_placeholder()
-  {
-    if (has_placeholder()) {
-      for (size_t i = 0, L = length(); i < L; ++i) {
-        if ((*this)[i]->has_placeholder()) return (*this)[i]->find_placeholder();
-      }
-      // return this;
-    }
-    return 0;
-  }*/
-
-  /* not used anymore - remove?
-  Selector_Placeholder* Selector_Placeholder::find_placeholder()
-  {
-    return this;
-  }*/
-
-  vector<string> Compound_Selector::to_str_vec()
-  {
-    To_String to_string;
-    vector<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 = new (ctx.mem) Compound_Selector(pstate());
-
-    // not very efficient because it needs to preserve order
-    for (size_t i = 0, L = length(); i < L; ++i)
-    {
-      bool found = false;
-      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));
-    }
-  }
-
-  /* not used anymore - remove?
-  vector<Compound_Selector*> Complex_Selector::to_vector()
-  {
-    vector<Compound_Selector*> result;
-    Compound_Selector* h = head();
-    Complex_Selector* t = tail();
-    if (h) result.push_back(h);
-    while (t)
-    {
-      h = t->head();
-      t = t->tail();
-      if (h) result.push_back(h);
-    }
-    return result;
-  }*/
-
-  Number::Number(ParserState pstate, double val, string u, bool zero)
-  : Expression(pstate),
-    value_(val),
-    zero_(zero),
-    numerator_units_(vector<string>()),
-    denominator_units_(vector<string>()),
-    hash_(0)
-  {
-    size_t l = 0, r = 0;
-    if (!u.empty()) {
-      bool nominator = true;
-      while (true) {
-        r = u.find_first_of("*/", l);
-        string unit(u.substr(l, r - l));
-        if (nominator) numerator_units_.push_back(unit);
-        else denominator_units_.push_back(unit);
-        if (u[r] == '/') nominator = false;
-        if (r == string::npos) break;
-        else l = r + 1;
-      }
-    }
-    concrete_type(NUMBER);
-  }
-
-  string Number::unit() const
-  {
-    stringstream u;
-    for (size_t i = 0, S = numerator_units_.size(); i < S; ++i) {
-      if (i) u << '*';
-      u << numerator_units_[i];
-    }
-    if (!denominator_units_.empty()) u << '/';
-    for (size_t i = 0, S = denominator_units_.size(); i < S; ++i) {
-      if (i) u << '*';
-      u << denominator_units_[i];
-    }
-    return u.str();
-  }
-
-  bool Number::is_unitless()
-  { return numerator_units_.empty() && denominator_units_.empty(); }
-
-  void Number::normalize(const string& prefered)
-  {
-
-    // first make sure same units cancel each other out
-    // it seems that a map table will fit nicely to do this
-    // we basically construct exponents for each unit
-    // has the advantage that they will be pre-sorted
-    map<string, int> exponents;
-
-    // initialize by summing up occurences in unit vectors
-    for (size_t i = 0, S = numerator_units_.size(); i < S; ++i) ++ exponents[numerator_units_[i]];
-    for (size_t i = 0, S = denominator_units_.size(); i < S; ++i) -- exponents[denominator_units_[i]];
-
-    // the final conversion factor
-    double factor = 1;
-
-    // get the first entry of numerators
-    // forward it when entry is converted
-    vector<string>::iterator nom_it = numerator_units_.begin();
-    vector<string>::iterator nom_end = numerator_units_.end();
-    vector<string>::iterator denom_it = denominator_units_.begin();
-    vector<string>::iterator denom_end = denominator_units_.end();
-
-    // main normalization loop
-    // should be close to optimal
-    while (denom_it != denom_end)
-    {
-      // get and increment afterwards
-      const string denom = *(denom_it ++);
-      // skip already canceled out unit
-      if (exponents[denom] >= 0) continue;
-      // skip all units we don't know how to convert
-      if (string_to_unit(denom) == UNKNOWN) continue;
-      // now search for nominator
-      while (nom_it != nom_end)
-      {
-        // get and increment afterwards
-        const string nom = *(nom_it ++);
-        // skip already canceled out unit
-        if (exponents[nom] <= 0) continue;
-        // skip all units we don't know how to convert
-        if (string_to_unit(nom) == UNKNOWN) continue;
-        // we now have two convertable units
-        // add factor for current conversion
-        factor *= conversion_factor(nom, denom);
-        // update nominator/denominator exponent
-        -- exponents[nom]; ++ exponents[denom];
-        // inner loop done
-        break;
-      }
-    }
-
-    // now we can build up the new unit arrays
-    numerator_units_.clear();
-    denominator_units_.clear();
-
-    // build them by iterating over the exponents
-    for (auto exp : exponents)
-    {
-      // maybe there is more effecient way to push
-      // the same item multiple times to a vector?
-      for(size_t i = 0, S = abs(exp.second); i < S; ++i)
-      {
-        // opted to have these switches in the inner loop
-        // makes it more readable and should not cost much
-        if (exp.second < 0) denominator_units_.push_back(exp.first);
-        else if (exp.second > 0) numerator_units_.push_back(exp.first);
-      }
-    }
-
-    // apply factor to value_
-    // best precision this way
-    value_ *= factor;
-
-    // maybe convert to other unit
-    // easier implemented on its own
-    try { convert(prefered); }
-    catch (incompatibleUnits& err)
-    { error(err.what(), pstate()); }
-    catch (...) { throw; }
-
-  }
-
-  void Number::convert(const string& prefered)
-  {
-    // abort if unit is empty
-    if (prefered.empty()) return;
-
-    // first make sure same units cancel each other out
-    // it seems that a map table will fit nicely to do this
-    // we basically construct exponents for each unit
-    // has the advantage that they will be pre-sorted
-    map<string, int> exponents;
-
-    // initialize by summing up occurences in unit vectors
-    for (size_t i = 0, S = numerator_units_.size(); i < S; ++i) ++ exponents[numerator_units_[i]];
-    for (size_t i = 0, S = denominator_units_.size(); i < S; ++i) -- exponents[denominator_units_[i]];
-
-    // the final conversion factor
-    double factor = 1;
-
-    vector<string>::iterator denom_it = denominator_units_.begin();
-    vector<string>::iterator denom_end = denominator_units_.end();
-
-    // main normalization loop
-    // should be close to optimal
-    while (denom_it != denom_end)
-    {
-      // get and increment afterwards
-      const string denom = *(denom_it ++);
-      // check if conversion is needed
-      if (denom == prefered) continue;
-      // skip already canceled out unit
-      if (exponents[denom] >= 0) continue;
-      // skip all units we don't know how to convert
-      if (string_to_unit(denom) == UNKNOWN) continue;
-      // we now have two convertable units
-      // add factor for current conversion
-      factor *= conversion_factor(denom, prefered);
-      // update nominator/denominator exponent
-      ++ exponents[denom]; -- exponents[prefered];
-    }
-
-    vector<string>::iterator nom_it = numerator_units_.begin();
-    vector<string>::iterator nom_end = numerator_units_.end();
-
-    // now search for nominator
-    while (nom_it != nom_end)
-    {
-      // get and increment afterwards
-      const string nom = *(nom_it ++);
-      // check if conversion is needed
-      if (nom == prefered) continue;
-      // skip already canceled out unit
-      if (exponents[nom] <= 0) continue;
-      // skip all units we don't know how to convert
-      if (string_to_unit(nom) == UNKNOWN) continue;
-      // we now have two convertable units
-      // add factor for current conversion
-      factor *= conversion_factor(nom, prefered);
-      // update nominator/denominator exponent
-      -- exponents[nom]; ++ exponents[prefered];
-    }
-
-    // now we can build up the new unit arrays
-    numerator_units_.clear();
-    denominator_units_.clear();
-
-    // build them by iterating over the exponents
-    for (auto exp : exponents)
-    {
-      // maybe there is more effecient way to push
-      // the same item multiple times to a vector?
-      for(size_t i = 0, S = abs(exp.second); i < S; ++i)
-      {
-        // opted to have these switches in the inner loop
-        // makes it more readable and should not cost much
-        if (exp.second < 0) denominator_units_.push_back(exp.first);
-        else if (exp.second > 0) numerator_units_.push_back(exp.first);
-      }
-    }
-
-    // apply factor to value_
-    // best precision this way
-    value_ *= factor;
-
-  }
-
-  // useful for making one number compatible with another
-  string Number::find_convertible_unit() const
-  {
-    for (size_t i = 0, S = numerator_units_.size(); i < S; ++i) {
-      string u(numerator_units_[i]);
-      if (string_to_unit(u) != UNKNOWN) return u;
-    }
-    for (size_t i = 0, S = denominator_units_.size(); i < S; ++i) {
-      string u(denominator_units_[i]);
-      if (string_to_unit(u) != UNKNOWN) return u;
-    }
-    return string();
-  }
-
-
-  bool Number::operator== (Expression* rhs) const
-  {
-    try
-    {
-      Number l(pstate_, value_, unit());
-      Number& r = dynamic_cast<Number&>(*rhs);
-      l.normalize(find_convertible_unit());
-      r.normalize(find_convertible_unit());
-      return l.unit() == r.unit() &&
-             l.value() == r.value();
-    }
-    catch (std::bad_cast&) {}
-    catch (...) { throw; }
-    return false;
-  }
-
-  bool Number::operator== (Expression& rhs) const
-  {
-    return operator==(&rhs);
-  }
-
-  bool List::operator==(Expression* rhs) const
-  {
-    try
-    {
-      List* r = dynamic_cast<List*>(rhs);
-      if (!r || length() != r->length()) return false;
-      if (separator() != r->separator()) return false;
-      for (size_t i = 0, L = r->length(); i < L; ++i)
-        if (*elements()[i] != *(*r)[i]) return false;
-      return true;
-    }
-    catch (std::bad_cast&) {}
-    catch (...) { throw; }
-    return false;
-  }
-
-  bool List::operator== (Expression& rhs) const
-  {
-    return operator==(&rhs);
-  }
-
-  size_t List::size() const {
-    if (!is_arglist_) return length();
-    // arglist expects a list of arguments
-    // so we need to break before keywords
-    for (size_t i = 0, L = length(); i < L; ++i) {
-      if (Argument* arg = dynamic_cast<Argument*>((*this)[i])) {
-        if (!arg->name().empty()) return i;
-      }
-    }
-    return length();
-  }
-
-  Expression* Hashed::at(Expression* k) const
-  {
-    if (elements_.count(k))
-    { return elements_.at(k); }
-    else { return &sass_null; }
-  }
-
-}
-
diff --git a/libsass/ast.hpp b/libsass/ast.hpp
deleted file mode 100644
--- a/libsass/ast.hpp
+++ /dev/null
@@ -1,2141 +0,0 @@
-#ifndef SASS_AST_H
-#define SASS_AST_H
-
-#include <set>
-#include <deque>
-#include <vector>
-#include <string>
-#include <sstream>
-#include <iostream>
-#include <typeinfo>
-#include <algorithm>
-#include <unordered_map>
-
-#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"
-#include "sass_values.h"
-#include "sass_functions.h"
-
-namespace Sass {
-  using namespace std;
-
-  //////////////////////////////////////////////////////////
-  // Abstract base class for all abstract syntax tree nodes.
-  //////////////////////////////////////////////////////////
-  class AST_Node {
-    ADD_PROPERTY(ParserState, pstate);
-  public:
-    AST_Node(ParserState pstate)
-    : pstate_(pstate)
-    { }
-    virtual ~AST_Node() = 0;
-    // virtual Block* block() { return 0; }
-  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,
-      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 string type() { return ""; /* TODO: raise an error? */ }
-    virtual bool is_invisible() { return false; }
-    static string type_name() { return ""; }
-    virtual bool is_false() { return false; }
-    virtual bool operator==( Expression& rhs) const { return false; }
-    virtual void set_delayed(bool delayed) { is_delayed(delayed); }
-    virtual size_t hash() { return 0; }
-  };
-}
-
-
-/////////////////////////////////////////////////////////////////////////////
-// Hash method specializations for 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 == *rhs;
-    }
-  };
-}
-
-namespace Sass {
-  using namespace std;
-
-  /////////////////////////////////////////////////////////////////////////////
-  // 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 {
-    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_(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& operator[](size_t i) { return elements_[i]; }
-    const T& operator[](size_t i) const { return elements_[i]; }
-    Vectorized& operator<<(T element)
-    {
-      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;
-    }
-    vector<T>& elements() { return elements_; }
-    const vector<T>& elements() const { return elements_; }
-    vector<T>& elements(vector<T>& e) { elements_ = e; return elements_; }
-  };
-  template <typename T>
-  inline Vectorized<T>::~Vectorized() { }
-
-  /////////////////////////////////////////////////////////////////////////////
-  // Mixin class for AST nodes that should behave like a hash table. Uses an
-  // extra <vector> internally to maintain insertion order for interation.
-  /////////////////////////////////////////////////////////////////////////////
-  class Hashed {
-  private:
-    unordered_map<Expression*, Expression*> elements_;
-    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_(unordered_map<Expression*, Expression*>(s)), list_(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 unordered_map<Expression*, Expression*> elements() { return elements_; }
-    Hashed& operator<<(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 << make_pair(key, h->at(key));
-      }
-
-      reset_duplicate_key();
-      return *this;
-    }
-    const unordered_map<Expression*, Expression*>& pairs() const { return elements_; }
-    const vector<Expression*>& keys() const { return list_; }
-  };
-  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,
-      FEATURE,
-      ATROOT,
-      BUBBLE,
-      KEYFRAMERULE
-    };
-  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() { return false; }
-    virtual bool   bubbles() { return false; }
-    virtual Block* block()  { return 0; }
-  };
-  inline Statement::~Statement() { }
-
-  ////////////////////////
-  // Blocks of statements.
-  ////////////////////////
-  class Block : public Statement, public Vectorized<Statement*> {
-    ADD_PROPERTY(bool, is_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), has_hoistable_(false), has_non_hoistable_(false)
-    { }
-    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 ~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);
-  public:
-    Ruleset(ParserState pstate, Selector* s, Block* b)
-    : Has_Block(pstate, b), selector_(s)
-    { statement_type(RULESET); }
-    bool is_invisible();
-    // 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);
-    ADD_PROPERTY(Selector*, selector);
-  public:
-    Media_Block(ParserState pstate, List* mqs, Block* b)
-    : Has_Block(pstate, b), media_queries_(mqs), selector_(0)
-    { statement_type(MEDIA); }
-    Media_Block(ParserState pstate, List* mqs, Block* b, Selector* s)
-    : Has_Block(pstate, b), media_queries_(mqs), selector_(s)
-    { statement_type(MEDIA); }
-    bool bubbles() { return true; }
-    bool is_hoistable() { return true; }
-    bool is_invisible() {
-      bool is_invisible = true;
-      for (size_t i = 0, L = block()->length(); i < L && is_invisible; i++)
-        is_invisible &= (*block())[i]->is_invisible();
-      return is_invisible;
-    }
-    ATTACH_OPERATIONS();
-  };
-
-  ///////////////////
-  // Feature queries.
-  ///////////////////
-  class Feature_Block : public Has_Block {
-    ADD_PROPERTY(Feature_Query*, feature_queries);
-    ADD_PROPERTY(Selector*, selector);
-  public:
-    Feature_Block(ParserState pstate, Feature_Query* fqs, Block* b)
-    : Has_Block(pstate, b), feature_queries_(fqs), selector_(0)
-    { statement_type(FEATURE); }
-    bool is_hoistable() { return true; }
-    bool bubbles() { return true; }
-    ATTACH_OPERATIONS();
-  };
-
-  ///////////////////////////////////////////////////////////////////////
-  // At-rules -- arbitrary directives beginning with "@" that may have an
-  // optional statement block.
-  ///////////////////////////////////////////////////////////////////////
-  class At_Rule : public Has_Block {
-    ADD_PROPERTY(string, keyword);
-    ADD_PROPERTY(Selector*, selector);
-    ADD_PROPERTY(Expression*, value);
-  public:
-    At_Rule(ParserState pstate, string kwd, Selector* sel = 0, Block* b = 0)
-    : Has_Block(pstate, b), keyword_(kwd), selector_(sel), value_(0) // 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);
-  public:
-    Declaration(ParserState pstate,
-                String* prop, Expression* val, bool i = false)
-    : Statement(pstate), property_(prop), value_(val), is_important_(i)
-    { }
-    ATTACH_OPERATIONS();
-  };
-
-  /////////////////////////////////////
-  // Assignments -- variable and value.
-  /////////////////////////////////////
-  class Assignment : public Statement {
-    ADD_PROPERTY(string, variable);
-    ADD_PROPERTY(Expression*, value);
-    ADD_PROPERTY(bool, is_default);
-    ADD_PROPERTY(bool, is_global);
-  public:
-    Assignment(ParserState pstate,
-               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)
-    { }
-    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 {
-    vector<string>         files_;
-    vector<Expression*>    urls_;
-  public:
-    Import(ParserState pstate)
-    : Statement(pstate),
-      files_(vector<string>()), urls_(vector<Expression*>())
-    { }
-    vector<string>&         files() { return files_; }
-    vector<Expression*>& urls()     { return urls_; }
-    ATTACH_OPERATIONS();
-  };
-
-  class Import_Stub : public Statement {
-    ADD_PROPERTY(string, file_name);
-  public:
-    Import_Stub(ParserState pstate, string f)
-    : Statement(pstate), file_name_(f)
-    { }
-    ATTACH_OPERATIONS();
-  };
-
-  //////////////////////////////
-  // The Sass `@warn` directive.
-  //////////////////////////////
-  class Warning : public Statement {
-    ADD_PROPERTY(Expression*, message);
-  public:
-    Warning(ParserState pstate, Expression* msg)
-    : Statement(pstate), message_(msg)
-    { }
-    ATTACH_OPERATIONS();
-  };
-
-  ///////////////////////////////
-  // The Sass `@error` directive.
-  ///////////////////////////////
-  class Error : public Statement {
-    ADD_PROPERTY(Expression*, message);
-  public:
-    Error(ParserState pstate, Expression* msg)
-    : Statement(pstate), message_(msg)
-    { }
-    ATTACH_OPERATIONS();
-  };
-
-  ///////////////////////////////
-  // The Sass `@debug` directive.
-  ///////////////////////////////
-  class Debug : public Statement {
-    ADD_PROPERTY(Expression*, value);
-  public:
-    Debug(ParserState pstate, Expression* val)
-    : Statement(pstate), value_(val)
-    { }
-    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)
-    { }
-    ATTACH_OPERATIONS();
-  };
-
-  ////////////////////////////////////
-  // The Sass `@if` control directive.
-  ////////////////////////////////////
-  class If : public Statement {
-    ADD_PROPERTY(Expression*, predicate);
-    ADD_PROPERTY(Block*, consequent);
-    ADD_PROPERTY(Block*, alternative);
-  public:
-    If(ParserState pstate, Expression* pred, Block* con, Block* alt = 0)
-    : Statement(pstate), predicate_(pred), consequent_(con), alternative_(alt)
-    { }
-    ATTACH_OPERATIONS();
-  };
-
-  /////////////////////////////////////
-  // The Sass `@for` control directive.
-  /////////////////////////////////////
-  class For : public Has_Block {
-    ADD_PROPERTY(string, variable);
-    ADD_PROPERTY(Expression*, lower_bound);
-    ADD_PROPERTY(Expression*, upper_bound);
-    ADD_PROPERTY(bool, is_inclusive);
-  public:
-    For(ParserState pstate,
-        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)
-    { }
-    ATTACH_OPERATIONS();
-  };
-
-  //////////////////////////////////////
-  // The Sass `@each` control directive.
-  //////////////////////////////////////
-  class Each : public Has_Block {
-    ADD_PROPERTY(vector<string>, variables);
-    ADD_PROPERTY(Expression*, list);
-  public:
-    Each(ParserState pstate, vector<string> vars, Expression* lst, Block* b)
-    : Has_Block(pstate, b), variables_(vars), list_(lst)
-    { }
-    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)
-    { }
-    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)
-    { }
-    ATTACH_OPERATIONS();
-  };
-
-  ////////////////////////////////
-  // The Sass `@extend` directive.
-  ////////////////////////////////
-  class Extension : public Statement {
-    ADD_PROPERTY(Selector*, selector);
-  public:
-    Extension(ParserState pstate, Selector* s)
-    : Statement(pstate), selector_(s)
-    { }
-    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(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(Context*, ctx);
-    ADD_PROPERTY(bool, is_overload_stub);
-    ADD_PROPERTY(Signature, signature);
-  public:
-    Definition(ParserState pstate,
-               string n,
-               Parameters* params,
-               Block* b,
-               Context* ctx,
-               Type t)
-    : Has_Block(pstate, b),
-      name_(n),
-      parameters_(params),
-      environment_(0),
-      type_(t),
-      native_function_(0),
-      c_function_(0),
-      cookie_(0),
-      ctx_(ctx),
-      is_overload_stub_(false),
-      signature_(0)
-    { }
-    Definition(ParserState pstate,
-               Signature sig,
-               string n,
-               Parameters* params,
-               Native_Function func_ptr,
-               Context* ctx,
-               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),
-      ctx_(ctx),
-      is_overload_stub_(overload_stub),
-      signature_(sig)
-    { }
-    Definition(ParserState pstate,
-               Signature sig,
-               string n,
-               Parameters* params,
-               Sass_Function_Entry c_func,
-               Context* ctx,
-               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)),
-      ctx_(ctx),
-      is_overload_stub_(false),
-      signature_(sig)
-    { }
-    ATTACH_OPERATIONS();
-  };
-
-  //////////////////////////////////////
-  // Mixin calls (i.e., `@include ...`).
-  //////////////////////////////////////
-  class Mixin_Call : public Has_Block {
-    ADD_PROPERTY(string, name);
-    ADD_PROPERTY(Arguments*, arguments);
-  public:
-    Mixin_Call(ParserState pstate, 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) { }
-    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 Expression, public Vectorized<Expression*> {
-    void adjust_after_pushing(Expression* e) { is_expanded(false); }
-  public:
-    enum Separator { SPACE, COMMA };
-  private:
-    ADD_PROPERTY(Separator, separator);
-    ADD_PROPERTY(bool, is_arglist);
-  public:
-    List(ParserState pstate,
-         size_t size = 0, Separator sep = SPACE, bool argl = false)
-    : Expression(pstate),
-      Vectorized<Expression*>(size),
-      separator_(sep), is_arglist_(argl)
-    { concrete_type(LIST); }
-    string type() { return is_arglist_ ? "arglist" : "list"; }
-    static string type_name() { return "list"; }
-    bool is_invisible() { return !length(); }
-    Expression* value_at_index(size_t i);
-
-    virtual size_t size() const;
-    virtual bool operator==(Expression& rhs) const;
-    virtual bool operator==(Expression* rhs) const;
-
-    virtual size_t hash()
-    {
-      if (hash_ > 0) return hash_;
-
-      hash_ = std::hash<string>()(separator() == COMMA ? "comma" : "space");
-
-      for (size_t i = 0, L = length(); i < L; ++i)
-        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);
-    }
-
-    ATTACH_OPERATIONS();
-  };
-
-  ///////////////////////////////////////////////////////////////////////
-  // Key value paris.
-  ///////////////////////////////////////////////////////////////////////
-  class Map : public Expression, public Hashed {
-    void adjust_after_pushing(std::pair<Expression*, Expression*> p) { is_expanded(false); }
-  public:
-    Map(ParserState pstate,
-         size_t size = 0)
-    : Expression(pstate),
-      Hashed(size)
-    { concrete_type(MAP); }
-    string type() { return "map"; }
-    static string type_name() { return "map"; }
-    bool is_invisible() { return !length(); }
-
-    virtual bool operator==(Expression& rhs) const
-    {
-      try
-      {
-        Map& m = dynamic_cast<Map&>(rhs);
-        if (!(m && length() == m.length())) return false;
-        for (auto key : keys())
-          if (!(*at(key) == *m.at(key))) return false;
-        return true;
-      }
-      catch (std::bad_cast&)
-      {
-        return false;
-      }
-      catch (...) { throw; }
-    }
-
-    virtual size_t hash()
-    {
-      if (hash_ > 0) return hash_;
-
-      for (auto key : keys())
-        hash_ ^= key->hash() ^ at(key)->hash();
-
-      return hash_;
-    }
-
-    ATTACH_OPERATIONS();
-  };
-
-  //////////////////////////////////////////////////////////////////////////
-  // Binary expressions. Represents logical, relational, and arithmetic
-  // operations. Templatized to avoid large switch statements and repetitive
-  // subclassing.
-  //////////////////////////////////////////////////////////////////////////
-  class Binary_Expression : public Expression {
-  public:
-    enum Type {
-      AND, OR,                   // logical connectives
-      EQ, NEQ, GT, GTE, LT, LTE, // arithmetic relations
-      ADD, SUB, MUL, DIV, MOD,   // arithmetic functions
-      NUM_OPS                    // so we know how big to make the op table
-    };
-  private:
-    ADD_PROPERTY(Type, type);
-    ADD_PROPERTY(Expression*, left);
-    ADD_PROPERTY(Expression*, right);
-    size_t hash_;
-  public:
-    Binary_Expression(ParserState pstate,
-                      Type t, Expression* lhs, Expression* rhs)
-    : Expression(pstate), type_(t), left_(lhs), right_(rhs), hash_(0)
-    { }
-    const string type_name() {
-      switch (type_) {
-        case AND: return "and"; break;
-        case OR: return "or"; break;
-        case EQ: return "eq"; break;
-        case NEQ: return "neq"; break;
-        case GT: return "gt"; break;
-        case GTE: return "gte"; break;
-        case LT: return "lt"; break;
-        case LTE: return "lte"; break;
-        case ADD: return "add"; break;
-        case SUB: return "sub"; break;
-        case MUL: return "mul"; break;
-        case DIV: return "div"; break;
-        case MOD: return "mod"; break;
-        case NUM_OPS: return "num_ops"; break;
-        default: return "invalid"; break;
-      }
-    }
-    virtual void set_delayed(bool delayed)
-    {
-      right()->set_delayed(delayed);
-      left()->set_delayed(delayed);
-      is_delayed(delayed);
-    }
-    virtual bool operator==(Expression& rhs) const
-    {
-      try
-      {
-        Binary_Expression& m = dynamic_cast<Binary_Expression&>(rhs);
-        if (m == 0) return false;
-        return type() == m.type() &&
-               left() == m.left() &&
-               right() == m.right();
-      }
-      catch (std::bad_cast&)
-      {
-        return false;
-      }
-      catch (...) { throw; }
-    }
-    virtual size_t hash()
-    {
-      if (hash_ > 0) return hash_;
-      hash_ = left()->hash() ^ right()->hash() ^ std::hash<size_t>()(type_);
-      return hash_;
-    }
-    ATTACH_OPERATIONS();
-  };
-
-  ////////////////////////////////////////////////////////////////////////////
-  // Arithmetic negation (logical negation is just an ordinary function call).
-  ////////////////////////////////////////////////////////////////////////////
-  class Unary_Expression : public Expression {
-  public:
-    enum Type { PLUS, MINUS, NOT };
-  private:
-    ADD_PROPERTY(Type, type);
-    ADD_PROPERTY(Expression*, operand);
-    size_t hash_;
-  public:
-    Unary_Expression(ParserState pstate, Type t, Expression* o)
-    : Expression(pstate), type_(t), operand_(o), hash_(0)
-    { }
-    const string type_name() {
-      switch (type_) {
-        case PLUS: return "plus"; break;
-        case MINUS: return "minus"; break;
-        case NOT: return "not"; break;
-        default: return "invalid"; break;
-      }
-    }
-    virtual bool operator==(Expression& rhs) const
-    {
-      try
-      {
-        Unary_Expression& m = dynamic_cast<Unary_Expression&>(rhs);
-        if (m == 0) return false;
-        return type() == m.type() &&
-               operand() == m.operand();
-      }
-      catch (std::bad_cast&)
-      {
-        return false;
-      }
-      catch (...) { throw; }
-    }
-    virtual size_t hash()
-    {
-      if (hash_ > 0) return hash_;
-      hash_ = operand()->hash() ^ std::hash<size_t>()(type_);
-      return hash_;
-    }
-    ATTACH_OPERATIONS();
-  };
-
-  ////////////////////////////////////////////////////////////
-  // Individual argument objects for mixin and function calls.
-  ////////////////////////////////////////////////////////////
-  class Argument : public Expression {
-    ADD_PROPERTY(Expression*, value);
-    ADD_PROPERTY(string, name);
-    ADD_PROPERTY(bool, is_rest_argument);
-    ADD_PROPERTY(bool, is_keyword_argument);
-    size_t hash_;
-  public:
-    Argument(ParserState pstate, Expression* val, 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==(Expression& rhs) const
-    {
-      try
-      {
-        Argument& m = dynamic_cast<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) return hash_;
-
-      hash_ = std::hash<string>()(name()) ^ 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)
-    {
-      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());
-        }
-      }
-    }
-  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_PROPERTY(string, name);
-    ADD_PROPERTY(Arguments*, arguments);
-    ADD_PROPERTY(void*, cookie);
-    size_t hash_;
-  public:
-    Function_Call(ParserState pstate, string n, Arguments* args, void* cookie)
-    : Expression(pstate), name_(n), arguments_(args), cookie_(cookie), hash_(0)
-    { concrete_type(STRING); }
-    Function_Call(ParserState pstate, string n, Arguments* args)
-    : Expression(pstate), name_(n), arguments_(args), cookie_(0), hash_(0)
-    { concrete_type(STRING); }
-
-    virtual bool operator==(Expression& rhs) const
-    {
-      try
-      {
-        Function_Call& m = dynamic_cast<Function_Call&>(rhs);
-        if (!(m && name() == m.name())) return false;
-        if (!(m && arguments()->length() == m.arguments()->length())) return false;
-        for (size_t i =0, L = arguments()->length(); i < L; ++i)
-          if (!((*arguments())[i] == (*m.arguments())[i])) return false;
-        return true;
-      }
-      catch (std::bad_cast&)
-      {
-        return false;
-      }
-      catch (...) { throw; }
-    }
-
-    virtual size_t hash()
-    {
-      if (hash_ > 0) return hash_;
-
-      hash_ = std::hash<string>()(name());
-      for (auto argument : arguments()->elements())
-        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(string, name);
-  public:
-    Variable(ParserState pstate, string n)
-    : Expression(pstate), name_(n)
-    { }
-
-    virtual bool operator==(Expression& rhs) const
-    {
-      try
-      {
-        Variable& e = dynamic_cast<Variable&>(rhs);
-        return e && name() == e.name();
-      }
-      catch (std::bad_cast&)
-      {
-        return false;
-      }
-      catch (...) { throw; }
-    }
-
-    virtual size_t hash()
-    {
-      return std::hash<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_PROPERTY(Type, type);
-    ADD_PROPERTY(string, value);
-    size_t hash_;
-  public:
-    Textual(ParserState pstate, Type t, string val)
-    : Expression(pstate, true), type_(t), value_(val),
-      hash_(0)
-    { }
-
-    virtual bool operator==(Expression& rhs) const
-    {
-      try
-      {
-        Textual& e = dynamic_cast<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<string>()(value_) ^ std::hash<int>()(type_);
-      return hash_;
-    }
-
-    ATTACH_OPERATIONS();
-  };
-
-  ////////////////////////////////////////////////
-  // Numbers, percentages, dimensions, and colors.
-  ////////////////////////////////////////////////
-  class Number : public Expression {
-    ADD_PROPERTY(double, value);
-    ADD_PROPERTY(bool, zero);
-    vector<string> numerator_units_;
-    vector<string> denominator_units_;
-    size_t hash_;
-  public:
-    Number(ParserState pstate, double val, string u = "", bool zero = true);
-    bool            zero()              { return zero_; }
-    vector<string>& numerator_units()   { return numerator_units_; }
-    vector<string>& denominator_units() { return denominator_units_; }
-    string type() { return "number"; }
-    static string type_name() { return "number"; }
-    string unit() const;
-
-    bool is_unitless();
-    void convert(const string& unit = "");
-    void normalize(const string& unit = "");
-    // useful for making one number compatible with another
-    string find_convertible_unit() const;
-
-    virtual bool operator== (Expression& rhs) const;
-    virtual bool operator== (Expression* rhs) const;
-
-    virtual size_t hash()
-    {
-      if (hash_ == 0) hash_ = std::hash<double>()(value_);
-      return hash_;
-    }
-
-    ATTACH_OPERATIONS();
-  };
-
-  //////////
-  // Colors.
-  //////////
-  class Color : public Expression {
-    ADD_PROPERTY(double, r);
-    ADD_PROPERTY(double, g);
-    ADD_PROPERTY(double, b);
-    ADD_PROPERTY(double, a);
-    ADD_PROPERTY(bool, sixtuplet);
-    ADD_PROPERTY(string, disp);
-    size_t hash_;
-  public:
-    Color(ParserState pstate, double r, double g, double b, double a = 1, bool sixtuplet = true, const string disp = "")
-    : Expression(pstate), r_(r), g_(g), b_(b), a_(a), sixtuplet_(sixtuplet), disp_(disp),
-      hash_(0)
-    { concrete_type(COLOR); }
-    string type() { return "color"; }
-    static string type_name() { return "color"; }
-
-    virtual bool operator==(Expression& rhs) const
-    {
-      try
-      {
-        Color& c = (dynamic_cast<Color&>(rhs));
-        return c && r() == c.r() && g() == c.g() && b() == c.b() && a() == c.a();
-      }
-      catch (std::bad_cast&)
-      {
-        return false;
-      }
-      catch (...) { throw; }
-    }
-
-    virtual size_t hash()
-    {
-      if (hash_ == 0) hash_ = std::hash<double>()(r_) ^ std::hash<double>()(g_) ^ std::hash<double>()(b_) ^ std::hash<double>()(a_);
-      return hash_;
-    }
-
-    ATTACH_OPERATIONS();
-  };
-
-  ////////////
-  // Booleans.
-  ////////////
-  class Boolean : public Expression {
-    ADD_PROPERTY(bool, value);
-    size_t hash_;
-  public:
-    Boolean(ParserState pstate, bool val)
-    : Expression(pstate), value_(val),
-      hash_(0)
-    { concrete_type(BOOLEAN); }
-    virtual operator bool() { return value_; }
-    string type() { return "bool"; }
-    static string type_name() { return "bool"; }
-    virtual bool is_false() { return !value_; }
-
-    virtual bool operator==(Expression& rhs) const
-    {
-      try
-      {
-        Boolean& e = dynamic_cast<Boolean&>(rhs);
-        return e && value() == e.value();
-      }
-      catch (std::bad_cast&)
-      {
-        return false;
-      }
-      catch (...) { throw; }
-    }
-
-    virtual size_t hash()
-    {
-      if (hash_ == 0) hash_ = std::hash<bool>()(value_);
-      return hash_;
-    }
-
-    ATTACH_OPERATIONS();
-  };
-
-  ////////////////////////////////////////////////////////////////////////
-  // Abstract base class for Sass string values. Includes interpolated and
-  // "flat" strings.
-  ////////////////////////////////////////////////////////////////////////
-  class String : public Expression {
-    ADD_PROPERTY(bool, sass_fix_1291);
-  public:
-    String(ParserState pstate, bool delayed = false, bool sass_fix_1291 = false)
-    : Expression(pstate, delayed), sass_fix_1291_(sass_fix_1291)
-    { concrete_type(STRING); }
-    static string type_name() { return "string"; }
-    virtual ~String() = 0;
-    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)
-    { }
-    string type() { return "string"; }
-    static string type_name() { return "string"; }
-
-    virtual bool operator==(Expression& rhs) const
-    {
-      try
-      {
-        String_Schema& e = dynamic_cast<String_Schema&>(rhs);
-        if (!(e && length() == e.length())) return false;
-        for (size_t i = 0, L = length(); i < L; ++i)
-          if (!((*this)[i] == e[i])) return false;
-        return true;
-      }
-      catch (std::bad_cast&)
-      {
-        return false;
-      }
-      catch (...) { throw; }
-    }
-
-    virtual size_t hash()
-    {
-      if (hash_ > 0) return hash_;
-
-      for (auto string : elements())
-        hash_ ^= string->hash();
-
-      return hash_;
-    }
-
-    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_PROPERTY(string, value);
-  protected:
-    size_t hash_;
-  public:
-    String_Constant(ParserState pstate, 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(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(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(string(tok.begin, tok.end))), hash_(0)
-    { }
-    string type() { return "string"; }
-    static string type_name() { return "string"; }
-
-    virtual bool operator==(Expression& rhs) const
-    {
-      try
-      {
-        String_Constant& e = dynamic_cast<String_Constant&>(rhs);
-        return e && value_ == e.value_;
-      }
-      catch (std::bad_cast&)
-      {
-        return false;
-      }
-      catch (...) { throw; }
-    }
-
-    virtual size_t hash()
-    {
-      if (hash_ == 0) hash_ = std::hash<string>()(value_);
-      return hash_;
-    }
-
-    // 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, string val)
-    : String_Constant(pstate, val)
-    {
-      value_ = unquote(value_, &quote_mark_);
-    }
-    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();
-  };
-
-  ///////////////////
-  // Feature queries.
-  ///////////////////
-  class Feature_Query : public Expression, public Vectorized<Feature_Query_Condition*> {
-  public:
-    Feature_Query(ParserState pstate, size_t s = 0)
-    : Expression(pstate), Vectorized<Feature_Query_Condition*>(s)
-    { }
-    ATTACH_OPERATIONS();
-  };
-
-  ////////////////////////////////////////////////////////
-  // Feature expressions (for use inside feature queries).
-  ////////////////////////////////////////////////////////
-  class Feature_Query_Condition : public Expression, public Vectorized<Feature_Query_Condition*> {
-  public:
-    enum Operand { NONE, AND, OR, NOT };
-  private:
-    ADD_PROPERTY(String*, feature);
-    ADD_PROPERTY(Expression*, value);
-    ADD_PROPERTY(Operand, operand);
-    ADD_PROPERTY(bool, is_root);
-  public:
-    Feature_Query_Condition(ParserState pstate, size_t s = 0, String* f = 0,
-                            Expression* v = 0, Operand o = NONE, bool r = false)
-    : Expression(pstate), Vectorized<Feature_Query_Condition*>(s),
-      feature_(f), value_(v), operand_(o), is_root_(r)
-    { }
-    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(string str)
-    {
-      To_String to_string;
-      bool with = feature() && unquote(feature()->perform(&to_string)).compare("with") == 0;
-      List* l = static_cast<List*>(value());
-      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::FEATURE)
-      {
-        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 Expression {
-  public:
-    Null(ParserState pstate) : Expression(pstate) { concrete_type(NULL_VAL); }
-    string type() { return "null"; }
-    static string type_name() { return "null"; }
-    bool is_invisible() { return true; }
-    operator bool() { return false; }
-    bool is_false() { return true; }
-
-    virtual bool operator==(Expression& rhs) const
-    {
-      return rhs.concrete_type() == NULL_VAL;
-    }
-
-    virtual size_t hash()
-    {
-      return 0;
-    }
-
-    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(string, name);
-    ADD_PROPERTY(Expression*, default_value);
-    ADD_PROPERTY(bool, is_rest_parameter);
-  public:
-    Parameter(ParserState pstate,
-              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();
-  };
-
-  //////////////////////////////////////////////////////////////////////////////////////////
-  // Additional method on Lists to retrieve values directly or from an encompassed Argument.
-  //////////////////////////////////////////////////////////////////////////////////////////
-  inline Expression* List::value_at_index(size_t i) { return is_arglist_ ? ((Argument*)(*this)[i])->value() : (*this)[i]; }
-
-  ////////////
-  // The Parent Selector Expression.
-  ////////////
-  class Parent_Selector : public Expression {
-    ADD_PROPERTY(Selector*, selector);
-  public:
-    Parent_Selector(ParserState pstate, Selector* r = 0)
-    : Expression(pstate), selector_(r)
-    { concrete_type(SELECTOR); }
-    virtual Selector* selector() { return selector_; }
-    string type() { return "selector"; }
-    static string type_name() { return "selector"; }
-
-    ATTACH_OPERATIONS();
-  };
-
-  /////////////////////////////////////////
-  // Abstract base class for CSS selectors.
-  /////////////////////////////////////////
-  class Selector : public AST_Node {
-    ADD_PROPERTY(bool, has_reference);
-    ADD_PROPERTY(bool, has_placeholder);
-    // line break before list separator
-    ADD_PROPERTY(bool, has_line_feed);
-    // line break after list separator
-    ADD_PROPERTY(bool, has_line_break);
-    // maybe we have optional flag
-    ADD_PROPERTY(bool, is_optional);
-    // parent block pointers
-    ADD_PROPERTY(Block*, last_block);
-    ADD_PROPERTY(Media_Block*, media_block);
-  public:
-    Selector(ParserState pstate, bool r = false, bool h = false)
-    : AST_Node(pstate),
-      has_reference_(r),
-      has_placeholder_(h),
-      has_line_feed_(false),
-      has_line_break_(false),
-      is_optional_(false),
-      media_block_(0)
-    { }
-    virtual ~Selector() = 0;
-    // virtual Selector_Placeholder* find_placeholder();
-    virtual unsigned long specificity() {
-      return Constants::Specificity_Universal;
-    };
-  };
-  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);
-  public:
-    Selector_Schema(ParserState pstate, String* c)
-    : Selector(pstate), contents_(c)
-    { }
-    ATTACH_OPERATIONS();
-  };
-
-  ////////////////////////////////////////////
-  // Abstract base class for simple selectors.
-  ////////////////////////////////////////////
-  class Simple_Selector : public Selector {
-  public:
-    Simple_Selector(ParserState pstate)
-    : Selector(pstate)
-    { }
-    virtual ~Simple_Selector() = 0;
-    virtual Compound_Selector* unify_with(Compound_Selector*, Context&);
-    virtual bool is_pseudo_element() { return false; }
-    virtual bool is_pseudo_class() { 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;
-  };
-  inline Simple_Selector::~Simple_Selector() { }
-
-  /////////////////////////////////////
-  // Parent references (i.e., the "&").
-  /////////////////////////////////////
-  class Selector_Reference : public Simple_Selector {
-    ADD_PROPERTY(Selector*, selector);
-  public:
-    Selector_Reference(ParserState pstate, Selector* r = 0)
-    : Simple_Selector(pstate), selector_(r)
-    { has_reference(true); }
-    virtual unsigned long specificity()
-    {
-      if (!selector()) return 0;
-      return selector()->specificity();
-    }
-    ATTACH_OPERATIONS();
-  };
-
-  /////////////////////////////////////////////////////////////////////////
-  // Placeholder selectors (e.g., "%foo") for use in extend-only selectors.
-  /////////////////////////////////////////////////////////////////////////
-  class Selector_Placeholder : public Simple_Selector {
-    ADD_PROPERTY(string, name);
-  public:
-    Selector_Placeholder(ParserState pstate, string n)
-    : Simple_Selector(pstate), name_(n)
-    { has_placeholder(true); }
-    // virtual Selector_Placeholder* find_placeholder();
-    ATTACH_OPERATIONS();
-  };
-
-  /////////////////////////////////////////////////////////////////////
-  // Type selectors (and the universal selector) -- e.g., div, span, *.
-  /////////////////////////////////////////////////////////////////////
-  class Type_Selector : public Simple_Selector {
-    ADD_PROPERTY(string, name);
-  public:
-    Type_Selector(ParserState pstate, string n)
-    : Simple_Selector(pstate), name_(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 Compound_Selector* unify_with(Compound_Selector*, Context&);
-    ATTACH_OPERATIONS();
-  };
-
-  ////////////////////////////////////////////////
-  // Selector qualifiers -- i.e., classes and ids.
-  ////////////////////////////////////////////////
-  class Selector_Qualifier : public Simple_Selector {
-    ADD_PROPERTY(string, name);
-  public:
-    Selector_Qualifier(ParserState pstate, string n)
-    : Simple_Selector(pstate), name_(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(string, name);
-    ADD_PROPERTY(string, matcher);
-    ADD_PROPERTY(String*, value); // might be interpolated
-  public:
-    Attribute_Selector(ParserState pstate, string n, string m, String* v)
-    : Simple_Selector(pstate), name_(n), matcher_(m), value_(v)
-    { }
-    virtual unsigned long specificity()
-    {
-      return Constants::Specificity_Attr;
-    }
-    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 string& name)
-  {
-    return name == ":before"       ||
-           name == ":after"        ||
-           name == ":first-line"   ||
-           name == ":first-letter";
-  }
-
-  class Pseudo_Selector : public Simple_Selector {
-    ADD_PROPERTY(string, name);
-    ADD_PROPERTY(String*, expression);
-  public:
-    Pseudo_Selector(ParserState pstate, string n, String* expr = 0)
-    : Simple_Selector(pstate), name_(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(string, name);
-    ADD_PROPERTY(Selector*, selector);
-  public:
-    Wrapped_Selector(ParserState pstate, string n, Selector* sel)
-    : Simple_Selector(pstate), name_(n), selector_(sel)
-    { }
-    // 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;
-    }
-    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 set<Complex_Selector*, Complex_Selector_Pointer_Compare> SourcesSet;
-  class Compound_Selector : public Selector, public Vectorized<Simple_Selector*> {
-  private:
-    SourcesSet sources_;
-  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)
-    { }
-
-    Compound_Selector* unify_with(Compound_Selector* rhs, Context& ctx);
-    // virtual Selector_Placeholder* find_placeholder();
-    Simple_Selector* base()
-    {
-      // Implement non-const in terms of const. Safe to const_cast since this method is non-const
-      return const_cast<Simple_Selector*>(static_cast<const Compound_Selector*>(this)->base());
-    }
-    const Simple_Selector* base() const {
-      if (length() > 0 && typeid(*(*this)[0]) == typeid(Type_Selector))
-        return (*this)[0];
-      return 0;
-    }
-    bool is_superselector_of(Compound_Selector* sub);
-    // bool is_superselector_of(Complex_Selector* sub);
-    // bool is_superselector_of(Selector_List* sub);
-    virtual unsigned long specificity()
-    {
-      int sum = 0;
-      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(Selector_Reference) &&
-             !static_cast<Selector_Reference*>((*this)[0])->selector();
-    }
-    vector<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);
-    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 };
-  private:
-    ADD_PROPERTY(Combinator, combinator);
-    ADD_PROPERTY(Compound_Selector*, head);
-    ADD_PROPERTY(Complex_Selector*, tail);
-  public:
-    Complex_Selector(ParserState pstate,
-                     Combinator c,
-                     Compound_Selector* h,
-                     Complex_Selector* t)
-    : Selector(pstate), combinator_(c), head_(h), tail_(t)
-    {
-      if ((h && h->has_reference())   || (t && t->has_reference()))   has_reference(true);
-      if ((h && h->has_placeholder()) || (t && t->has_placeholder())) has_placeholder(true);
-    }
-    Compound_Selector* base();
-    Complex_Selector* context(Context&);
-    Complex_Selector* innermost();
-    size_t length();
-    bool is_superselector_of(Compound_Selector* sub);
-    bool is_superselector_of(Complex_Selector* sub);
-    bool is_superselector_of(Selector_List* sub);
-    // virtual Selector_Placeholder* find_placeholder();
-    Combinator clear_innermost();
-    void set_innermost(Complex_Selector*, Combinator);
-    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
-    // vector<Compound_Selector*> to_vector();
-    ATTACH_OPERATIONS();
-  };
-
-  typedef deque<Complex_Selector*> ComplexSelectorDeque;
-
-  ///////////////////////////////////
-  // Comma-separated selector groups.
-  ///////////////////////////////////
-  class Selector_List : public Selector, public Vectorized<Complex_Selector*> {
-#ifdef DEBUG
-    ADD_PROPERTY(string, mCachedSelector);
-#endif
-    ADD_PROPERTY(vector<string>, wspace);
-  protected:
-    void adjust_after_pushing(Complex_Selector* c);
-  public:
-    Selector_List(ParserState pstate, size_t s = 0)
-    : Selector(pstate), Vectorized<Complex_Selector*>(s), wspace_(0)
-    { }
-    // virtual Selector_Placeholder* find_placeholder();
-    bool is_superselector_of(Compound_Selector* sub);
-    bool is_superselector_of(Complex_Selector* sub);
-    bool is_superselector_of(Selector_List* sub);
-    virtual unsigned long specificity()
-    {
-      unsigned long sum = 0;
-      for (size_t i = 0, L = length(); i < L; ++i)
-      { sum += (*this)[i]->specificity(); }
-      return sum;
-    }
-    // vector<Complex_Selector*> members() { return elements_; }
-    ATTACH_OPERATIONS();
-  };
-
-  inline bool Ruleset::is_invisible() {
-    bool is_invisible = true;
-    Selector_List* sl = static_cast<Selector_List*>(selector());
-    for (size_t i = 0, L = sl->length(); i < L && is_invisible; ++i)
-      is_invisible &= (*sl)[i]->has_placeholder();
-    return is_invisible;
-  }
-
-
-  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;
-    }
-  }
-
-}
-
-#ifdef __clang__
-
-#pragma clang diagnostic pop
-
-#endif
-
-#endif
diff --git a/libsass/ast_def_macros.hpp b/libsass/ast_def_macros.hpp
deleted file mode 100644
--- a/libsass/ast_def_macros.hpp
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifndef SASS_AST_DEF_MACROS_H
-#define SASS_AST_DEF_MACROS_H
-
-#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 string perform(Operation<string>* op) { return (*op)(this); }\
-virtual Sass_Value* perform(Operation<Sass_Value*>* op) { return (*op)(this); }
-
-#define ADD_PROPERTY(type, name)\
-protected:\
-  type name##_;\
-public:\
-  type name() const        { return name##_; }\
-  type name(type name##__) { return name##_ = name##__; }\
-private:
-
-#endif
diff --git a/libsass/ast_factory.hpp b/libsass/ast_factory.hpp
deleted file mode 100644
--- a/libsass/ast_factory.hpp
+++ /dev/null
@@ -1,92 +0,0 @@
-#ifndef SASS_AST_FACTORY_H
-#define SASS_AST_FACTORY_H
-
-#include <vector>
-
-#include "ast.hpp"
-
-namespace Sass {
-  using namespace std;
-
-  class AST_Factory {
-    vector<AST_Node*> nodes;
-  public:
-    // statements
-    Block* new_Block(string p, size_t l, size_t s = 0, bool r = false);
-    Ruleset* new_Ruleset(string p, size_t l, Selector* s, Block* b);
-    Propset* new_Propset(string p, size_t l, String* pf, Block* b);
-    Feature_Query* new_Feature_Query(string p, size_t l, Feature_Query* f, Block* b);
-    Media_Query* new_Media_Query(string p, size_t l, List* q, Block* b);
-    At_Root_Block* new_At_Root_Block(string p, size_t l, Selector* sel, Block* b);
-    At_Rule* new_At_Rule(string p, size_t l, string kwd, Selector* sel, Block* b);
-    Keyframe_Rule* new_Keyframe_Rule(string p, size_t l, Block* b);
-    Declaration* new_Declaration(string p, size_t l, String* prop, List* vals);
-    Assignment* new_Assignment(string p, size_t l, string var, Expression* val, bool guarded = false);
-    Import<Function_Call*>* new_CSS_Import(string p, size_t l, Function_Call* loc);
-    Import<String*>* new_SASS_Import(string p, size_t l, String* loc);
-    Warning* new_Warning(string p, size_t l, Expression* msg);
-    Error* new_Error(string p, size_t l, Expression* msg);
-    Debug* new_Debug(string p, size_t l, Expression* val);
-    Comment* new_Comment(string p, size_t l, String* txt);
-    If* new_If(string p, size_t l, Expression* pred, Block* con, Block* alt = 0);
-    For* new_For(string p, size_t l, string var, Expression* lo, Expression* hi, Block* b, bool inc);
-    Each* new_Each(string p, size_t l, vector<string> vars, Expression* lst, Block* b);
-    While* new_While(string p, size_t l, Expression* pred, Block* b);
-    Extension* new_Extension(string p, size_t l, Selector* s);
-    Definition<MIXIN>* new_Mixin_Definition(string p, size_t l, string n, Parameters* params, Block* b);
-    Definition<FUNCTION>* new_Function_Definition(string p, size_t l, string n, Parameters* params, Block* b);
-    Mixin_Call* new_Mixin_Call(string p, size_t l, string n, Arguments* args, Block* b = 0);
-    // expressions
-    List* new_List(string p, size_t l, size_t size = 0, List::Separator sep = List::space, bool argl = false);
-    Map* new_Map(string p, size_t l, size_t size = 0);
-    Binary_Expression<AND>* new_And(string p, size_t l, Expression* lhs, Expression* rhs);
-    Binary_Expression<OR>* new_Or(string p, size_t l, Expression* lhs, Expression* rhs);
-    Binary_Expression<EQ>* new_Eq(string p, size_t l, Expression* lhs, Expression* rhs);
-    Binary_Expression<NEQ>* new_Neq(string p, size_t l, Expression* lhs, Expression* rhs);
-    Binary_Expression<GT>* new_Gt(string p, size_t l, Expression* lhs, Expression* rhs);
-    Binary_Expression<GTE>* new_Gte(string p, size_t l, Expression* lhs, Expression* rhs);
-    Binary_Expression<LT>* new_Lt(string p, size_t l, Expression* lhs, Expression* rhs);
-    Binary_Expression<LTE>* new_Lte(string p, size_t l, Expression* lhs, Expression* rhs);
-    Binary_Expression<ADD>* new_Add(string p, size_t l, Expression* lhs, Expression* rhs);
-    Binary_Expression<SUB>* new_Sub(string p, size_t l, Expression* lhs, Expression* rhs);
-    Binary_Expression<MUL>* new_Mul(string p, size_t l, Expression* lhs, Expression* rhs);
-    Binary_Expression<DIV>* new_Div(string p, size_t l, Expression* lhs, Expression* rhs);
-    Negation* new_Negation(string p, size_t l, Expression* o);
-    Function_Call* new_Function_Call(string p, size_t l, String* n, Arguments* args);
-    Variable* new_Variable(string p, size_t l, string n);
-    Textual<NUMBER>* new_Textual_Number(string p, size_t l, string val);
-    Textual<PERCENTAGE>* new_Textual_Percentage(string p, size_t l, string val);
-    Textual<DIMENSION>* new_Textual_Dimension(string p, size_t l, string val);
-    Textual<HEX>* new_Textual_Hex(string p, size_t l, string val);
-    Number* new_Number(string p, size_t l, double val);
-    Percentage* new_Percentage(string p, size_t l, double val);
-    Dimension* new_Dimension(string p, size_t l, double val, string unit);
-    Color* new_Color(string p, size_t l, double r, double g, double b, double a = 1, string disp = "");
-    Boolean* new_Boolean(string p, size_t l, bool val);
-    String_Schema* new_String_Schema(string p, size_t l, size_t size = 0);
-    String_Constant* new_String_Constant(string p, size_t l, string val);
-    String_Constant* new_String_Constant(string p, size_t l, const char* beg);
-    String_Constant* new_String_Constant(string p, size_t l, const char* beg, const char* end);
-    Feature_Query_Condition* new_Feature_Query_Condition(string p, size_t l, String* f, Expression* v);
-    Media_Expression* new_Media_Expression(string p, size_t l, String* f, Expression* v);
-    Parent_Selector* new_Parent_Selector(string p, size_t l, Selector* s);
-    // parameters and arguments
-    Parameter* new_Parameter(string p, size_t l, string n, Expression* def = 0, bool rest = false);
-    Parameters* new_Parameters(string p, size_t l);
-    Argument* new_Argument(string p, size_t l, Expression* val, string n = "", bool rest = false);
-    Arguments* new_Arguments(string p, size_t l);
-    // selectors
-    Selector_Schema* new_Selector_Schema(string p, size_t l, String* c);
-    Attribute_Selector* new_Attribute_Selector(string p, size_t l, string n, string m, String* v);
-    Simple_Selector* new_Simple_Selector(string p, size_t l, string c);
-    Reference_Selector* new_Reference_Selector(string p, size_t l);
-    Placeholder_Selector* new_Placeholder_Selector(string p, size_t l, string n);
-    Pseudo_Selector* new_Pseudo_Selector(string p, size_t l, string n, Expression* expr = 0);
-    Wrapped_Selector* new_Wrapped_Selector(string p, size_t l, string n, Simple_Base* sel);
-    Compound_Selector* new_Compound_Selector(string p, size_t l, size_t s = 0);
-    Complex_Selector* new_Complex_Selector(string p, size_t l, Complex_Selector::Combinator c, Complex_Selector* ctx, Compound_Selector* sel);
-    Selector_List* new_Selector_List(string p, size_t l, size_t s = 0);
-  };
-}
-
-#endif
diff --git a/libsass/ast_fwd_decl.hpp b/libsass/ast_fwd_decl.hpp
deleted file mode 100644
--- a/libsass/ast_fwd_decl.hpp
+++ /dev/null
@@ -1,85 +0,0 @@
-#ifndef SASS_AST_FWD_DECL_H
-#define SASS_AST_FWD_DECL_H
-
-/////////////////////////////////////////////
-// Forward declarations for the AST visitors.
-/////////////////////////////////////////////
-namespace Sass {
-
-  enum Output_Style { NESTED, EXPANDED, COMPACT, COMPRESSED, FORMATTED };
-
-  class AST_Node;
-  // statements
-  class Statement;
-  class Block;
-  class Ruleset;
-  class Propset;
-  class Bubble;
-  class Media_Block;
-  class Feature_Block;
-  class At_Rule;
-  class Keyframe_Rule;
-  class At_Root_Block;
-  class Declaration;
-  class Assignment;
-  class Import;
-  class Import_Stub;
-  class Warning;
-  class Error;
-  class Debug;
-  class Comment;
-  class If;
-  class For;
-  class Each;
-  class While;
-  class Return;
-  class Content;
-  class Extension;
-  class Definition;
-  class Mixin_Call;
-  // expressions
-  class Expression;
-  class List;
-  class Map;
-  class Binary_Expression;
-  class Unary_Expression;
-  class Function_Call;
-  class Function_Call_Schema;
-  class Variable;
-  class Textual;
-  class Number;
-  class Color;
-  class Boolean;
-  class String_Schema;
-  class String;
-  class String_Constant;
-  class String_Quoted;
-  class Media_Query;
-  class Media_Query_Expression;
-  class Feature_Query;
-  class Feature_Query_Condition;
-  class At_Root_Expression;
-  class Null;
-  class Parent_Selector;
-  // parameters and arguments
-  class Parameter;
-  class Parameters;
-  class Argument;
-  class Arguments;
-  // selectors
-  class Selector;
-  class Selector_Schema;
-  class Selector_Reference;
-  class Selector_Placeholder;
-  class Type_Selector;
-  class Selector_Qualifier;
-  class Attribute_Selector;
-  class Pseudo_Selector;
-  class Wrapped_Selector;
-  class Compound_Selector;
-  class Complex_Selector;
-  class Selector_List;
-
-}
-
-#endif
diff --git a/libsass/b64/cencode.h b/libsass/b64/cencode.h
deleted file mode 100644
--- a/libsass/b64/cencode.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
-cencode.h - c header for a base64 encoding algorithm
-
-This is part of the libb64 project, and has been placed in the public domain.
-For details, see http://sourceforge.net/projects/libb64
-*/
-
-#ifndef BASE64_CENCODE_H
-#define BASE64_CENCODE_H
-
-typedef enum
-{
-	step_A, step_B, step_C
-} base64_encodestep;
-
-typedef struct
-{
-	base64_encodestep step;
-	char result;
-	int stepcount;
-} base64_encodestate;
-
-void base64_init_encodestate(base64_encodestate* state_in);
-
-char base64_encode_value(char value_in);
-
-int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in);
-
-int base64_encode_blockend(char* code_out, base64_encodestate* state_in);
-
-#endif /* BASE64_CENCODE_H */
-
diff --git a/libsass/b64/encode.h b/libsass/b64/encode.h
deleted file mode 100644
--- a/libsass/b64/encode.h
+++ /dev/null
@@ -1,77 +0,0 @@
-// :mode=c++:
-/*
-encode.h - c++ wrapper for a base64 encoding algorithm
-
-This is part of the libb64 project, and has been placed in the public domain.
-For details, see http://sourceforge.net/projects/libb64
-*/
-#ifndef BASE64_ENCODE_H
-#define BASE64_ENCODE_H
-
-#include <iostream>
-
-namespace base64
-{
-	extern "C"
-	{
-		#include "cencode.h"
-	}
-
-	struct encoder
-	{
-		base64_encodestate _state;
-		int _buffersize;
-
-		encoder(int buffersize_in = BUFFERSIZE)
-		: _buffersize(buffersize_in)
-		{}
-
-		int encode(char value_in)
-		{
-			return base64_encode_value(value_in);
-		}
-
-		int encode(const char* code_in, const int length_in, char* plaintext_out)
-		{
-			return base64_encode_block(code_in, length_in, plaintext_out, &_state);
-		}
-
-		int encode_end(char* plaintext_out)
-		{
-			return base64_encode_blockend(plaintext_out, &_state);
-		}
-
-		void encode(std::istream& istream_in, std::ostream& ostream_in)
-		{
-			base64_init_encodestate(&_state);
-			//
-			const int N = _buffersize;
-			char* plaintext = new char[N];
-			char* code = new char[2*N];
-			int plainlength;
-			int codelength;
-
-			do
-			{
-				istream_in.read(plaintext, N);
-				plainlength = static_cast<int>(istream_in.gcount());
-				//
-				codelength = encode(plaintext, plainlength, code);
-				ostream_in.write(code, codelength);
-			}
-			while (istream_in.good() && plainlength > 0);
-
-			codelength = encode_end(code);
-			ostream_in.write(code, codelength);
-			//
-			base64_init_encodestate(&_state);
-
-			delete [] code;
-			delete [] plaintext;
-		}
-	};
-
-} // namespace base64
-
-#endif // BASE64_ENCODE_H
-
diff --git a/libsass/backtrace.hpp b/libsass/backtrace.hpp
deleted file mode 100644
--- a/libsass/backtrace.hpp
+++ /dev/null
@@ -1,77 +0,0 @@
-#ifndef SASS_BACKTRACE_H
-#define SASS_BACKTRACE_H
-
-#include <sstream>
-
-#include "file.hpp"
-#include "position.hpp"
-
-namespace Sass {
-
-  using namespace std;
-
-  struct Backtrace {
-
-    Backtrace*  parent;
-    ParserState pstate;
-    string      caller;
-
-    Backtrace(Backtrace* prn, ParserState pstate, string c)
-    : parent(prn),
-      pstate(pstate),
-      caller(c)
-    { }
-
-    string to_string(bool warning = false)
-    {
-      size_t i = -1;
-      stringstream ss;
-      string cwd(Sass::File::get_cwd());
-      Backtrace* this_point = this;
-
-      if (!warning) ss << endl << "Backtrace:";
-      // the first tracepoint (which is parent-less) is an empty placeholder
-      while (this_point->parent) {
-
-        // make path relative to the current directory
-        string rel_path(Sass::File::resolve_relative_path(this_point->pstate.path, cwd, cwd));
-
-        if (warning) {
-          ss << endl
-             << "\t"
-             << (++i == 0 ? "on" : "from")
-             << " line "
-             << this_point->pstate.line + 1
-             << " of "
-             << rel_path;
-        } else {
-          ss << endl
-             << "\t"
-             << rel_path
-             << ":"
-             << this_point->pstate.line + 1
-             << this_point->parent->caller;
-        }
-
-        this_point = this_point->parent;
-      }
-
-      return ss.str();
-    }
-
-    size_t depth()
-    {
-      size_t d = 0;
-      Backtrace* p = parent;
-      while (p) {
-        ++d;
-        p = p->parent;
-      }
-      return d-1;
-    }
-
-  };
-
-}
-
-#endif
diff --git a/libsass/base64vlq.cpp b/libsass/base64vlq.cpp
deleted file mode 100644
--- a/libsass/base64vlq.cpp
+++ /dev/null
@@ -1,43 +0,0 @@
-#include "base64vlq.hpp"
-
-namespace Sass {
-
-  string Base64VLQ::encode(const int number) const
-  {
-    string encoded = "";
-
-    int vlq = to_vlq_signed(number);
-
-    do {
-      int digit = vlq & VLQ_BASE_MASK;
-      vlq >>= VLQ_BASE_SHIFT;
-      if (vlq > 0) {
-        digit |= VLQ_CONTINUATION_BIT;
-      }
-      encoded += base64_encode(digit);
-    } while (vlq > 0);
-
-    return encoded;
-  }
-
-  char Base64VLQ::base64_encode(const int number) const
-  {
-    int index = number;
-    if (index < 0) index = 0;
-    if (index > 63) index = 63;
-    return CHARACTERS[index];
-  }
-
-  int Base64VLQ::to_vlq_signed(const int number) const
-  {
-    return (number < 0) ? ((-number) << 1) + 1 : (number << 1) + 0;
-  }
-
-  const char* Base64VLQ::CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-
-  const int Base64VLQ::VLQ_BASE_SHIFT = 5;
-  const int Base64VLQ::VLQ_BASE = 1 << VLQ_BASE_SHIFT;
-  const int Base64VLQ::VLQ_BASE_MASK = VLQ_BASE - 1;
-  const int Base64VLQ::VLQ_CONTINUATION_BIT = VLQ_BASE;
-
-}
diff --git a/libsass/base64vlq.hpp b/libsass/base64vlq.hpp
deleted file mode 100644
--- a/libsass/base64vlq.hpp
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef SASS_BASE64VLQ_H
-#define SASS_BASE64VLQ_H
-
-#include <string>
-
-namespace Sass {
-  using std::string;
-
-  class Base64VLQ {
-
-  public:
-
-    string encode(const int number) const;
-
-  private:
-
-    char base64_encode(const int number) const;
-
-    int to_vlq_signed(const int number) const;
-
-    static const char* CHARACTERS;
-
-    static const int VLQ_BASE_SHIFT;
-    static const int VLQ_BASE;
-    static const int VLQ_BASE_MASK;
-    static const int VLQ_CONTINUATION_BIT;
-  };
-
-}
-
-#endif
diff --git a/libsass/bind.cpp b/libsass/bind.cpp
deleted file mode 100644
--- a/libsass/bind.cpp
+++ /dev/null
@@ -1,255 +0,0 @@
-#include "bind.hpp"
-#include "ast.hpp"
-#include "context.hpp"
-#include "eval.hpp"
-#include <map>
-#include <iostream>
-#include <sstream>
-#include "to_string.hpp"
-
-namespace Sass {
-  using namespace std;
-
-  void bind(string callee, Parameters* ps, Arguments* as, Context& ctx, Env* env, Eval* eval)
-  {
-    map<string, Parameter*> param_map;
-
-    // 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];
-      param_map[p->name()] = p;
-      // if (p->default_value()) {
-      //   env->local_frame()[p->name()] = p->default_value()->perform(eval->with(env));
-      // }
-    }
-
-    // plug in all args; if we have leftover params, deal with it later
-    size_t ip = 0, LP = ps->length();
-    size_t ia = 0, LA = as->length();
-    while (ia < LA) {
-      Argument* a = (*as)[ia];
-      if (ip >= LP) {
-        // skip empty rest arguments
-        if (a->is_rest_argument()) {
-          if (List* l = dynamic_cast<List*>(a->value())) {
-            if (l->length() == 0) {
-              ++ ia; continue;
-            }
-          }
-        }
-        stringstream msg;
-        msg << callee << " only takes " << LP << " arguments; "
-            << "given " << LA;
-        error(msg.str(), as->pstate());
-      }
-      Parameter* p = (*ps)[ip];
-
-      // 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 {
-              // create a new list object for wrapped items
-              List* arglist = new (ctx.mem) List(p->pstate(),
-                                                 0,
-                                                 rest->separator(),
-                                                 true);
-              // wrap each item from list as an argument
-              for (Expression* item : rest->elements()) {
-                (*arglist) << new (ctx.mem) Argument(item->pstate(),
-                                                     item,
-                                                     "",
-                                                     false,
-                                                     false);
-              }
-              // assign new arglist to environment
-              env->local_frame()[p->name()] = arglist;
-            }
-          }
-          // invalid state
-          else {
-            throw runtime_error("invalid state");
-          }
-        } else if (a->is_keyword_argument()) {
-
-          // expand keyword arguments into their parameters
-          List* arglist = new (ctx.mem) List(p->pstate(), 0, List::COMMA, true);
-          env->local_frame()[p->name()] = arglist;
-          Map* argmap = static_cast<Map*>(a->value());
-          for (auto key : argmap->keys()) {
-            string name = unquote(static_cast<String_Constant*>(key)->value());
-            (*arglist) << new (ctx.mem) Argument(key->pstate(),
-                                                 argmap->at(key),
-                                                 name,
-                                                 false,
-                                                 false);
-          }
-
-        } else {
-
-          // create a new list object for wrapped items
-          List* arglist = new (ctx.mem) List(p->pstate(),
-                                             0,
-                                             List::COMMA,
-                                             true);
-          // consume the next args
-          while (ia < LA) {
-            // get and post inc
-            a = (*as)[ia++];
-            // wrap current argument into new object
-            (*arglist) << new (ctx.mem) Argument(a->pstate(),
-                                                 a->value(),
-                                                 a->name(),
-                                                 false,
-                                                 false);
-            // check if we have rest argument
-            if (a->is_rest_argument()) {
-              // preserve the list separator from rest args
-              if (List* rest = dynamic_cast<List*>(a->value())) {
-                arglist->separator(rest->separator());
-              }
-              // no more arguments
-              break;
-            }
-          }
-          // assign new arglist to environment
-          env->local_frame()[p->name()] = arglist;
-        }
-        // consumed parameter
-        ++ip;
-        // no more paramaters
-        break;
-      }
-
-      // 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());
-        // empty rest arg - treat all args as default values
-        if (!arglist->length()) {
-          break;
-        }
-        // otherwise move one of the rest args into the param, converting to argument if necessary
-        if (arglist->is_arglist()) {
-          a = static_cast<Argument*>((*arglist)[0]);
-        } else {
-          Expression* a_to_convert = (*arglist)[0];
-          a = new (ctx.mem) Argument(a_to_convert->pstate(),
-                                     a_to_convert,
-                                     "",
-                                     false,
-                                     false);
-        }
-        arglist->elements().erase(arglist->elements().begin());
-        if (!arglist->length() || (!arglist->is_arglist() && ip + 1 == LP)) {
-          ++ia;
-        }
-      } else if (a->is_keyword_argument()) {
-        Map* argmap = static_cast<Map*>(a->value());
-
-        for (auto key : argmap->keys()) {
-          string name = "$" + unquote(static_cast<String_Constant*>(key)->value());
-
-          if (!param_map.count(name)) {
-            stringstream msg;
-            msg << callee << " has no parameter named " << name;
-            error(msg.str(), a->pstate());
-          }
-          env->local_frame()[name] = argmap->at(key);
-        }
-        ++ia;
-        continue;
-      } else {
-        ++ia;
-      }
-
-      if (a->name().empty()) {
-        if (env->has_local(p->name())) {
-          stringstream msg;
-          msg << "parameter " << p->name()
-          << " provided more than once in call to " << callee;
-          error(msg.str(), a->pstate());
-        }
-        // ordinal arg -- bind it to the next param
-        env->local_frame()[p->name()] = a->value();
-        ++ip;
-      }
-      else {
-        // named arg -- bind it to the appropriately named param
-        if (!param_map.count(a->name())) {
-          stringstream msg;
-          msg << callee << " has no parameter named " << a->name();
-          error(msg.str(), a->pstate());
-        }
-        if (param_map[a->name()]->is_rest_parameter()) {
-          stringstream msg;
-          msg << "argument " << a->name() << " of " << callee
-              << "cannot be used as named argument";
-          error(msg.str(), a->pstate());
-        }
-        if (env->has_local(a->name())) {
-          stringstream msg;
-          msg << "parameter " << p->name()
-              << "provided more than once in call to " << callee;
-          error(msg.str(), a->pstate());
-        }
-        env->local_frame()[a->name()] = a->value();
-      }
-    }
-    // EO while ia
-
-    // If we make it here, we're out of args but may have leftover params.
-    // That's only okay if they have default values, or were already bound by
-    // 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];
-      // 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()] = new (ctx.mem) List(leftover->pstate(),
-                                                                      0,
-                                                                      List::COMMA,
-                                                                      true);
-        }
-        else if (leftover->default_value()) {
-          // make sure to eval the default value in the env that we've been populating
-          Env* old_env = eval->env;
-          Backtrace* old_bt = eval->backtrace;
-          Contextualize* old_context = eval->contextualize;
-          Expression* dv = leftover->default_value()->perform(eval->with(env, eval->backtrace));
-          eval->env = old_env;
-          eval->backtrace = old_bt;
-          eval->contextualize = old_context;
-          // dv->perform(&to_string);
-          env->local_frame()[leftover->name()] = dv;
-        }
-        else {
-          // param is unbound and has no default value -- error
-          stringstream msg;
-          msg << "required parameter " << leftover->name()
-              << " is missing in call to " << callee;
-          error(msg.str(), as->pstate());
-        }
-      }
-    }
-
-    return;
-  }
-
-
-}
diff --git a/libsass/bind.hpp b/libsass/bind.hpp
deleted file mode 100644
--- a/libsass/bind.hpp
+++ /dev/null
@@ -1,18 +0,0 @@
-#ifndef SASS_BIND_H
-#define SASS_BIND_H
-
-#include <string>
-#include "environment.hpp"
-
-namespace Sass {
-  class   AST_Node;
-  class   Parameters;
-  class   Arguments;
-  class   Context;
-  class   Eval;
-  typedef Environment<AST_Node*> Env;
-
-  void bind(string caller, Parameters*, Arguments*, Context&, Env*, Eval*);
-}
-
-#endif
diff --git a/libsass/cencode.c b/libsass/cencode.c
deleted file mode 100644
--- a/libsass/cencode.c
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
-cencoder.c - c source to a base64 encoding algorithm implementation
-
-This is part of the libb64 project, and has been placed in the public domain.
-For details, see http://sourceforge.net/projects/libb64
-*/
-
-#include "b64/cencode.h"
-
-void base64_init_encodestate(base64_encodestate* state_in)
-{
-	state_in->step = step_A;
-	state_in->result = 0;
-	state_in->stepcount = 0;
-}
-
-char base64_encode_value(char value_in)
-{
-	static const char* encoding = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-	if (value_in > 63) return '=';
-	return encoding[(int)value_in];
-}
-
-int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in)
-{
-	const char* plainchar = plaintext_in;
-	const char* const plaintextend = plaintext_in + length_in;
-	char* codechar = code_out;
-	char result;
-	char fragment;
-
-	result = state_in->result;
-
-	switch (state_in->step)
-	{
-		while (1)
-		{
-	case step_A:
-			if (plainchar == plaintextend)
-			{
-				state_in->result = result;
-				state_in->step = step_A;
-				return codechar - code_out;
-			}
-			fragment = *plainchar++;
-			result = (fragment & 0x0fc) >> 2;
-			*codechar++ = base64_encode_value(result);
-			result = (fragment & 0x003) << 4;
-	case step_B:
-			if (plainchar == plaintextend)
-			{
-				state_in->result = result;
-				state_in->step = step_B;
-				return codechar - code_out;
-			}
-			fragment = *plainchar++;
-			result |= (fragment & 0x0f0) >> 4;
-			*codechar++ = base64_encode_value(result);
-			result = (fragment & 0x00f) << 2;
-	case step_C:
-			if (plainchar == plaintextend)
-			{
-				state_in->result = result;
-				state_in->step = step_C;
-				return codechar - code_out;
-			}
-			fragment = *plainchar++;
-			result |= (fragment & 0x0c0) >> 6;
-			*codechar++ = base64_encode_value(result);
-			result  = (fragment & 0x03f) >> 0;
-			*codechar++ = base64_encode_value(result);
-
-			++(state_in->stepcount);
-		}
-	}
-	/* control should not reach here */
-	return codechar - code_out;
-}
-
-int base64_encode_blockend(char* code_out, base64_encodestate* state_in)
-{
-	char* codechar = code_out;
-
-	switch (state_in->step)
-	{
-	case step_B:
-		*codechar++ = base64_encode_value(state_in->result);
-		*codechar++ = '=';
-		*codechar++ = '=';
-		break;
-	case step_C:
-		*codechar++ = base64_encode_value(state_in->result);
-		*codechar++ = '=';
-		break;
-	case step_A:
-		break;
-	}
-	*codechar++ = '\n';
-
-	return codechar - code_out;
-}
-
diff --git a/libsass/color_names.hpp b/libsass/color_names.hpp
deleted file mode 100644
--- a/libsass/color_names.hpp
+++ /dev/null
@@ -1,327 +0,0 @@
-#ifndef SASS_COLOR_NAMES_H
-#define SASS_COLOR_NAMES_H
-
-namespace Sass {
-
-  /*
-   * Color names are processed in order. For color names with alternate aliases
-   * (i.e. gray & grey), the canonical name should be listed last, so it takes
-   * precedence.
-   */
-  const char* color_names[] =
-  {
-    "aliceblue",
-    "antiquewhite",
-    "aqua",
-    "aquamarine",
-    "azure",
-    "beige",
-    "bisque",
-    "black",
-    "blanchedalmond",
-    "blue",
-    "blueviolet",
-    "brown",
-    "burlywood",
-    "cadetblue",
-    "chartreuse",
-    "chocolate",
-    "coral",
-    "cornflowerblue",
-    "cornsilk",
-    "crimson",
-    "cyan",
-    "darkblue",
-    "darkcyan",
-    "darkgoldenrod",
-    "darkgrey",
-    "darkgray",
-    "darkgreen",
-    "darkkhaki",
-    "darkmagenta",
-    "darkolivegreen",
-    "darkorange",
-    "darkorchid",
-    "darkred",
-    "darksalmon",
-    "darkseagreen",
-    "darkslateblue",
-    "darkslategrey",
-    "darkslategray",
-    "darkturquoise",
-    "darkviolet",
-    "deeppink",
-    "deepskyblue",
-    "dimgrey",
-    "dimgray",
-    "dodgerblue",
-    "firebrick",
-    "floralwhite",
-    "forestgreen",
-    "fuchsia",
-    "gainsboro",
-    "ghostwhite",
-    "gold",
-    "goldenrod",
-    "grey",
-    "gray",
-    "green",
-    "greenyellow",
-    "honeydew",
-    "hotpink",
-    "indianred",
-    "indigo",
-    "ivory",
-    "khaki",
-    "lavender",
-    "lavenderblush",
-    "lawngreen",
-    "lemonchiffon",
-    "lightblue",
-    "lightcoral",
-    "lightcyan",
-    "lightgoldenrodyellow",
-    "lightgrey",
-    "lightgray",
-    "lightgreen",
-    "lightpink",
-    "lightsalmon",
-    "lightseagreen",
-    "lightskyblue",
-    "lightslategrey",
-    "lightslategray",
-    "lightsteelblue",
-    "lightyellow",
-    "lime",
-    "limegreen",
-    "linen",
-    "magenta",
-    "maroon",
-    "mediumaquamarine",
-    "mediumblue",
-    "mediumorchid",
-    "mediumpurple",
-    "mediumseagreen",
-    "mediumslateblue",
-    "mediumspringgreen",
-    "mediumturquoise",
-    "mediumvioletred",
-    "midnightblue",
-    "mintcream",
-    "mistyrose",
-    "moccasin",
-    "navajowhite",
-    "navy",
-    "oldlace",
-    "olive",
-    "olivedrab",
-    "orange",
-    "orangered",
-    "orchid",
-    "palegoldenrod",
-    "palegreen",
-    "paleturquoise",
-    "palevioletred",
-    "papayawhip",
-    "peachpuff",
-    "peru",
-    "pink",
-    "plum",
-    "powderblue",
-    "purple",
-    "red",
-    "rosybrown",
-    "royalblue",
-    "saddlebrown",
-    "salmon",
-    "sandybrown",
-    "seagreen",
-    "seashell",
-    "sienna",
-    "silver",
-    "skyblue",
-    "slateblue",
-    "slategrey",
-    "slategray",
-    "snow",
-    "springgreen",
-    "steelblue",
-    "tan",
-    "teal",
-    "thistle",
-    "tomato",
-    "turquoise",
-    "violet",
-    "wheat",
-    "white",
-    "whitesmoke",
-    "yellow",
-    "yellowgreen",
-    // rebeccapurple
-    "rebeccapurple",
-    // transparent
-    "transparent",
-    // sentinel value
-    0
-  };
-
-  const double color_values[] =
-  {
-    0xf0, 0xf8, 0xff, 1,
-    0xfa, 0xeb, 0xd7, 1,
-    0x00, 0xff, 0xff, 1,
-    0x7f, 0xff, 0xd4, 1,
-    0xf0, 0xff, 0xff, 1,
-    0xf5, 0xf5, 0xdc, 1,
-    0xff, 0xe4, 0xc4, 1,
-    0x00, 0x00, 0x00, 1,
-    0xff, 0xeb, 0xcd, 1,
-    0x00, 0x00, 0xff, 1,
-    0x8a, 0x2b, 0xe2, 1,
-    0xa5, 0x2a, 0x2a, 1,
-    0xde, 0xb8, 0x87, 1,
-    0x5f, 0x9e, 0xa0, 1,
-    0x7f, 0xff, 0x00, 1,
-    0xd2, 0x69, 0x1e, 1,
-    0xff, 0x7f, 0x50, 1,
-    0x64, 0x95, 0xed, 1,
-    0xff, 0xf8, 0xdc, 1,
-    0xdc, 0x14, 0x3c, 1,
-    0x00, 0xff, 0xff, 1,
-    0x00, 0x00, 0x8b, 1,
-    0x00, 0x8b, 0x8b, 1,
-    0xb8, 0x86, 0x0b, 1,
-    0xa9, 0xa9, 0xa9, 1,
-    0xa9, 0xa9, 0xa9, 1,
-    0x00, 0x64, 0x00, 1,
-    0xbd, 0xb7, 0x6b, 1,
-    0x8b, 0x00, 0x8b, 1,
-    0x55, 0x6b, 0x2f, 1,
-    0xff, 0x8c, 0x00, 1,
-    0x99, 0x32, 0xcc, 1,
-    0x8b, 0x00, 0x00, 1,
-    0xe9, 0x96, 0x7a, 1,
-    0x8f, 0xbc, 0x8f, 1,
-    0x48, 0x3d, 0x8b, 1,
-    0x2f, 0x4f, 0x4f, 1,
-    0x2f, 0x4f, 0x4f, 1,
-    0x00, 0xce, 0xd1, 1,
-    0x94, 0x00, 0xd3, 1,
-    0xff, 0x14, 0x93, 1,
-    0x00, 0xbf, 0xff, 1,
-    0x69, 0x69, 0x69, 1,
-    0x69, 0x69, 0x69, 1,
-    0x1e, 0x90, 0xff, 1,
-    0xb2, 0x22, 0x22, 1,
-    0xff, 0xfa, 0xf0, 1,
-    0x22, 0x8b, 0x22, 1,
-    0xff, 0x00, 0xff, 1,
-    0xdc, 0xdc, 0xdc, 1,
-    0xf8, 0xf8, 0xff, 1,
-    0xff, 0xd7, 0x00, 1,
-    0xda, 0xa5, 0x20, 1,
-    0x80, 0x80, 0x80, 1,
-    0x80, 0x80, 0x80, 1,
-    0x00, 0x80, 0x00, 1,
-    0xad, 0xff, 0x2f, 1,
-    0xf0, 0xff, 0xf0, 1,
-    0xff, 0x69, 0xb4, 1,
-    0xcd, 0x5c, 0x5c, 1,
-    0x4b, 0x00, 0x82, 1,
-    0xff, 0xff, 0xf0, 1,
-    0xf0, 0xe6, 0x8c, 1,
-    0xe6, 0xe6, 0xfa, 1,
-    0xff, 0xf0, 0xf5, 1,
-    0x7c, 0xfc, 0x00, 1,
-    0xff, 0xfa, 0xcd, 1,
-    0xad, 0xd8, 0xe6, 1,
-    0xf0, 0x80, 0x80, 1,
-    0xe0, 0xff, 0xff, 1,
-    0xfa, 0xfa, 0xd2, 1,
-    0xd3, 0xd3, 0xd3, 1,
-    0xd3, 0xd3, 0xd3, 1,
-    0x90, 0xee, 0x90, 1,
-    0xff, 0xb6, 0xc1, 1,
-    0xff, 0xa0, 0x7a, 1,
-    0x20, 0xb2, 0xaa, 1,
-    0x87, 0xce, 0xfa, 1,
-    0x77, 0x88, 0x99, 1,
-    0x77, 0x88, 0x99, 1,
-    0xb0, 0xc4, 0xde, 1,
-    0xff, 0xff, 0xe0, 1,
-    0x00, 0xff, 0x00, 1,
-    0x32, 0xcd, 0x32, 1,
-    0xfa, 0xf0, 0xe6, 1,
-    0xff, 0x00, 0xff, 1,
-    0x80, 0x00, 0x00, 1,
-    0x66, 0xcd, 0xaa, 1,
-    0x00, 0x00, 0xcd, 1,
-    0xba, 0x55, 0xd3, 1,
-    0x93, 0x70, 0xdb, 1,
-    0x3c, 0xb3, 0x71, 1,
-    0x7b, 0x68, 0xee, 1,
-    0x00, 0xfa, 0x9a, 1,
-    0x48, 0xd1, 0xcc, 1,
-    0xc7, 0x15, 0x85, 1,
-    0x19, 0x19, 0x70, 1,
-    0xf5, 0xff, 0xfa, 1,
-    0xff, 0xe4, 0xe1, 1,
-    0xff, 0xe4, 0xb5, 1,
-    0xff, 0xde, 0xad, 1,
-    0x00, 0x00, 0x80, 1,
-    0xfd, 0xf5, 0xe6, 1,
-    0x80, 0x80, 0x00, 1,
-    0x6b, 0x8e, 0x23, 1,
-    0xff, 0xa5, 0x00, 1,
-    0xff, 0x45, 0x00, 1,
-    0xda, 0x70, 0xd6, 1,
-    0xee, 0xe8, 0xaa, 1,
-    0x98, 0xfb, 0x98, 1,
-    0xaf, 0xee, 0xee, 1,
-    0xdb, 0x70, 0x93, 1,
-    0xff, 0xef, 0xd5, 1,
-    0xff, 0xda, 0xb9, 1,
-    0xcd, 0x85, 0x3f, 1,
-    0xff, 0xc0, 0xcb, 1,
-    0xdd, 0xa0, 0xdd, 1,
-    0xb0, 0xe0, 0xe6, 1,
-    0x80, 0x00, 0x80, 1,
-    0xff, 0x00, 0x00, 1,
-    0xbc, 0x8f, 0x8f, 1,
-    0x41, 0x69, 0xe1, 1,
-    0x8b, 0x45, 0x13, 1,
-    0xfa, 0x80, 0x72, 1,
-    0xf4, 0xa4, 0x60, 1,
-    0x2e, 0x8b, 0x57, 1,
-    0xff, 0xf5, 0xee, 1,
-    0xa0, 0x52, 0x2d, 1,
-    0xc0, 0xc0, 0xc0, 1,
-    0x87, 0xce, 0xeb, 1,
-    0x6a, 0x5a, 0xcd, 1,
-    0x70, 0x80, 0x90, 1,
-    0x70, 0x80, 0x90, 1,
-    0xff, 0xfa, 0xfa, 1,
-    0x00, 0xff, 0x7f, 1,
-    0x46, 0x82, 0xb4, 1,
-    0xd2, 0xb4, 0x8c, 1,
-    0x00, 0x80, 0x80, 1,
-    0xd8, 0xbf, 0xd8, 1,
-    0xff, 0x63, 0x47, 1,
-    0x40, 0xe0, 0xd0, 1,
-    0xee, 0x82, 0xee, 1,
-    0xf5, 0xde, 0xb3, 1,
-    0xff, 0xff, 0xff, 1,
-    0xf5, 0xf5, 0xf5, 1,
-    0xff, 0xff, 0x00, 1,
-    0x9a, 0xcd, 0x32, 1,
-    // rebeccapurple
-    0x66, 0x33, 0x99, 1,
-    // transparent
-    0x00, 0x00, 0x00, 0,
-    // sentinel value
-    0xfff
-  };
-
-}
-
-#endif
diff --git a/libsass/constants.cpp b/libsass/constants.cpp
deleted file mode 100644
--- a/libsass/constants.cpp
+++ /dev/null
@@ -1,168 +0,0 @@
-#include "constants.hpp"
-
-namespace Sass {
-  namespace Constants {
-
-    extern const unsigned long MaxCallStack = 1024;
-
-    // https://github.com/sass/libsass/issues/592
-    // https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity
-    // https://github.com/sass/sass/issues/1495#issuecomment-61189114
-    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;
-
-    // sass keywords
-    extern const char at_root_kwd[]       = "@at-root";
-    extern const char import_kwd[]        = "@import";
-    extern const char mixin_kwd[]         = "@mixin";
-    extern const char function_kwd[]      = "@function";
-    extern const char return_kwd[]        = "@return";
-    extern const char include_kwd[]       = "@include";
-    extern const char content_kwd[]       = "@content";
-    extern const char extend_kwd[]        = "@extend";
-    extern const char if_kwd[]            = "@if";
-    extern const char else_kwd[]          = "@else";
-    extern const char if_after_else_kwd[] = "if";
-    extern const char for_kwd[]           = "@for";
-    extern const char from_kwd[]          = "from";
-    extern const char to_kwd[]            = "to";
-    extern const char through_kwd[]       = "through";
-    extern const char each_kwd[]          = "@each";
-    extern const char in_kwd[]            = "in";
-    extern const char while_kwd[]         = "@while";
-    extern const char warn_kwd[]          = "@warn";
-    extern const char error_kwd[]         = "@error";
-    extern const char debug_kwd[]         = "@debug";
-    extern const char default_kwd[]       = "default";
-    extern const char global_kwd[]        = "global";
-    extern const char null_kwd[]          = "null";
-    extern const char optional_kwd[]      = "optional";
-    extern const char with_kwd[]          = "with";
-    extern const char without_kwd[]       = "without";
-    extern const char all_kwd[]           = "all";
-    extern const char rule_kwd[]          = "rule";
-
-    // css standard units
-    extern const char em_kwd[]   = "em";
-    extern const char ex_kwd[]   = "ex";
-    extern const char px_kwd[]   = "px";
-    extern const char cm_kwd[]   = "cm";
-    extern const char mm_kwd[]   = "mm";
-    extern const char pt_kwd[]   = "pt";
-    extern const char pc_kwd[]   = "pc";
-    extern const char deg_kwd[]  = "deg";
-    extern const char rad_kwd[]  = "rad";
-    extern const char grad_kwd[] = "grad";
-    extern const char turn_kwd[] = "turn";
-    extern const char ms_kwd[]   = "ms";
-    extern const char s_kwd[]    = "s";
-    extern const char Hz_kwd[]   = "Hz";
-    extern const char kHz_kwd[]  = "kHz";
-
-    // vendor prefixes
-    extern const char vendor_opera_kwd[]    = "-o-";
-    extern const char vendor_webkit_kwd[]   = "-webkit-";
-    extern const char vendor_mozilla_kwd[]  = "-moz-";
-    extern const char vendor_ms_kwd[]       = "-ms-";
-    extern const char vendor_khtml_kwd[]    = "-khtml-";
-
-    // css functions and keywords
-    extern const char charset_kwd[]      = "@charset";
-    extern const char media_kwd[]        = "@media";
-    extern const char supports_kwd[]     = "@supports";
-    extern const char keyframes_kwd[]    = "keyframes";
-    extern const char only_kwd[]         = "only";
-    extern const char rgb_kwd[]          = "rgb(";
-    extern const char url_kwd[]          = "url(";
-    extern const char important_kwd[]    = "important";
-    extern const char pseudo_not_kwd[]   = ":not(";
-    extern const char even_kwd[]         = "even";
-    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(";
-
-    // css selector keywords
-    extern const char sel_deep_kwd[] = "/deep/";
-
-    // css attribute-matching operators
-    extern const char tilde_equal[]  = "~=";
-    extern const char pipe_equal[]   = "|=";
-    extern const char caret_equal[]  = "^=";
-    extern const char dollar_equal[] = "$=";
-    extern const char star_equal[]   = "*=";
-
-    // relational & logical operators and constants
-    extern const char and_kwd[]   = "and";
-    extern const char or_kwd[]    = "or";
-    extern const char not_kwd[]   = "not";
-    extern const char gt[]        = ">";
-    extern const char gte[]       = ">=";
-    extern const char lt[]        = "<";
-    extern const char lte[]       = "<=";
-    extern const char eq[]        = "==";
-    extern const char neq[]       = "!=";
-    extern const char true_kwd[]  = "true";
-    extern const char false_kwd[] = "false";
-
-    // miscellaneous punctuation and delimiters
-    extern const char percent_str[]     = "%";
-    extern const char empty_str[]       = "";
-    extern const char slash_slash[]     = "//";
-    extern const char slash_star[]      = "/*";
-    extern const char star_slash[]      = "*/";
-    extern const char hash_lbrace[]     = "#{";
-    extern const char rbrace[]          = "}";
-    extern const char rparen[]          = ")";
-    extern const char sign_chars[]      = "-+";
-    extern const char hyphen[]          = "-";
-    extern const char ellipsis[]        = "...";
-    // extern const char url_space_chars[] = " \t\r\n\f";
-    extern const char escape_chars[]    = " -~"; // need to include unicode spaces too
-    // type names
-    extern const char numeric_name[]    = "numeric value";
-    extern const char number_name[]     = "number";
-    extern const char percentage_name[] = "percentage";
-    extern const char dimension_name[]  = "numeric dimension";
-    extern const char string_name[]     = "string";
-    extern const char bool_name[]       = "bool";
-    extern const char color_name[]      = "color";
-    extern const char list_name[]       = "list";
-    extern const char map_name[]        = "map";
-    extern const char arglist_name[]    = "arglist";
-
-    // constants for uri parsing (RFC 3986 Appendix A.)
-    extern const char uri_chars[]  = ":;/?!$%&#@|[]{}'`^\"*+-.,_=~";
-
-    // some specific constant character classes
-    // they must be static to be useable by lexer
-    extern const char static_ops[]      = "*/%";
-
-    // byte order marks
-    // (taken from http://en.wikipedia.org/wiki/Byte_order_mark)
-    extern const unsigned char utf_8_bom[]      = { 0xEF, 0xBB, 0xBF };
-    extern const unsigned char utf_16_bom_be[]  = { 0xFE, 0xFF };
-    extern const unsigned char utf_16_bom_le[]  = { 0xFF, 0xFE };
-    extern const unsigned char utf_32_bom_be[]  = { 0x00, 0x00, 0xFE, 0xFF };
-    extern const unsigned char utf_32_bom_le[]  = { 0xFF, 0xFE, 0x00, 0x00 };
-    extern const unsigned char utf_7_bom_1[]    = { 0x2B, 0x2F, 0x76, 0x38 };
-    extern const unsigned char utf_7_bom_2[]    = { 0x2B, 0x2F, 0x76, 0x39 };
-    extern const unsigned char utf_7_bom_3[]    = { 0x2B, 0x2F, 0x76, 0x2B };
-    extern const unsigned char utf_7_bom_4[]    = { 0x2B, 0x2F, 0x76, 0x2F };
-    extern const unsigned char utf_7_bom_5[]    = { 0x2B, 0x2F, 0x76, 0x38, 0x2D };
-    extern const unsigned char utf_1_bom[]      = { 0xF7, 0x64, 0x4C };
-    extern const unsigned char utf_ebcdic_bom[] = { 0xDD, 0x73, 0x66, 0x73 };
-    extern const unsigned char scsu_bom[]       = { 0x0E, 0xFE, 0xFF };
-    extern const unsigned char bocu_1_bom[]     = { 0xFB, 0xEE, 0x28 };
-    extern const unsigned char gb_18030_bom[]   = { 0x84, 0x31, 0x95, 0x33 };
-
-  }
-}
diff --git a/libsass/constants.hpp b/libsass/constants.hpp
deleted file mode 100644
--- a/libsass/constants.hpp
+++ /dev/null
@@ -1,173 +0,0 @@
-#ifndef SASS_CONSTANTS_H
-#define SASS_CONSTANTS_H
-
-namespace Sass {
-  namespace Constants {
-
-    // The maximum call stack that can be created
-    extern const unsigned long MaxCallStack;
-
-    // https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity
-    // The following list of selectors is by increasing specificity:
-    extern const unsigned long Specificity_Star;
-    extern const unsigned long Specificity_Universal;
-    extern const unsigned long Specificity_Type;
-    extern const unsigned long Specificity_Class;
-    extern const unsigned long Specificity_Attr;
-    extern const unsigned long Specificity_Pseudo;
-    extern const unsigned long Specificity_ID;
-
-    // sass keywords
-    extern const char at_root_kwd[];
-    extern const char import_kwd[];
-    extern const char mixin_kwd[];
-    extern const char function_kwd[];
-    extern const char return_kwd[];
-    extern const char include_kwd[];
-    extern const char content_kwd[];
-    extern const char extend_kwd[];
-    extern const char if_kwd[];
-    extern const char else_kwd[];
-    extern const char if_after_else_kwd[];
-    extern const char for_kwd[];
-    extern const char from_kwd[];
-    extern const char to_kwd[];
-    extern const char through_kwd[];
-    extern const char each_kwd[];
-    extern const char in_kwd[];
-    extern const char while_kwd[];
-    extern const char warn_kwd[];
-    extern const char error_kwd[];
-    extern const char debug_kwd[];
-    extern const char default_kwd[];
-    extern const char global_kwd[];
-    extern const char null_kwd[];
-    extern const char optional_kwd[];
-    extern const char with_kwd[];
-    extern const char without_kwd[];
-    extern const char all_kwd[];
-    extern const char rule_kwd[];
-
-    // css standard units
-    extern const char em_kwd[];
-    extern const char ex_kwd[];
-    extern const char px_kwd[];
-    extern const char cm_kwd[];
-    extern const char mm_kwd[];
-    extern const char pt_kwd[];
-    extern const char pc_kwd[];
-    extern const char deg_kwd[];
-    extern const char rad_kwd[];
-    extern const char grad_kwd[];
-    extern const char turn_kwd[];
-    extern const char ms_kwd[];
-    extern const char s_kwd[];
-    extern const char Hz_kwd[];
-    extern const char kHz_kwd[];
-
-    // vendor prefixes
-    extern const char vendor_opera_kwd[];
-    extern const char vendor_webkit_kwd[];
-    extern const char vendor_mozilla_kwd[];
-    extern const char vendor_ms_kwd[];
-    extern const char vendor_khtml_kwd[];
-
-    // css functions and keywords
-    extern const char charset_kwd[];
-    extern const char media_kwd[];
-    extern const char supports_kwd[];
-    extern const char keyframes_kwd[];
-    extern const char only_kwd[];
-    extern const char rgb_kwd[];
-    extern const char url_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[];
-
-    // css selector keywords
-    extern const char sel_deep_kwd[];
-
-    // css attribute-matching operators
-    extern const char tilde_equal[];
-    extern const char pipe_equal[];
-    extern const char caret_equal[];
-    extern const char dollar_equal[];
-    extern const char star_equal[];
-
-    // relational & logical operators and constants
-    extern const char and_kwd[];
-    extern const char or_kwd[];
-    extern const char not_kwd[];
-    extern const char gt[];
-    extern const char gte[];
-    extern const char lt[];
-    extern const char lte[];
-    extern const char eq[];
-    extern const char neq[];
-    extern const char true_kwd[];
-    extern const char false_kwd[];
-
-    // miscellaneous punctuation and delimiters
-    extern const char percent_str[];
-    extern const char empty_str[];
-    extern const char slash_slash[];
-    extern const char slash_star[];
-    extern const char star_slash[];
-    extern const char hash_lbrace[];
-    extern const char rbrace[];
-    extern const char rparen[];
-    extern const char sign_chars[];
-    extern const char hyphen[];
-    extern const char ellipsis[];
-    // extern const char url_space_chars[];
-    extern const char escape_chars[];
-
-    // type names
-    extern const char numeric_name[];
-    extern const char number_name[];
-    extern const char percentage_name[];
-    extern const char dimension_name[];
-    extern const char string_name[];
-    extern const char bool_name[];
-    extern const char color_name[];
-    extern const char list_name[];
-    extern const char map_name[];
-    extern const char arglist_name[];
-
-    // constants for uri parsing (RFC 3986 Appendix A.)
-    extern const char uri_chars[];
-
-    // some specific constant character classes
-    // they must be static to be useable by lexer
-    extern const char static_ops[];
-
-    // byte order marks
-    // (taken from http://en.wikipedia.org/wiki/Byte_order_mark)
-    extern const unsigned char utf_8_bom[];
-    extern const unsigned char utf_16_bom_be[];
-    extern const unsigned char utf_16_bom_le[];
-    extern const unsigned char utf_32_bom_be[];
-    extern const unsigned char utf_32_bom_le[];
-    extern const unsigned char utf_7_bom_1[];
-    extern const unsigned char utf_7_bom_2[];
-    extern const unsigned char utf_7_bom_3[];
-    extern const unsigned char utf_7_bom_4[];
-    extern const unsigned char utf_7_bom_5[];
-    extern const unsigned char utf_1_bom[];
-    extern const unsigned char utf_ebcdic_bom[];
-    extern const unsigned char scsu_bom[];
-    extern const unsigned char bocu_1_bom[];
-    extern const unsigned char gb_18030_bom[];
-
-  }
-}
-
-#endif
diff --git a/libsass/context.cpp b/libsass/context.cpp
deleted file mode 100644
--- a/libsass/context.cpp
+++ /dev/null
@@ -1,561 +0,0 @@
-#ifdef _WIN32
-#define PATH_SEP ';'
-#else
-#define PATH_SEP ':'
-#endif
-
-#include <string>
-#include <cstdlib>
-#include <cstring>
-#include <iomanip>
-#include <sstream>
-#include <iostream>
-
-#include "ast.hpp"
-#include "util.hpp"
-#include "sass.h"
-#include "context.hpp"
-#include "plugins.hpp"
-#include "constants.hpp"
-#include "parser.hpp"
-#include "file.hpp"
-#include "inspect.hpp"
-#include "output.hpp"
-#include "expand.hpp"
-#include "eval.hpp"
-#include "contextualize.hpp"
-#include "contextualize_eval.hpp"
-#include "cssize.hpp"
-#include "listize.hpp"
-#include "extend.hpp"
-#include "remove_placeholders.hpp"
-#include "color_names.hpp"
-#include "functions.hpp"
-#include "backtrace.hpp"
-#include "sass2scss.h"
-#include "prelexer.hpp"
-#include "emitter.hpp"
-
-namespace Sass {
-  using namespace Constants;
-  using namespace File;
-  using namespace Sass;
-  using std::cerr;
-  using std::endl;
-
-  Sass_Queued::Sass_Queued(const string& load_path, const string& abs_path, const char* source)
-  {
-    this->load_path = load_path;
-    this->abs_path = abs_path;
-    this->source = source;
-  }
-
-  inline bool sort_importers (const Sass_Importer_Entry& i, const Sass_Importer_Entry& j)
-  { return sass_importer_get_priority(i) > sass_importer_get_priority(j); }
-
-  Context::Context(Context::Data initializers)
-  : // Output(this),
-    head_imports(0),
-    mem(Memory_Manager<AST_Node>()),
-    c_options               (initializers.c_options()),
-    c_compiler              (initializers.c_compiler()),
-    source_c_str            (initializers.source_c_str()),
-    sources                 (vector<const char*>()),
-    plugin_paths            (initializers.plugin_paths()),
-    include_paths           (initializers.include_paths()),
-    queue                   (vector<Sass_Queued>()),
-    style_sheets            (map<string, Block*>()),
-    emitter (this),
-    c_headers               (vector<Sass_Importer_Entry>()),
-    c_importers             (vector<Sass_Importer_Entry>()),
-    c_functions             (vector<Sass_Function_Entry>()),
-    indent                  (initializers.indent()),
-    linefeed                (initializers.linefeed()),
-    input_path              (make_canonical_path(initializers.input_path())),
-    output_path             (make_canonical_path(initializers.output_path())),
-    source_comments         (initializers.source_comments()),
-    output_style            (initializers.output_style()),
-    source_map_file         (make_canonical_path(initializers.source_map_file())),
-    source_map_root         (initializers.source_map_root()), // pass-through
-    source_map_embed        (initializers.source_map_embed()),
-    source_map_contents     (initializers.source_map_contents()),
-    omit_source_map_url     (initializers.omit_source_map_url()),
-    is_indented_syntax_src  (initializers.is_indented_syntax_src()),
-    names_to_colors         (map<string, Color*>()),
-    colors_to_names         (map<int, string>()),
-    precision               (initializers.precision()),
-    plugins(),
-    subset_map              (Subset_Map<string, pair<Complex_Selector*, Compound_Selector*> >())
-  {
-
-    cwd = get_cwd();
-
-    // enforce some safe defaults
-    // used to create relative file links
-    if (input_path == "") input_path = "stdin";
-    if (output_path == "") output_path = "stdout";
-
-    include_paths.push_back(cwd);
-    collect_include_paths(initializers.include_paths_c_str());
-    // collect_include_paths(initializers.include_paths_array());
-    collect_plugin_paths(initializers.plugin_paths_c_str());
-    // collect_plugin_paths(initializers.plugin_paths_array());
-
-    setup_color_map();
-
-    for (size_t i = 0, S = plugin_paths.size(); i < S; ++i) {
-      plugins.load_plugins(plugin_paths[i]);
-    }
-
-    for(auto fn : plugins.get_functions()) {
-      c_functions.push_back(fn);
-    }
-    for(auto fn : plugins.get_headers()) {
-      c_headers.push_back(fn);
-    }
-    for(auto fn : plugins.get_importers()) {
-      c_importers.push_back(fn);
-    }
-
-    sort (c_headers.begin(), c_headers.end(), sort_importers);
-    sort (c_importers.begin(), c_importers.end(), sort_importers);
-    string entry_point = initializers.entry_point();
-    if (!entry_point.empty()) {
-      string result(add_file(entry_point));
-      if (result.empty()) {
-        throw "File to read not found or unreadable: " + entry_point;
-      }
-    }
-
-    emitter.set_filename(resolve_relative_path(output_path, source_map_file, cwd));
-
-  }
-
-  void Context::add_c_function(Sass_Function_Entry function)
-  {
-    c_functions.push_back(function);
-  }
-  void Context::add_c_header(Sass_Importer_Entry header)
-  {
-    c_headers.push_back(header);
-    // need to sort the array afterwards (no big deal)
-    sort (c_headers.begin(), c_headers.end(), sort_importers);
-  }
-  void Context::add_c_importer(Sass_Importer_Entry importer)
-  {
-    c_importers.push_back(importer);
-    // need to sort the array afterwards (no big deal)
-    sort (c_importers.begin(), c_importers.end(), sort_importers);
-  }
-
-  Context::~Context()
-  {
-    // everything that gets put into sources will be freed by us
-    for (size_t n = 0; n < import_stack.size(); ++n) sass_delete_import(import_stack[n]);
-    // sources are allocated by strdup or malloc (overtaken from C code)
-    for (size_t i = 0; i < sources.size(); ++i) free((void*)sources[i]);
-    // clear inner structures (vectors)
-    sources.clear(); import_stack.clear();
-  }
-
-  void Context::setup_color_map()
-  {
-    size_t i = 0;
-    while (color_names[i]) {
-      string name(color_names[i]);
-      Color* value = new (mem) Color(ParserState("[COLOR TABLE]"),
-                                     color_values[i*4],
-                                     color_values[i*4+1],
-                                     color_values[i*4+2],
-                                     color_values[i*4+3]);
-      names_to_colors[name] = value;
-      // only map fully opaque colors
-      if (color_values[i*4+3] >= 1) {
-        int numval = static_cast<int>(color_values[i*4])*0x10000;
-        numval += static_cast<int>(color_values[i*4+1])*0x100;
-        numval += static_cast<int>(color_values[i*4+2]);
-        colors_to_names[numval] = name;
-      }
-      ++i;
-    }
-  }
-
-  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);
-
-      while (end) {
-        string path(beg, end - beg);
-        if (!path.empty()) {
-          if (*path.rbegin() != '/') path += '/';
-          include_paths.push_back(path);
-        }
-        beg = end + 1;
-        end = Prelexer::find_first<PATH_SEP>(beg);
-      }
-
-      string path(beg);
-      if (!path.empty()) {
-        if (*path.rbegin() != '/') path += '/';
-        include_paths.push_back(path);
-      }
-    }
-  }
-
-  void Context::collect_include_paths(const char** paths_array)
-  {
-    if (paths_array) {
-      for (size_t i = 0; paths_array[i]; i++) {
-        collect_include_paths(paths_array[i]);
-      }
-    }
-  }
-
-  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);
-
-      while (end) {
-        string path(beg, end - beg);
-        if (!path.empty()) {
-          if (*path.rbegin() != '/') path += '/';
-          plugin_paths.push_back(path);
-        }
-        beg = end + 1;
-        end = Prelexer::find_first<PATH_SEP>(beg);
-      }
-
-      string path(beg);
-      if (!path.empty()) {
-        if (*path.rbegin() != '/') path += '/';
-        plugin_paths.push_back(path);
-      }
-    }
-  }
-
-  void Context::collect_plugin_paths(const char** paths_array)
-  {
-    if (paths_array) {
-      for (size_t i = 0; paths_array[i]; i++) {
-        collect_plugin_paths(paths_array[i]);
-      }
-    }
-  }
-  void Context::add_source(string load_path, string abs_path, const char* contents)
-  {
-    sources.push_back(contents);
-    included_files.push_back(abs_path);
-    queue.push_back(Sass_Queued(load_path, abs_path, contents));
-    emitter.add_source_index(sources.size() - 1);
-    include_links.push_back(resolve_relative_path(abs_path, source_map_file, cwd));
-  }
-
-  // Add a new import file to the context
-  string Context::add_file(const string& file)
-  {
-    using namespace File;
-    string path(make_canonical_path(file));
-    string resolved(find_file(path, include_paths));
-    if (resolved == "") return resolved;
-    if (char* contents = read_file(resolved)) {
-      add_source(path, resolved, contents);
-      style_sheets[path] = 0;
-      return path;
-    }
-    return string("");
-  }
-
-  // Add a new import file to the context
-  // This has some previous directory context
-  string Context::add_file(const string& base, const string& file)
-  {
-    using namespace File;
-    string path(make_canonical_path(file));
-    string base_file(join_paths(base, path));
-    string resolved(resolve_file(base_file));
-    if (style_sheets.count(base_file)) return base_file;
-    if (char* contents = read_file(resolved)) {
-      add_source(base_file, resolved, contents);
-      style_sheets[base_file] = 0;
-      return base_file;
-    }
-    // now go the regular code path
-    return add_file(path);
-  }
-
-  void register_function(Context&, Signature sig, Native_Function f, Env* env);
-  void register_function(Context&, Signature sig, Native_Function f, size_t arity, Env* env);
-  void register_overload_stub(Context&, string name, Env* env);
-  void register_built_in_functions(Context&, Env* env);
-  void register_c_functions(Context&, Env* env, Sass_Function_List);
-  void register_c_function(Context&, Env* env, Sass_Function_Entry);
-
-  char* Context::compile_block(Block* root)
-  {
-    if (!root) return 0;
-    root->perform(&emitter);
-    emitter.finalize();
-    OutputBuffer emitted = emitter.get_buffer();
-    string output = emitted.buffer;
-    if (source_map_file != "" && !omit_source_map_url) {
-      output += linefeed + format_source_mapping_url(source_map_file);
-    }
-    return sass_strdup(output.c_str());
-  }
-
-  Block* Context::parse_file()
-  {
-    Block* root = 0;
-    for (size_t i = 0; i < queue.size(); ++i) {
-      Sass_Import_Entry import = sass_make_import(
-        queue[i].load_path.c_str(),
-        queue[i].abs_path.c_str(),
-        0, 0
-      );
-      import_stack.push_back(import);
-      Parser p(Parser::from_c_str(queue[i].source, *this, ParserState(queue[i].abs_path, queue[i].source, i)));
-      Block* ast = p.parse();
-      sass_delete_import(import_stack.back());
-      import_stack.pop_back();
-      if (i == 0) root = ast;
-      style_sheets[queue[i].load_path] = ast;
-    }
-    if (root == 0) return 0;
-    Env tge;
-    Backtrace backtrace(0, ParserState("", 0), "");
-    register_built_in_functions(*this, &tge);
-    for (size_t i = 0, S = c_functions.size(); i < S; ++i) {
-      register_c_function(*this, &tge, c_functions[i]);
-    }
-    Contextualize contextualize(*this, &tge, &backtrace);
-    Listize listize(*this);
-    Eval eval(*this, &contextualize, &listize, &tge, &backtrace);
-    Contextualize_Eval contextualize_eval(*this, &eval, &tge, &backtrace);
-    Expand expand(*this, &eval, &contextualize_eval, &tge, &backtrace);
-    Cssize cssize(*this, &tge, &backtrace);
-    root = root->perform(&expand)->block();
-    root = root->perform(&cssize)->block();
-    if (!subset_map.empty()) {
-      Extend extend(*this, subset_map);
-      root->perform(&extend);
-    }
-
-    Remove_Placeholders remove_placeholders(*this);
-    root->perform(&remove_placeholders);
-
-    return root;
-  }
-
-  Block* Context::parse_string()
-  {
-    if (!source_c_str) return 0;
-    queue.clear();
-    if(is_indented_syntax_src) {
-      char * contents = sass2scss(source_c_str, SASS2SCSS_PRETTIFY_1 | SASS2SCSS_KEEP_COMMENT);
-      add_source(input_path, input_path, contents);
-      delete [] source_c_str;
-      return parse_file();
-    }
-    add_source(input_path, input_path, source_c_str);
-    return parse_file();
-  }
-
-  char* Context::compile_file()
-  {
-    // returns NULL if something fails
-    return compile_block(parse_file());
-  }
-
-  char* Context::compile_string()
-  {
-    // returns NULL if something fails
-    return compile_block(parse_string());
-  }
-
-  string Context::format_source_mapping_url(const string& file)
-  {
-    string url = resolve_relative_path(file, output_path, cwd);
-    if (source_map_embed) {
-      string map = emitter.generate_source_map(*this);
-      istringstream is( map );
-      ostringstream buffer;
-      base64::encoder E;
-      E.encode(is, buffer);
-      url = "data:application/json;base64," + buffer.str();
-      url.erase(url.size() - 1);
-    }
-    return "/*# sourceMappingURL=" + url + " */";
-  }
-
-  char* Context::generate_source_map()
-  {
-    if (source_map_file == "") return 0;
-    char* result = 0;
-    string map = emitter.generate_source_map(*this);
-    result = sass_strdup(map.c_str());
-    return result;
-  }
-
-
-  std::vector<std::string> Context::get_included_files(size_t skip)
-  {
-      vector<string> includes = included_files;
-      if (includes.size() == 0) return includes;
-      std::sort( includes.begin() + skip, includes.end() );
-      includes.erase( includes.begin(), includes.begin() + skip );
-      includes.erase( std::unique( includes.begin(), includes.end() ), includes.end() );
-      // the skip solution seems more robust, as we may have real files named stdin
-      // includes.erase( std::remove( includes.begin(), includes.end(), "stdin" ), includes.end() );
-      return includes;
-  }
-
-  string Context::get_cwd()
-  {
-    return Sass::File::get_cwd();
-  }
-
-  void register_function(Context& ctx, Signature sig, Native_Function f, Env* env)
-  {
-    Definition* 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);
-    stringstream ss;
-    ss << def->name() << "[f]" << arity;
-    def->environment(env);
-    (*env)[ss.str()] = def;
-  }
-
-  void register_overload_stub(Context& ctx, string name, Env* env)
-  {
-    Definition* stub = new (ctx.mem) Definition(ParserState("[built-in function]"),
-                                            0,
-                                            name,
-                                            0,
-                                            0,
-                                            &ctx,
-                                            true);
-    (*env)[name + "[f]"] = stub;
-  }
-
-
-  void register_built_in_functions(Context& ctx, Env* env)
-  {
-    using namespace Functions;
-    // RGB Functions
-    register_function(ctx, rgb_sig, rgb, env);
-    register_overload_stub(ctx, "rgba", env);
-    register_function(ctx, rgba_4_sig, rgba_4, 4, env);
-    register_function(ctx, rgba_2_sig, rgba_2, 2, env);
-    register_function(ctx, red_sig, red, env);
-    register_function(ctx, green_sig, green, env);
-    register_function(ctx, blue_sig, blue, env);
-    register_function(ctx, mix_sig, mix, env);
-    // HSL Functions
-    register_function(ctx, hsl_sig, hsl, env);
-    register_function(ctx, hsla_sig, hsla, env);
-    register_function(ctx, hue_sig, hue, env);
-    register_function(ctx, saturation_sig, saturation, env);
-    register_function(ctx, lightness_sig, lightness, env);
-    register_function(ctx, adjust_hue_sig, adjust_hue, env);
-    register_function(ctx, lighten_sig, lighten, env);
-    register_function(ctx, darken_sig, darken, env);
-    register_function(ctx, saturate_sig, saturate, env);
-    register_function(ctx, desaturate_sig, desaturate, env);
-    register_function(ctx, grayscale_sig, grayscale, env);
-    register_function(ctx, complement_sig, complement, env);
-    register_function(ctx, invert_sig, invert, env);
-    // Opacity Functions
-    register_function(ctx, alpha_sig, alpha, env);
-    register_function(ctx, opacity_sig, alpha, env);
-    register_function(ctx, opacify_sig, opacify, env);
-    register_function(ctx, fade_in_sig, opacify, env);
-    register_function(ctx, transparentize_sig, transparentize, env);
-    register_function(ctx, fade_out_sig, transparentize, env);
-    // Other Color Functions
-    register_function(ctx, adjust_color_sig, adjust_color, env);
-    register_function(ctx, scale_color_sig, scale_color, env);
-    register_function(ctx, change_color_sig, change_color, env);
-    register_function(ctx, ie_hex_str_sig, ie_hex_str, env);
-    // String Functions
-    register_function(ctx, unquote_sig, sass_unquote, env);
-    register_function(ctx, quote_sig, sass_quote, env);
-    register_function(ctx, str_length_sig, str_length, env);
-    register_function(ctx, str_insert_sig, str_insert, env);
-    register_function(ctx, str_index_sig, str_index, env);
-    register_function(ctx, str_slice_sig, str_slice, env);
-    register_function(ctx, to_upper_case_sig, to_upper_case, env);
-    register_function(ctx, to_lower_case_sig, to_lower_case, env);
-    // Number Functions
-    register_function(ctx, percentage_sig, percentage, env);
-    register_function(ctx, round_sig, round, env);
-    register_function(ctx, ceil_sig, ceil, env);
-    register_function(ctx, floor_sig, floor, env);
-    register_function(ctx, abs_sig, abs, env);
-    register_function(ctx, min_sig, min, env);
-    register_function(ctx, max_sig, max, env);
-    register_function(ctx, random_sig, random, env);
-    // List Functions
-    register_function(ctx, length_sig, length, env);
-    register_function(ctx, nth_sig, nth, env);
-    register_function(ctx, set_nth_sig, set_nth, env);
-    register_function(ctx, index_sig, index, env);
-    register_function(ctx, join_sig, join, env);
-    register_function(ctx, append_sig, append, env);
-    register_function(ctx, zip_sig, zip, env);
-    register_function(ctx, list_separator_sig, list_separator, env);
-    // Map Functions
-    register_function(ctx, map_get_sig, map_get, env);
-    register_function(ctx, map_merge_sig, map_merge, env);
-    register_function(ctx, map_remove_sig, map_remove, env);
-    register_function(ctx, map_keys_sig, map_keys, env);
-    register_function(ctx, map_values_sig, map_values, env);
-    register_function(ctx, map_has_key_sig, map_has_key, env);
-    register_function(ctx, keywords_sig, keywords, env);
-    // Introspection Functions
-    register_function(ctx, type_of_sig, type_of, env);
-    register_function(ctx, unit_sig, unit, env);
-    register_function(ctx, unitless_sig, unitless, env);
-    register_function(ctx, comparable_sig, comparable, env);
-    register_function(ctx, variable_exists_sig, variable_exists, env);
-    register_function(ctx, global_variable_exists_sig, global_variable_exists, env);
-    register_function(ctx, function_exists_sig, function_exists, env);
-    register_function(ctx, mixin_exists_sig, mixin_exists, env);
-    register_function(ctx, feature_exists_sig, feature_exists, env);
-    register_function(ctx, call_sig, call, env);
-    // Boolean Functions
-    register_function(ctx, not_sig, sass_not, env);
-    register_function(ctx, if_sig, sass_if, env);
-    // Misc Functions
-    register_function(ctx, inspect_sig, inspect, env);
-    register_function(ctx, unique_id_sig, unique_id, env);
-    // Selector functions
-    register_function(ctx, is_superselector_sig, is_superselector, env);
-  }
-
-  void register_c_functions(Context& ctx, Env* env, Sass_Function_List descrs)
-  {
-    while (descrs && *descrs) {
-      register_c_function(ctx, env, *descrs);
-      ++descrs;
-    }
-  }
-  void register_c_function(Context& ctx, Env* env, Sass_Function_Entry descr)
-  {
-    Definition* def = make_c_function(descr, ctx);
-    def->environment(env);
-    (*env)[def->name() + "[f]"] = def;
-  }
-
-
-}
diff --git a/libsass/context.hpp b/libsass/context.hpp
deleted file mode 100644
--- a/libsass/context.hpp
+++ /dev/null
@@ -1,157 +0,0 @@
-#ifndef SASS_CONTEXT_H
-#define SASS_CONTEXT_H
-
-#include <string>
-#include <vector>
-#include <map>
-
-#define BUFFERSIZE 255
-#include "b64/encode.h"
-
-#include "ast_fwd_decl.hpp"
-#include "kwd_arg_macros.hpp"
-#include "memory_manager.hpp"
-#include "environment.hpp"
-#include "source_map.hpp"
-#include "subset_map.hpp"
-#include "output.hpp"
-#include "plugins.hpp"
-#include "sass_functions.h"
-
-struct Sass_Function;
-
-namespace Sass {
-  using namespace std;
-  struct Sass_Queued {
-    string abs_path;
-    string load_path;
-    const char* source;
-  public:
-    Sass_Queued(const string& load_path, const string& abs_path, const char* source);
-  };
-
-  class Context {
-  public:
-    size_t head_imports;
-    Memory_Manager<AST_Node> mem;
-
-    struct Sass_Options* c_options;
-    struct Sass_Compiler* c_compiler;
-    const char* source_c_str;
-
-    // c-strs containing Sass file contents
-    // we will overtake ownership of memory
-    vector<const char*> sources;
-    // absolute paths to includes
-    vector<string> included_files;
-    // relative links to includes
-    vector<string> include_links;
-    // vectors above have same size
-
-    vector<string> plugin_paths; // relative paths to load plugins
-    vector<string> include_paths; // lookup paths for includes
-    vector<Sass_Queued> queue; // queue of files to be parsed
-    map<string, Block*> style_sheets; // map of paths to ASTs
-    // SourceMap source_map;
-    Output emitter;
-
-    vector<Sass_Importer_Entry> c_headers;
-    vector<Sass_Importer_Entry> c_importers;
-    vector<Sass_Function_Entry> c_functions;
-
-    void add_c_header(Sass_Importer_Entry header);
-    void add_c_importer(Sass_Importer_Entry importer);
-    void add_c_function(Sass_Function_Entry function);
-
-    string       indent; // String to be used for indentation
-    string       linefeed; // String to be used for line feeds
-    string       input_path; // for relative paths in src-map
-    string       output_path; // for relative paths to the output
-    bool         source_comments; // for inline debug comments in css output
-    Output_Style output_style; // output style for the generated css code
-    string       source_map_file; // path to source map file (enables feature)
-    string       source_map_root; // path for sourceRoot property (pass-through)
-    bool         source_map_embed; // embed in sourceMappingUrl (as data-url)
-    bool         source_map_contents; // insert included contents into source map
-    bool         omit_source_map_url; // disable source map comment in css output
-    bool         is_indented_syntax_src; // treat source string as sass
-
-    // overload import calls
-    vector<Sass_Import_Entry> import_stack;
-
-    map<string, Color*> names_to_colors;
-    map<int, string>    colors_to_names;
-
-    size_t precision; // precision for outputting fractional numbers
-
-    KWD_ARG_SET(Data) {
-      KWD_ARG(Data, struct Sass_Options*, c_options);
-      KWD_ARG(Data, struct Sass_Compiler*, c_compiler);
-      KWD_ARG(Data, const char*,     source_c_str);
-      KWD_ARG(Data, string,          entry_point);
-      KWD_ARG(Data, string,          input_path);
-      KWD_ARG(Data, string,          output_path);
-      KWD_ARG(Data, string,          indent);
-      KWD_ARG(Data, string,          linefeed);
-      KWD_ARG(Data, const char*,     include_paths_c_str);
-      KWD_ARG(Data, const char*,     plugin_paths_c_str);
-      // KWD_ARG(Data, const char**,    include_paths_array);
-      // KWD_ARG(Data, const char**,    plugin_paths_array);
-      KWD_ARG(Data, vector<string>,  include_paths);
-      KWD_ARG(Data, vector<string>,  plugin_paths);
-      KWD_ARG(Data, bool,            source_comments);
-      KWD_ARG(Data, Output_Style,    output_style);
-      KWD_ARG(Data, string,          source_map_file);
-      KWD_ARG(Data, string,          source_map_root);
-      KWD_ARG(Data, bool,            omit_source_map_url);
-      KWD_ARG(Data, bool,            is_indented_syntax_src);
-      KWD_ARG(Data, size_t,          precision);
-      KWD_ARG(Data, bool,            source_map_embed);
-      KWD_ARG(Data, bool,            source_map_contents);
-    };
-
-    Context(Data);
-    ~Context();
-    static string get_cwd();
-    void setup_color_map();
-
-    Block* parse_file();
-    Block* parse_string();
-    void add_source(string, string, const char*);
-
-    string add_file(const string& file);
-    string add_file(const string& base, const string& file);
-
-
-    // allow to optionally overwrite the input path
-    // default argument for input_path is string("stdin")
-    // usefull to influence the source-map generating etc.
-    char* compile_file();
-    char* compile_string();
-    char* compile_block(Block* root);
-    char* generate_source_map();
-
-    vector<string> get_included_files(size_t skip = 0);
-
-  private:
-    void collect_plugin_paths(const char* paths_str);
-    void collect_plugin_paths(const char** paths_array);
-    void collect_include_paths(const char* paths_str);
-    void collect_include_paths(const char** paths_array);
-    string format_source_mapping_url(const string& file);
-
-    string cwd;
-    Plugins plugins;
-
-    // void register_built_in_functions(Env* env);
-    // void register_function(Signature sig, Native_Function f, Env* env);
-    // void register_function(Signature sig, Native_Function f, size_t arity, Env* env);
-    // void register_overload_stub(string name, Env* env);
-
-  public:
-    Subset_Map<string, pair<Complex_Selector*, Compound_Selector*> > subset_map;
-  };
-
-}
-
-#endif
diff --git a/libsass/contextualize.cpp b/libsass/contextualize.cpp
deleted file mode 100644
--- a/libsass/contextualize.cpp
+++ /dev/null
@@ -1,148 +0,0 @@
-#include "contextualize.hpp"
-#include "ast.hpp"
-#include "eval.hpp"
-#include "backtrace.hpp"
-#include "to_string.hpp"
-#include "parser.hpp"
-
-namespace Sass {
-
-  Contextualize::Contextualize(Context& ctx, Env* env, Backtrace* bt, Selector* placeholder, Selector* extender)
-  : ctx(ctx), env(env), backtrace(bt), parent(0), placeholder(placeholder), extender(extender)
-  { }
-
-  Contextualize::~Contextualize() { }
-
-  Selector* Contextualize::fallback_impl(AST_Node* n)
-  { return parent; }
-
-  Contextualize* Contextualize::with(Selector* s, Env* e, Backtrace* bt, Selector* p, Selector* ex)
-  {
-    parent = s;
-    env = e;
-    backtrace = bt;
-    placeholder = p;
-    extender = ex;
-    return this;
-  }
-
-  Selector* Contextualize::operator()(Selector_List* s)
-  {
-    Selector_List* p = static_cast<Selector_List*>(parent);
-    Selector_List* ss = 0;
-    if (p) {
-      ss = new (ctx.mem) Selector_List(s->pstate(), p->length() * s->length());
-      if (s->length() == 0) {
-          Complex_Selector* comb = static_cast<Complex_Selector*>(parent->perform(this));
-          if (parent->has_line_feed()) comb->has_line_feed(true);
-          if (comb) *ss << comb;
-          else cerr << "Warning: contextualize returned null" << endl;
-      }
-      for (size_t i = 0, L = p->length(); i < L; ++i) {
-        for (size_t j = 0, L = s->length(); j < L; ++j) {
-          parent = (*p)[i];
-          Complex_Selector* comb = static_cast<Complex_Selector*>((*s)[j]->perform(this));
-          if (parent->has_line_feed()) comb->has_line_feed(true);
-          if (comb) *ss << comb;
-          else cerr << "Warning: contextualize returned null" << endl;
-        }
-      }
-    }
-    else {
-      ss = new (ctx.mem) Selector_List(s->pstate(), s->length());
-      for (size_t j = 0, L = s->length(); j < L; ++j) {
-        Complex_Selector* comb = static_cast<Complex_Selector*>((*s)[j]->perform(this));
-        if (comb) *ss << comb;
-      }
-    }
-    return ss->length() ? ss : 0;
-  }
-
-  Selector* Contextualize::operator()(Complex_Selector* s)
-  {
-    To_String to_string(&ctx);
-    Complex_Selector* ss = new (ctx.mem) Complex_Selector(*s);
-    // ss->last_block(s->last_block());
-    // ss->media_block(s->media_block());
-    Compound_Selector* new_head = 0;
-    Complex_Selector* new_tail = 0;
-    if (ss->head()) {
-      new_head = static_cast<Compound_Selector*>(s->head()->perform(this));
-      ss->head(new_head);
-    }
-    if (ss->tail()) {
-      new_tail = static_cast<Complex_Selector*>(s->tail()->perform(this));
-      // new_tail->last_block(s->last_block());
-      // new_tail->media_block(s->media_block());
-      ss->tail(new_tail);
-    }
-    if ((new_head && new_head->has_placeholder()) || (new_tail && new_tail->has_placeholder())) {
-      ss->has_placeholder(true);
-    }
-    else {
-      ss->has_placeholder(false);
-    }
-    if (!ss->head() && ss->combinator() == Complex_Selector::ANCESTOR_OF) {
-      return ss->tail();
-    }
-    else {
-      return ss;
-    }
-  }
-
-  Selector* Contextualize::operator()(Compound_Selector* s)
-  {
-    To_String to_string(&ctx);
-    if (placeholder && extender && s->perform(&to_string) == placeholder->perform(&to_string)) {
-      return extender;
-    }
-    Compound_Selector* ss = new (ctx.mem) Compound_Selector(s->pstate(), s->length());
-    ss->last_block(s->last_block());
-    ss->media_block(s->media_block());
-    ss->has_line_break(s->has_line_break());
-    for (size_t i = 0, L = s->length(); i < L; ++i) {
-      Simple_Selector* simp = static_cast<Simple_Selector*>((*s)[i]->perform(this));
-      if (simp) *ss << simp;
-    }
-    return ss->length() ? ss : 0;
-  }
-
-  Selector* Contextualize::operator()(Wrapped_Selector* s)
-  {
-    Selector* old_parent = parent;
-    parent = 0;
-    Wrapped_Selector* neg = new (ctx.mem) Wrapped_Selector(s->pstate(),
-                                                           s->name(),
-                                                           s->selector()->perform(this));
-    parent = old_parent;
-    return neg;
-  }
-
-  Selector* Contextualize::operator()(Pseudo_Selector* s)
-  { return s; }
-
-  Selector* Contextualize::operator()(Selector_Qualifier* s)
-  { return s; }
-
-  Selector* Contextualize::operator()(Type_Selector* s)
-  { return s; }
-
-  Selector* Contextualize::operator()(Selector_Placeholder* p)
-  {
-    To_String to_string(&ctx);
-    if (placeholder && extender && p->perform(&to_string) == placeholder->perform(&to_string)) {
-      return extender;
-    }
-    else {
-      return p;
-    }
-  }
-
-  Selector* Contextualize::operator()(Selector_Reference* s)
-  {
-    if (!parent) return 0;
-    Selector_Reference* ss = new (ctx.mem) Selector_Reference(*s);
-    ss->selector(parent);
-    return ss;
-  }
-}
diff --git a/libsass/contextualize.hpp b/libsass/contextualize.hpp
deleted file mode 100644
--- a/libsass/contextualize.hpp
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef SASS_CONTEXTUALIZE_H
-#define SASS_CONTEXTUALIZE_H
-
-#include "context.hpp"
-#include "operation.hpp"
-#include "environment.hpp"
-#include "ast_fwd_decl.hpp"
-
-namespace Sass {
-  struct Backtrace;
-
-  typedef Environment<AST_Node*> Env;
-
-  class Contextualize : public Operation_CRTP<Selector*, Contextualize> {
-
-
-  public:
-    Context&   ctx;
-    Env*       env;
-    Backtrace* backtrace;
-    Selector*  parent;
-    Selector* placeholder;
-    Selector* extender;
-
-    Selector* fallback_impl(AST_Node* n);
-    Contextualize(Context&, Env*, Backtrace*, Selector* placeholder = 0, Selector* extender = 0);
-    virtual ~Contextualize();
-    Contextualize* with(Selector*, Env*, Backtrace*, Selector* placeholder = 0, Selector* extender = 0);
-    using Operation<Selector*>::operator();
-
-    Selector* operator()(Selector_List*);
-    Selector* operator()(Complex_Selector*);
-    Selector* operator()(Compound_Selector*);
-    Selector* operator()(Wrapped_Selector*);
-    Selector* operator()(Pseudo_Selector*);
-    Selector* operator()(Selector_Qualifier*);
-    Selector* operator()(Type_Selector*);
-    Selector* operator()(Selector_Placeholder*);
-    Selector* operator()(Selector_Reference*);
-
-    template <typename U>
-    Selector* fallback(U x) { return fallback_impl(x); }
-  };
-}
-
-#endif
diff --git a/libsass/contextualize_eval.cpp b/libsass/contextualize_eval.cpp
deleted file mode 100644
--- a/libsass/contextualize_eval.cpp
+++ /dev/null
@@ -1,93 +0,0 @@
-#include "contextualize_eval.hpp"
-#include "ast.hpp"
-#include "eval.hpp"
-#include "backtrace.hpp"
-#include "to_string.hpp"
-#include "parser.hpp"
-
-namespace Sass {
-
-  Contextualize_Eval::Contextualize_Eval(Context& ctx, Eval* eval, Env* env, Backtrace* bt)
-  : Contextualize(ctx, env, bt), eval(eval)
-  { }
-
-  Contextualize_Eval::~Contextualize_Eval() { }
-
-  Selector* Contextualize_Eval::fallback_impl(AST_Node* n)
-  {
-    return Contextualize::fallback_impl(n);
-  }
-
-  Contextualize_Eval* Contextualize_Eval::with(Selector* s, Env* e, Backtrace* bt, Selector* p, Selector* ex)
-  {
-    Contextualize::with(s, e, bt, p, ex);
-    eval = eval->with(s, e, bt, p, ex);
-    return this;
-  }
-
-  Selector* Contextualize_Eval::operator()(Selector_Schema* s)
-  {
-    To_String to_string;
-    string result_str(s->contents()->perform(eval)->perform(&to_string));
-    result_str += '{'; // the parser looks for a brace to end the selector
-    Selector* result_sel = Parser::from_c_str(result_str.c_str(), ctx, s->pstate()).parse_selector_group();
-    return result_sel->perform(this);
-  }
-
-  Selector* Contextualize_Eval::operator()(Selector_List* s)
-  {
-    return Contextualize::operator ()(s);
-  }
-
-  Selector* Contextualize_Eval::operator()(Complex_Selector* s)
-  {
-    return Contextualize::operator ()(s);
-  }
-
-  Selector* Contextualize_Eval::operator()(Compound_Selector* s)
-  {
-    return Contextualize::operator ()(s);
-  }
-
-  Selector* Contextualize_Eval::operator()(Wrapped_Selector* s)
-  {
-    return Contextualize::operator ()(s);
-  }
-
-  Selector* Contextualize_Eval::operator()(Pseudo_Selector* s)
-  {
-    return Contextualize::operator ()(s);
-  }
-
-  Selector* Contextualize_Eval::operator()(Attribute_Selector* s)
-  {
-    // the value might be interpolated; evaluate it
-    String* v = s->value();
-    if (v && eval) {
-     Eval* eval_with = eval->with(parent, env, backtrace);
-     v = static_cast<String*>(v->perform(eval_with));
-    }
-    To_String toString;
-    Attribute_Selector* ss = new (ctx.mem) Attribute_Selector(*s);
-    ss->value(v);
-    return ss;
-  }
-
-  Selector* Contextualize_Eval::operator()(Selector_Qualifier* s)
-  {     return Contextualize::operator ()(s);
- }
-
-  Selector* Contextualize_Eval::operator()(Type_Selector* s)
-  {     return Contextualize::operator ()(s);
- }
-
-  Selector* Contextualize_Eval::operator()(Selector_Placeholder* p)
-  {
-    return Contextualize::operator ()(p);
-  }
-
-  Selector* Contextualize_Eval::operator()(Selector_Reference* s)
-  {
-    return Contextualize::operator ()(s);
-  }
-}
diff --git a/libsass/contextualize_eval.hpp b/libsass/contextualize_eval.hpp
deleted file mode 100644
--- a/libsass/contextualize_eval.hpp
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifndef SASS_CONTEXTUALIZE_EVAL_H
-#define SASS_CONTEXTUALIZE_EVAL_H
-
-#include "eval.hpp"
-#include "context.hpp"
-#include "operation.hpp"
-#include "environment.hpp"
-#include "ast_fwd_decl.hpp"
-
-namespace Sass {
-  struct Backtrace;
-
-  typedef Environment<AST_Node*> Env;
-
-  class Contextualize_Eval : public Contextualize {
-
-    Eval*      eval;
-
-    Selector* fallback_impl(AST_Node* n);
-
-  public:
-    Contextualize_Eval(Context&, Eval*, Env*, Backtrace*);
-    virtual ~Contextualize_Eval();
-    Contextualize_Eval* with(Selector*, Env*, Backtrace*, Selector* placeholder = 0, Selector* extender = 0);
-    using Operation<Selector*>::operator();
-
-    Selector* operator()(Selector_Schema*);
-    Selector* operator()(Selector_List*);
-    Selector* operator()(Complex_Selector*);
-    Selector* operator()(Compound_Selector*);
-    Selector* operator()(Wrapped_Selector*);
-    Selector* operator()(Pseudo_Selector*);
-    Selector* operator()(Attribute_Selector*);
-    Selector* operator()(Selector_Qualifier*);
-    Selector* operator()(Type_Selector*);
-    Selector* operator()(Selector_Placeholder*);
-    Selector* operator()(Selector_Reference*);
-
-    template <typename U>
-    Selector* fallback(U x) { return fallback_impl(x); }
-  };
-}
-
-#endif
diff --git a/libsass/cssize.cpp b/libsass/cssize.cpp
deleted file mode 100644
--- a/libsass/cssize.cpp
+++ /dev/null
@@ -1,551 +0,0 @@
-#include <iostream>
-#include <typeinfo>
-
-#include "cssize.hpp"
-#include "to_string.hpp"
-#include "context.hpp"
-#include "backtrace.hpp"
-
-namespace Sass {
-
-  Cssize::Cssize(Context& ctx, Env* env, Backtrace* bt)
-  : ctx(ctx),
-    env(env),
-    block_stack(vector<Block*>()),
-    p_stack(vector<Statement*>()),
-    backtrace(bt)
-  {  }
-
-  Statement* Cssize::parent()
-  {
-    return p_stack.size() ? p_stack.back() : block_stack.front();
-  }
-
-  Statement* Cssize::operator()(Block* b)
-  {
-    Env new_env;
-    new_env.link(*env);
-    env = &new_env;
-    Block* bb = new (ctx.mem) Block(b->pstate(), b->length(), b->is_root());
-    // bb->tabs(b->tabs());
-    block_stack.push_back(bb);
-    append_block(b);
-    block_stack.pop_back();
-    env = env->parent();
-    return bb;
-  }
-
-  Statement* Cssize::operator()(At_Rule* r)
-  {
-    if (!r->block() || !r->block()->length()) return r;
-
-    if (parent()->statement_type() == Statement::RULESET)
-    {
-      return (r->is_keyframes()) ? new (ctx.mem) Bubble(r->pstate(), r) : bubble(r);
-    }
-
-    p_stack.push_back(r);
-    At_Rule* rr = new (ctx.mem) At_Rule(r->pstate(),
-                                        r->keyword(),
-                                        r->selector(),
-                                        r->block() ? r->block()->perform(this)->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];
-      if (s->statement_type() != Statement::BUBBLE) directive_exists = true;
-      else {
-        s = static_cast<Bubble*>(s)->node();
-        if (s->statement_type() != Statement::DIRECTIVE) directive_exists = false;
-        else directive_exists = (static_cast<At_Rule*>(s)->keyword() == rr->keyword());
-      }
-
-    }
-
-    Block* result = new (ctx.mem) Block(rr->pstate());
-    if (!(directive_exists || rr->is_keyframes()))
-    {
-      At_Rule* empty_node = static_cast<At_Rule*>(rr);
-      empty_node->block(new (ctx.mem) Block(rr->block() ? rr->block()->pstate() : rr->pstate()));
-      *result << empty_node;
-    }
-
-    Statement* ss = debubble(rr->block() ? rr->block() : new (ctx.mem) Block(rr->pstate()), rr);
-    for (size_t i = 0, L = ss->block()->length(); i < L; ++i) {
-      *result << (*ss->block())[i];
-    }
-
-    return result;
-  }
-
-  Statement* Cssize::operator()(Keyframe_Rule* r)
-  {
-    if (!r->block() || !r->block()->length()) return r;
-
-    Keyframe_Rule* rr = new (ctx.mem) Keyframe_Rule(r->pstate(),
-                                                    r->block()->perform(this)->block());
-    if (r->selector()) rr->selector(r->selector());
-
-    return debubble(rr->block(), rr)->block();
-  }
-
-  Statement* Cssize::operator()(Ruleset* r)
-  {
-    p_stack.push_back(r);
-    Ruleset* rr = new (ctx.mem) Ruleset(r->pstate(),
-                                        r->selector(),
-                                        r->block()->perform(this)->block());
-    // rr->tabs(r->block()->tabs());
-    p_stack.pop_back();
-
-    Block* props = new (ctx.mem) Block(rr->block()->pstate());
-    Block* rules = new (ctx.mem) 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;
-    }
-
-    if (props->length())
-    {
-      Block* bb = new (ctx.mem) Block(rr->block()->pstate());
-      *bb += props;
-      rr->block(bb);
-
-      for (size_t i = 0, L = rules->length(); i < L; i++)
-      {
-        (*rules)[i]->tabs((*rules)[i]->tabs() + 1);
-      }
-
-      rules->unshift(rr);
-    }
-
-    rules = debubble(rules)->block();
-
-    if (!(!rules->length() ||
-          !bubblable(rules->last()) ||
-          parent()->statement_type() == Statement::RULESET))
-    {
-      rules->last()->group_end(true);
-    }
-
-    return rules;
-  }
-
-  Statement* Cssize::operator()(Media_Block* m)
-  {
-    if (parent()->statement_type() == Statement::RULESET)
-    { return bubble(m); }
-
-    if (parent()->statement_type() == Statement::MEDIA)
-    { return new (ctx.mem) Bubble(m->pstate(), m); }
-
-    p_stack.push_back(m);
-
-    Media_Block* mm = new (ctx.mem) Media_Block(m->pstate(),
-                                                m->media_queries(),
-                                                m->block()->perform(this)->block());
-    mm->tabs(m->tabs());
-
-    p_stack.pop_back();
-
-    return debubble(mm->block(), mm)->block();
-  }
-
-  Statement* Cssize::operator()(Feature_Block* m)
-  {
-    if (!m->block()->length())
-    { return m; }
-
-    if (parent()->statement_type() == Statement::RULESET)
-    { return bubble(m); }
-
-    p_stack.push_back(m);
-
-    Feature_Block* mm = new (ctx.mem) Feature_Block(m->pstate(),
-                                                    m->feature_queries(),
-                                                    m->block()->perform(this)->block());
-    mm->tabs(m->tabs());
-
-    p_stack.pop_back();
-
-    return debubble(mm->block(), mm)->block();
-  }
-
-  Statement* Cssize::operator()(At_Root_Block* m)
-  {
-    bool tmp = false;
-    for (size_t i = 0, L = p_stack.size(); i < L; ++i) {
-      Statement* s = p_stack[i];
-      tmp |= m->exclude_node(s);
-    }
-
-    if (!tmp)
-    {
-      Block* bb = m->block()->perform(this)->block();
-      for (size_t i = 0, L = bb->length(); i < L; ++i) {
-        // (bb->elements())[i]->tabs(m->tabs());
-        if (bubblable((*bb)[i])) (*bb)[i]->tabs((*bb)[i]->tabs() + m->tabs());
-      }
-      if (bb->length() && bubblable(bb->last())) bb->last()->group_end(m->group_end());
-      return bb;
-    }
-
-    if (m->exclude_node(parent()))
-    {
-      return new (ctx.mem) Bubble(m->pstate(), m);
-    }
-
-    return bubble(m);
-  }
-
-  Statement* Cssize::bubble(At_Rule* m)
-  {
-    Block* bb = new (ctx.mem) Block(this->parent()->pstate());
-    Has_Block* new_rule = static_cast<Has_Block*>(shallow_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];
-    }
-
-    Block* wrapper_block = new (ctx.mem) Block(m->block() ? m->block()->pstate() : m->pstate());
-    *wrapper_block << new_rule;
-    At_Rule* mm = new (ctx.mem) At_Rule(m->pstate(),
-                                        m->keyword(),
-                                        m->selector(),
-                                        wrapper_block);
-    if (m->value()) mm->value(m->value());
-
-    Bubble* bubble = new (ctx.mem) Bubble(mm->pstate(), mm);
-    return bubble;
-  }
-
-  Statement* Cssize::bubble(At_Root_Block* m)
-  {
-    Block* bb = new (ctx.mem) Block(this->parent()->pstate());
-    Has_Block* new_rule = static_cast<Has_Block*>(shallow_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];
-    }
-
-    Block* wrapper_block = new (ctx.mem) Block(m->block()->pstate());
-    *wrapper_block << new_rule;
-    At_Root_Block* mm = new (ctx.mem) At_Root_Block(m->pstate(),
-                                                    wrapper_block,
-                                                    m->expression());
-
-    Bubble* bubble = new (ctx.mem) Bubble(mm->pstate(), mm);
-    return bubble;
-  }
-
-  Statement* Cssize::bubble(Feature_Block* m)
-  {
-    Ruleset* parent = static_cast<Ruleset*>(shallow_copy(this->parent()));
-
-    Block* bb = new (ctx.mem) Block(parent->block()->pstate());
-    Ruleset* new_rule = new (ctx.mem) 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];
-    }
-
-    Block* wrapper_block = new (ctx.mem) Block(m->block()->pstate());
-    *wrapper_block << new_rule;
-    Feature_Block* mm = new (ctx.mem) Feature_Block(m->pstate(),
-                                                    m->feature_queries(),
-                                                    wrapper_block);
-
-    mm->tabs(m->tabs());
-
-    Bubble* bubble = new (ctx.mem) Bubble(mm->pstate(), mm);
-    return bubble;
-  }
-
-  Statement* Cssize::bubble(Media_Block* m)
-  {
-    Ruleset* parent = static_cast<Ruleset*>(shallow_copy(this->parent()));
-
-    Block* bb = new (ctx.mem) Block(parent->block()->pstate());
-    Ruleset* new_rule = new (ctx.mem) 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];
-    }
-
-    Block* wrapper_block = new (ctx.mem) Block(m->block()->pstate());
-    *wrapper_block << new_rule;
-    Media_Block* mm = new (ctx.mem) Media_Block(m->pstate(),
-                                                m->media_queries(),
-                                                wrapper_block,
-                                                m->selector());
-
-    mm->tabs(m->tabs());
-
-    Bubble* bubble = new (ctx.mem) Bubble(mm->pstate(), mm);
-
-    return bubble;
-  }
-
-  bool Cssize::bubblable(Statement* s)
-  {
-    return s->statement_type() == Statement::RULESET || s->bubbles();
-  }
-
-  Statement* Cssize::flatten(Statement* s)
-  {
-    Block* bb = s->block();
-    Block* result = 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];
-        }
-      }
-      else {
-        *result << ss;
-      }
-    }
-    return result;
-  }
-
-  vector<pair<bool, Block*>> Cssize::slice_by_bubble(Statement* b)
-  {
-    vector<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;
-
-      if (!results.empty() && results.back().first == key)
-      {
-        Block* wrapper_block = results.back().second;
-        *wrapper_block << value;
-      }
-      else
-      {
-        Block* wrapper_block = new (ctx.mem) Block(value->pstate());
-        *wrapper_block << value;
-        results.push_back(make_pair(key, wrapper_block));
-      }
-    }
-    return results;
-  }
-
-  Statement* Cssize::shallow_copy(Statement* s)
-  {
-    switch (s->statement_type())
-    {
-      case Statement::RULESET:
-        return new (ctx.mem) Ruleset(*static_cast<Ruleset*>(s));
-      case Statement::MEDIA:
-        return new (ctx.mem) Media_Block(*static_cast<Media_Block*>(s));
-      case Statement::BUBBLE:
-        return new (ctx.mem) Bubble(*static_cast<Bubble*>(s));
-      case Statement::DIRECTIVE:
-        return new (ctx.mem) At_Rule(*static_cast<At_Rule*>(s));
-      case Statement::FEATURE:
-        return new (ctx.mem) Feature_Block(*static_cast<Feature_Block*>(s));
-      case Statement::ATROOT:
-        return new (ctx.mem) At_Root_Block(*static_cast<At_Root_Block*>(s));
-      case Statement::KEYFRAMERULE:
-        return 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_Constant* msg = new (ctx.mem) String_Constant(ParserState("[WARN]"), string("`CSSize` can't clone ") + typeid(*s).name());
-        return new (ctx.mem) Warning(ParserState("[WARN]"), msg);
-    }
-  }
-
-  Statement* Cssize::debubble(Block* children, Statement* parent)
-  {
-    Has_Block* previous_parent = 0;
-    vector<pair<bool, Block*>> baz = slice_by_bubble(children);
-    Block* result = new (ctx.mem) 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;
-
-      if (!is_bubble) {
-        if (!parent) {
-          *result << slice;
-        }
-        else if (previous_parent) {
-          *previous_parent->block() += slice;
-        }
-        else {
-          previous_parent = static_cast<Has_Block*>(shallow_copy(parent));
-          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;
-        }
-        continue;
-      }
-
-      Block* wrapper_block = 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]);
-
-        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())
-        {
-          ss = b->node();
-        }
-        else
-        {
-          List* mq = merge_media_queries(static_cast<Media_Block*>(b->node()), static_cast<Media_Block*>(parent));
-          if (mq->length()) {
-            static_cast<Media_Block*>(b->node())->media_queries(mq);
-            ss = b->node();
-          }
-        }
-
-        if (!ss) continue;
-
-        ss->tabs(ss->tabs() + b->tabs());
-        ss->group_end(b->group_end());
-
-        if (!ss) continue;
-
-        Block* bb = 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;
-
-        if (wrapper->block()->length()) {
-          previous_parent = 0;
-        }
-      }
-
-      if (wrapper_block) {
-        *result << flatten(wrapper_block);
-      }
-    }
-
-    return flatten(result);
-  }
-
-  Statement* Cssize::fallback_impl(AST_Node* n)
-  {
-    return static_cast<Statement*>(n);
-  }
-
-  void Cssize::append_block(Block* b)
-  {
-    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];
-        }
-      }
-      else if (ith) {
-        *current_block << ith;
-      }
-    }
-  }
-
-  List* Cssize::merge_media_queries(Media_Block* m1, Media_Block* m2)
-  {
-    List* qq = new (ctx.mem) List(m1->media_queries()->pstate(),
-                                  m1->media_queries()->length(),
-                                  List::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;
-      }
-    }
-
-    return qq;
-  }
-
-
-  Media_Query* Cssize::merge_media_query(Media_Query* mq1, Media_Query* mq2)
-  {
-    To_String to_string(&ctx);
-
-    string type;
-    string mod;
-
-    string m1 = string(mq1->is_restricted() ? "only" : mq1->is_negated() ? "not" : "");
-    string t1 = mq1->media_type() ? mq1->media_type()->perform(&to_string) : "";
-    string m2 = string(mq2->is_restricted() ? "only" : mq1->is_negated() ? "not" : "");
-    string t2 = mq2->media_type() ? mq2->media_type()->perform(&to_string) : "";
-
-
-    if (t1.empty()) t1 = t2;
-    if (t2.empty()) t2 = t1;
-
-    if ((m1 == "not") ^ (m2 == "not")) {
-      if (t1 == t2) {
-        return 0;
-      }
-      type = m1 == "not" ? t2 : t1;
-      mod = m1 == "not" ? m2 : m1;
-    }
-    else if (m1 == "not" && m2 == "not") {
-      if (t1 != t2) {
-        return 0;
-      }
-      type = t1;
-      mod = "not";
-    }
-    else if (t1 != t2) {
-      return 0;
-    } else {
-      type = t1;
-      mod = m1.empty() ? m2 : m1;
-    }
-
-    Media_Query* mm = new (ctx.mem) Media_Query(
-      mq1->pstate(), 0,
-      mq1->length() + mq2->length(), mod == "not", mod == "only"
-    );
-
-    if (!type.empty()) {
-      mm->media_type(new (ctx.mem) String_Constant(mq1->pstate(), type));
-    }
-
-    *mm += mq2;
-    *mm += mq1;
-    return mm;
-  }
-}
diff --git a/libsass/cssize.hpp b/libsass/cssize.hpp
deleted file mode 100644
--- a/libsass/cssize.hpp
+++ /dev/null
@@ -1,82 +0,0 @@
-#ifndef SASS_CSSIZE_H
-#define SASS_CSSIZE_H
-
-#include <vector>
-#include <iostream>
-
-#include "ast.hpp"
-#include "context.hpp"
-#include "operation.hpp"
-#include "environment.hpp"
-
-namespace Sass {
-  using namespace std;
-
-  typedef Environment<AST_Node*> Env;
-  struct Backtrace;
-
-  class Cssize : public Operation_CRTP<Statement*, Cssize> {
-
-    Context&            ctx;
-    Env*                env;
-    vector<Block*>      block_stack;
-    vector<Statement*>  p_stack;
-    Backtrace*          backtrace;
-
-    Statement* fallback_impl(AST_Node* n);
-
-  public:
-    Cssize(Context&, Env*, Backtrace*);
-    virtual ~Cssize() { }
-
-    using Operation<Statement*>::operator();
-
-    Statement* operator()(Block*);
-    Statement* operator()(Ruleset*);
-    // Statement* operator()(Propset*);
-    // Statement* operator()(Bubble*);
-    Statement* operator()(Media_Block*);
-    Statement* operator()(Feature_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* parent();
-    vector<pair<bool, Block*>> slice_by_bubble(Statement*);
-    Statement* bubble(At_Rule*);
-    Statement* bubble(At_Root_Block*);
-    Statement* bubble(Media_Block*);
-    Statement* bubble(Feature_Block*);
-    Statement* shallow_copy(Statement*);
-    Statement* debubble(Block* children, Statement* parent = 0);
-    Statement* flatten(Statement*);
-    bool bubblable(Statement*);
-
-    List* merge_media_queries(Media_Block*, Media_Block*);
-    Media_Query* merge_media_query(Media_Query*, Media_Query*);
-
-    template <typename U>
-    Statement* fallback(U x) { return fallback_impl(x); }
-
-    void append_block(Block*);
-  };
-
-}
-
-#endif
diff --git a/libsass/debug.hpp b/libsass/debug.hpp
deleted file mode 100644
--- a/libsass/debug.hpp
+++ /dev/null
@@ -1,39 +0,0 @@
-#ifndef SASS_DEBUG_H
-#define SASS_DEBUG_H
-
-#include <stdint.h>
-
-enum dbg_lvl_t : uint32_t {
-	NONE = 0,
-	TRIM = 1,
-	CHUNKS = 2,
-	SUBWEAVE = 4,
-	WEAVE = 8,
-	EXTEND_COMPOUND = 16,
-	EXTEND_COMPLEX = 32,
-	LCS = 64,
-  EXTEND_OBJECT = 128,
-	ALL = UINT32_MAX
-};
-
-#ifdef DEBUG
-
-#ifndef DEBUG_LVL
-const uint32_t debug_lvl = UINT32_MAX;
-#else
-const uint32_t debug_lvl = (DEBUG_LVL);
-#endif // DEBUG_LVL
-
-#define DEBUG_PRINT(lvl, x) if((lvl) & debug_lvl) { std::cerr << x; }
-#define DEBUG_PRINTLN(lvl, x) if((lvl) & debug_lvl) { std::cerr << x << std::endl; }
-#define DEBUG_EXEC(lvl, x) if((lvl) & debug_lvl) { x; }
-
-#else // DEBUG
-
-#define DEBUG_PRINT(lvl, x)
-#define DEBUG_PRINTLN(lvl, x)
-#define DEBUG_EXEC(lvl, x)
-
-#endif // DEBUG
-
-#endif // SASS_DEBUG
diff --git a/libsass/debugger.hpp b/libsass/debugger.hpp
deleted file mode 100644
--- a/libsass/debugger.hpp
+++ /dev/null
@@ -1,558 +0,0 @@
-#ifndef SASS_DEBUGGER_H
-#define SASS_DEBUGGER_H
-
-#include <string>
-#include <sstream>
-#include "ast_fwd_decl.hpp"
-
-using namespace std;
-using namespace Sass;
-
-inline string str_replace(std::string str, const std::string& oldStr, const std::string& newStr)
-{
-  size_t pos = 0;
-  while((pos = str.find(oldStr, pos)) != std::string::npos)
-  {
-     str.replace(pos, oldStr.length(), newStr);
-     pos += newStr.length();
-  }
-  return str;
-}
-
-inline string prettyprint(const string& str) {
-  string clean = str_replace(str, "\n", "\\n");
-  clean = str_replace(clean, "	", "\\t");
-  clean = str_replace(clean, "\r", "\\r");
-  return clean;
-}
-
-inline string longToHex(long long t) {
-  std::stringstream is;
-  is << std::hex << t;
-  return is.str();
-}
-
-inline string pstate_source_position(AST_Node* node)
-{
-  stringstream str;
-  Position start(node->pstate());
-  Position end(start + node->pstate().offset);
-  str << (start.file == string::npos ? -1 : start.file)
-    << "@[" << start.line << ":" << start.column << "]"
-    << "-[" << end.line << ":" << end.column << "]";
-  return str.str();
-}
-
-inline void debug_ast(AST_Node* node, string ind = "", Env* env = 0)
-{
-  if (node == 0) return;
-  if (ind == "") cerr << "####################################################################\n";
-  if (dynamic_cast<Bubble*>(node)) {
-    Bubble* bubble = dynamic_cast<Bubble*>(node);
-    cerr << ind << "Bubble " << bubble;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << " " << bubble->tabs();
-    cerr << endl;
-  } else if (dynamic_cast<At_Root_Block*>(node)) {
-    At_Root_Block* root_block = dynamic_cast<At_Root_Block*>(node);
-    cerr << ind << "At_Root_Block " << root_block;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << " " << root_block->tabs();
-    cerr << endl;
-    if (root_block->block()) for(auto i : root_block->block()->elements()) { debug_ast(i, ind + " ", env); }
-  } else if (dynamic_cast<Selector_List*>(node)) {
-    Selector_List* selector = dynamic_cast<Selector_List*>(node);
-    cerr << ind << "Selector_List " << selector;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << " [block:" << selector->last_block() << "]";
-    cerr << (selector->last_block() && selector->last_block()->is_root() ? " [root]" : "");
-    cerr << " [@media:" << selector->media_block() << "]";
-    cerr << (selector->is_optional() ? " [is_optional]": " -");
-    cerr << (selector->has_line_break() ? " [line-break]": " -");
-    cerr << (selector->has_line_feed() ? " [line-feed]": " -");
-    cerr << endl;
-
-    for(auto i : selector->elements()) { debug_ast(i, ind + " ", env); }
-
-//  } else if (dynamic_cast<Expression*>(node)) {
-//    Expression* expression = dynamic_cast<Expression*>(node);
-//    cerr << ind << "Expression " << expression << " " << expression->concrete_type() << endl;
-
-  } else if (dynamic_cast<Parent_Selector*>(node)) {
-    Parent_Selector* selector = dynamic_cast<Parent_Selector*>(node);
-    cerr << ind << "Parent_Selector " << selector;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << " <" << prettyprint(selector->pstate().token.ws_before()) << ">" << endl;
-    debug_ast(selector->selector(), ind + "->", env);
-
-  } else if (dynamic_cast<Complex_Selector*>(node)) {
-    Complex_Selector* selector = dynamic_cast<Complex_Selector*>(node);
-    cerr << ind << "Complex_Selector " << selector
-      << " (" << pstate_source_position(node) << ")"
-      << " [block:" << selector->last_block() << "]"
-      << " [weight:" << longToHex(selector->specificity()) << "]"
-      << (selector->last_block() && selector->last_block()->is_root() ? " [root]" : "")
-      << " [@media:" << selector->media_block() << "]"
-      << (selector->is_optional() ? " [is_optional]": " -")
-      << (selector->has_line_break() ? " [line-break]": " -")
-      << (selector->has_line_feed() ? " [line-feed]": " -") << " -> ";
-      switch (selector->combinator()) {
-        case Complex_Selector::PARENT_OF:   cerr << "{>}"; break;
-        case Complex_Selector::PRECEDES:    cerr << "{~}"; break;
-        case Complex_Selector::ADJACENT_TO: cerr << "{+}"; break;
-        case Complex_Selector::ANCESTOR_OF: cerr << "{ }"; break;
-      }
-    cerr << " <" << prettyprint(selector->pstate().token.ws_before()) << ">" << endl;
-    debug_ast(selector->head(), ind + " ", env);
-    debug_ast(selector->tail(), ind + "-", env);
-  } else if (dynamic_cast<Compound_Selector*>(node)) {
-    Compound_Selector* selector = dynamic_cast<Compound_Selector*>(node);
-    cerr << ind << "Compound_Selector " << selector;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << " [block:" << selector->last_block() << "]";
-    cerr << " [weight:" << longToHex(selector->specificity()) << "]";
-    // cerr << (selector->last_block() && selector->last_block()->is_root() ? " [root]" : "");
-    cerr << " [@media:" << selector->media_block() << "]";
-    cerr << (selector->is_optional() ? " [is_optional]": " -");
-    cerr << (selector->has_line_break() ? " [line-break]": " -");
-    cerr << (selector->has_line_feed() ? " [line-feed]": " -");
-    cerr << " <" << prettyprint(selector->pstate().token.ws_before()) << ">" << endl;
-    for(auto i : selector->elements()) { debug_ast(i, ind + " ", env); }
-  } else if (dynamic_cast<Propset*>(node)) {
-    Propset* selector = dynamic_cast<Propset*>(node);
-    cerr << ind << "Propset " << selector;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << " " << selector->tabs() << endl;
-    if (selector->block()) for(auto i : selector->block()->elements()) { debug_ast(i, ind + " ", env); }
-  } else if (dynamic_cast<Wrapped_Selector*>(node)) {
-    Wrapped_Selector* selector = dynamic_cast<Wrapped_Selector*>(node);
-    cerr << ind << "Wrapped_Selector " << selector;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << " <<" << selector->name() << ">>" << (selector->has_line_break() ? " [line-break]": " -") << (selector->has_line_feed() ? " [line-feed]": " -") << endl;
-    debug_ast(selector->selector(), ind + " () ", env);
-  } else if (dynamic_cast<Pseudo_Selector*>(node)) {
-    Pseudo_Selector* selector = dynamic_cast<Pseudo_Selector*>(node);
-    cerr << ind << "Pseudo_Selector " << selector;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << " <<" << selector->name() << ">>" << (selector->has_line_break() ? " [line-break]": " -") << (selector->has_line_feed() ? " [line-feed]": " -") << endl;
-    debug_ast(selector->expression(), ind + " <= ", env);
-  } else if (dynamic_cast<Attribute_Selector*>(node)) {
-    Attribute_Selector* selector = dynamic_cast<Attribute_Selector*>(node);
-    cerr << ind << "Attribute_Selector " << selector;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << " <<" << selector->name() << ">>" << (selector->has_line_break() ? " [line-break]": " -") << (selector->has_line_feed() ? " [line-feed]": " -") << endl;
-    debug_ast(selector->value(), ind + "[" + selector->matcher() + "] ", env);
-  } else if (dynamic_cast<Selector_Qualifier*>(node)) {
-    Selector_Qualifier* selector = dynamic_cast<Selector_Qualifier*>(node);
-    cerr << ind << "Selector_Qualifier " << selector;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << " <<" << selector->name() << ">>" << (selector->has_line_break() ? " [line-break]": " -") << (selector->has_line_feed() ? " [line-feed]": " -") << endl;
-  } else if (dynamic_cast<Type_Selector*>(node)) {
-    Type_Selector* selector = dynamic_cast<Type_Selector*>(node);
-    cerr << ind << "Type_Selector " << selector;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << " <<" << selector->name() << ">>" << (selector->has_line_break() ? " [line-break]": " -") <<
-      " <" << prettyprint(selector->pstate().token.ws_before()) << ">" << endl;
-  } else if (dynamic_cast<Selector_Placeholder*>(node)) {
-
-    Selector_Placeholder* selector = dynamic_cast<Selector_Placeholder*>(node);
-    cerr << ind << "Selector_Placeholder [" << selector->name() << "] " << selector
-      << " [block:" << selector->last_block() << "]"
-      << " [@media:" << selector->media_block() << "]"
-      << (selector->is_optional() ? " [is_optional]": " -")
-      << (selector->has_line_break() ? " [line-break]": " -")
-      << (selector->has_line_feed() ? " [line-feed]": " -")
-    << endl;
-
-  } else if (dynamic_cast<Selector_Reference*>(node)) {
-    Selector_Reference* selector = dynamic_cast<Selector_Reference*>(node);
-    cerr << ind << "Selector_Reference " << selector;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << " @ref " << selector->selector() << endl;
-  } else if (dynamic_cast<Simple_Selector*>(node)) {
-    Simple_Selector* selector = dynamic_cast<Simple_Selector*>(node);
-    cerr << ind << "Simple_Selector " << selector;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << (selector->has_line_break() ? " [line-break]": " -") << (selector->has_line_feed() ? " [line-feed]": " -") << endl;
-
-  } else if (dynamic_cast<Selector_Schema*>(node)) {
-    Selector_Schema* selector = dynamic_cast<Selector_Schema*>(node);
-    cerr << ind << "Selector_Schema " << selector;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << " [block:" << selector->last_block() << "]"
-      << (selector->last_block() && selector->last_block()->is_root() ? " [root]" : "")
-      << " [@media:" << selector->media_block() << "]"
-      << (selector->has_line_break() ? " [line-break]": " -")
-      << (selector->has_line_feed() ? " [line-feed]": " -")
-    << endl;
-
-    debug_ast(selector->contents(), ind + " ");
-    // for(auto i : selector->elements()) { debug_ast(i, ind + " ", env); }
-
-  } else if (dynamic_cast<Selector*>(node)) {
-    Selector* selector = dynamic_cast<Selector*>(node);
-    cerr << ind << "Selector " << selector;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << (selector->has_line_break() ? " [line-break]": " -")
-      << (selector->has_line_feed() ? " [line-feed]": " -")
-    << endl;
-
-  } else if (dynamic_cast<Media_Query_Expression*>(node)) {
-    Media_Query_Expression* block = dynamic_cast<Media_Query_Expression*>(node);
-    cerr << ind << "Media_Query_Expression " << block;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << (block->is_interpolated() ? " [is_interpolated]": " -")
-    << endl;
-    debug_ast(block->feature(), ind + " feature) ");
-    debug_ast(block->value(), ind + " value) ");
-
-  } else if (dynamic_cast<Media_Query*>(node)) {
-    Media_Query* block = dynamic_cast<Media_Query*>(node);
-    cerr << ind << "Media_Query " << block;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << (block->is_negated() ? " [is_negated]": " -")
-      << (block->is_restricted() ? " [is_restricted]": " -")
-    << endl;
-    debug_ast(block->media_type(), ind + " ");
-    for(auto i : block->elements()) { debug_ast(i, ind + " ", env); }
-
-  } else if (dynamic_cast<Media_Block*>(node)) {
-    Media_Block* block = dynamic_cast<Media_Block*>(node);
-    cerr << ind << "Media_Block " << block;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << " " << block->tabs() << endl;
-    debug_ast(block->media_queries(), ind + " =@ ");
-    debug_ast(block->selector(), ind + " -@ ");
-    if (block->block()) for(auto i : block->block()->elements()) { debug_ast(i, ind + " ", env); }
-  } else if (dynamic_cast<Feature_Block*>(node)) {
-    Feature_Block* block = dynamic_cast<Feature_Block*>(node);
-    cerr << ind << "Feature_Block " << block;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << " " << block->tabs() << endl;
-    if (block->block()) for(auto i : block->block()->elements()) { debug_ast(i, ind + " ", env); }
-  } else if (dynamic_cast<Block*>(node)) {
-    Block* root_block = dynamic_cast<Block*>(node);
-    cerr << ind << "Block " << root_block;
-    cerr << " (" << pstate_source_position(node) << ")";
-    if (root_block->is_root()) cerr << " [root]";
-    cerr << " " << root_block->tabs() << endl;
-    if (root_block->block()) for(auto i : root_block->block()->elements()) { debug_ast(i, ind + " ", env); }
-  } else if (dynamic_cast<Warning*>(node)) {
-    Warning* block = dynamic_cast<Warning*>(node);
-    cerr << ind << "Warning " << block;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << " " << block->tabs() << endl;
-  } else if (dynamic_cast<Error*>(node)) {
-    Error* block = dynamic_cast<Error*>(node);
-    cerr << ind << "Error " << block;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << " " << block->tabs() << endl;
-  } else if (dynamic_cast<Debug*>(node)) {
-    Debug* block = dynamic_cast<Debug*>(node);
-    cerr << ind << "Debug " << block;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << " " << block->tabs() << endl;
-  } else if (dynamic_cast<Comment*>(node)) {
-    Comment* block = dynamic_cast<Comment*>(node);
-    cerr << ind << "Comment " << block;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << " " << block->tabs() <<
-      " <" << prettyprint(block->pstate().token.ws_before()) << ">" << endl;
-    debug_ast(block->text(), ind + "// ", env);
-  } else if (dynamic_cast<If*>(node)) {
-    If* block = dynamic_cast<If*>(node);
-    cerr << ind << "If " << block;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << " " << block->tabs() << endl;
-    debug_ast(block->predicate(), ind + " = ");
-    debug_ast(block->consequent(), ind + " <>");
-    debug_ast(block->alternative(), ind + " ><");
-  } else if (dynamic_cast<Return*>(node)) {
-    Return* block = dynamic_cast<Return*>(node);
-    cerr << ind << "Return " << block;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << " " << block->tabs() << endl;
-  } else if (dynamic_cast<Extension*>(node)) {
-    Extension* block = dynamic_cast<Extension*>(node);
-    cerr << ind << "Extension " << block;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << " " << block->tabs() << endl;
-    debug_ast(block->selector(), ind + "-> ", env);
-  } else if (dynamic_cast<Content*>(node)) {
-    Content* block = dynamic_cast<Content*>(node);
-    cerr << ind << "Content " << block;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << " " << block->tabs() << endl;
-  } else if (dynamic_cast<Import_Stub*>(node)) {
-    Import_Stub* block = dynamic_cast<Import_Stub*>(node);
-    cerr << ind << "Import_Stub " << block;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << " " << block->tabs() << endl;
-  } else if (dynamic_cast<Import*>(node)) {
-    Import* block = dynamic_cast<Import*>(node);
-    cerr << ind << "Import " << block;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << " " << block->tabs() << endl;
-    // debug_ast(block->media_queries(), ind + " @ ");
-    // vector<string>         files_;
-    for (auto imp : block->urls()) debug_ast(imp, "@ ", env);
-  } else if (dynamic_cast<Assignment*>(node)) {
-    Assignment* block = dynamic_cast<Assignment*>(node);
-    cerr << ind << "Assignment " << block;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << " <<" << block->variable() << ">> " << block->tabs() << endl;
-    debug_ast(block->value(), ind + "=", env);
-  } else if (dynamic_cast<Declaration*>(node)) {
-    Declaration* block = dynamic_cast<Declaration*>(node);
-    cerr << ind << "Declaration " << block;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << " " << block->tabs() << endl;
-    debug_ast(block->property(), ind + " prop: ", env);
-    debug_ast(block->value(), ind + " value: ", env);
-  } else if (dynamic_cast<Keyframe_Rule*>(node)) {
-    Keyframe_Rule* has_block = dynamic_cast<Keyframe_Rule*>(node);
-    cerr << ind << "Keyframe_Rule " << has_block;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << " " << has_block->tabs() << endl;
-    if (has_block->selector()) debug_ast(has_block->selector(), ind + "@");
-    if (has_block->block()) for(auto i : has_block->block()->elements()) { debug_ast(i, ind + " ", env); }
-  } else if (dynamic_cast<At_Rule*>(node)) {
-    At_Rule* block = dynamic_cast<At_Rule*>(node);
-    cerr << ind << "At_Rule " << block;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << " [" << block->keyword() << "] " << block->tabs() << endl;
-    debug_ast(block->value(), ind + "+", env);
-    debug_ast(block->selector(), ind + "~", env);
-    if (block->block()) for(auto i : block->block()->elements()) { debug_ast(i, ind + " ", env); }
-  } else if (dynamic_cast<Each*>(node)) {
-    Each* block = dynamic_cast<Each*>(node);
-    cerr << ind << "Each " << block;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << " " << block->tabs() << endl;
-    if (block->block()) for(auto i : block->block()->elements()) { debug_ast(i, ind + " ", env); }
-  } else if (dynamic_cast<For*>(node)) {
-    For* block = dynamic_cast<For*>(node);
-    cerr << ind << "For " << block;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << " " << block->tabs() << endl;
-    if (block->block()) for(auto i : block->block()->elements()) { debug_ast(i, ind + " ", env); }
-  } else if (dynamic_cast<While*>(node)) {
-    While* block = dynamic_cast<While*>(node);
-    cerr << ind << "While " << block;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << " " << block->tabs() << endl;
-    if (block->block()) for(auto i : block->block()->elements()) { debug_ast(i, ind + " ", env); }
-  } else if (dynamic_cast<Definition*>(node)) {
-    Definition* block = dynamic_cast<Definition*>(node);
-    cerr << ind << "Definition " << block;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << " [name: " << block->name() << "] ";
-    cerr << " [type: " << (block->type() == Sass::Definition::Type::MIXIN ? "Mixin " : "Function ") << "] ";
-    // this seems to lead to segfaults some times?
-    // cerr << " [signature: " << block->signature() << "] ";
-    cerr << " [native: " << block->native_function() << "] ";
-    cerr << " " << block->tabs() << endl;
-    debug_ast(block->parameters(), ind + " params: ", env);
-    if (block->block()) for(auto i : block->block()->elements()) { debug_ast(i, ind + " ", env); }
-  } else if (dynamic_cast<Mixin_Call*>(node)) {
-    Mixin_Call* block = dynamic_cast<Mixin_Call*>(node);
-    cerr << ind << "Mixin_Call " << block << " " << block->tabs();
-    cerr << " [" <<  block->name() << "]" << endl;
-    debug_ast(block->arguments(), ind + " args: ");
-    if (block->block()) for(auto i : block->block()->elements()) { debug_ast(i, ind + " ", env); }
-  } else if (dynamic_cast<Ruleset*>(node)) {
-    Ruleset* ruleset = dynamic_cast<Ruleset*>(node);
-    cerr << ind << "Ruleset " << ruleset;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << " " << ruleset->tabs() << endl;
-    debug_ast(ruleset->selector(), ind + " ");
-    if (ruleset->block()) for(auto i : ruleset->block()->elements()) { debug_ast(i, ind + " ", env); }
-  } else if (dynamic_cast<Block*>(node)) {
-    Block* block = dynamic_cast<Block*>(node);
-    cerr << ind << "Block " << block;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << " " << block->tabs() << endl;
-    for(auto i : block->elements()) { debug_ast(i, ind + " ", env); }
-  } else if (dynamic_cast<Textual*>(node)) {
-    Textual* expression = dynamic_cast<Textual*>(node);
-    cerr << ind << "Textual ";
-    if (expression->type() == Textual::NUMBER) cerr << " [NUMBER]";
-    else if (expression->type() == Textual::PERCENTAGE) cerr << " [PERCENTAGE]";
-    else if (expression->type() == Textual::DIMENSION) cerr << " [DIMENSION]";
-    else if (expression->type() == Textual::HEX) cerr << " [HEX]";
-    cerr << expression << " [" << expression->value() << "]";
-    if (expression->is_delayed()) cerr << " [delayed]";
-    cerr << endl;
-  } else if (dynamic_cast<Variable*>(node)) {
-    Variable* expression = dynamic_cast<Variable*>(node);
-    cerr << ind << "Variable " << expression;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << " [" << expression->name() << "]" << endl;
-    string name(expression->name());
-    if (env && env->has(name)) debug_ast(static_cast<Expression*>((*env)[name]), ind + " -> ", env);
-  } else if (dynamic_cast<Function_Call_Schema*>(node)) {
-    Function_Call_Schema* expression = dynamic_cast<Function_Call_Schema*>(node);
-    cerr << ind << "Function_Call_Schema " << expression;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << "" << endl;
-    debug_ast(expression->name(), ind + "name: ", env);
-    debug_ast(expression->arguments(), ind + " args: ", env);
-  } else if (dynamic_cast<Function_Call*>(node)) {
-    Function_Call* expression = dynamic_cast<Function_Call*>(node);
-    cerr << ind << "Function_Call " << expression;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << " [" << expression->name() << "]" << endl;
-    debug_ast(expression->arguments(), ind + " args: ", env);
-  } else if (dynamic_cast<Arguments*>(node)) {
-    Arguments* expression = dynamic_cast<Arguments*>(node);
-    cerr << ind << "Arguments " << expression;
-    if (expression->is_delayed()) cerr << " [delayed]";
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << endl;
-    for(auto i : expression->elements()) { debug_ast(i, ind + " ", env); }
-  } else if (dynamic_cast<Argument*>(node)) {
-    Argument* expression = dynamic_cast<Argument*>(node);
-    cerr << ind << "Argument " << expression;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << " [" << expression->value() << "]";
-    cerr << " [name: " << expression->name() << "] ";
-    cerr << " [rest: " << expression->is_rest_argument() << "] ";
-    cerr << " [keyword: " << expression->is_keyword_argument() << "] " << endl;
-    debug_ast(expression->value(), ind + " value: ", env);
-  } else if (dynamic_cast<Parameters*>(node)) {
-    Parameters* expression = dynamic_cast<Parameters*>(node);
-    cerr << ind << "Parameters " << expression;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << " [has_optional: " << expression->has_optional_parameters() << "] ";
-    cerr << " [has_rest: " << expression->has_rest_parameter() << "] ";
-    cerr << endl;
-    for(auto i : expression->elements()) { debug_ast(i, ind + " ", env); }
-  } else if (dynamic_cast<Parameter*>(node)) {
-    Parameter* expression = dynamic_cast<Parameter*>(node);
-    cerr << ind << "Parameter " << expression;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << " [name: " << expression->name() << "] ";
-    cerr << " [default: " << expression->default_value() << "] ";
-    cerr << " [rest: " << expression->is_rest_parameter() << "] " << endl;
-  } else if (dynamic_cast<Unary_Expression*>(node)) {
-    Unary_Expression* expression = dynamic_cast<Unary_Expression*>(node);
-    cerr << ind << "Unary_Expression " << expression;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << " [" << expression->type() << "]" << endl;
-    debug_ast(expression->operand(), ind + " operand: ", env);
-  } else if (dynamic_cast<Binary_Expression*>(node)) {
-    Binary_Expression* expression = dynamic_cast<Binary_Expression*>(node);
-    cerr << ind << "Binary_Expression " << expression;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << " [" << expression->type_name() << "]" << endl;
-    debug_ast(expression->left(), ind + " left:  ", env);
-    debug_ast(expression->right(), ind + " right: ", env);
-  } else if (dynamic_cast<Map*>(node)) {
-    Map* expression = dynamic_cast<Map*>(node);
-    cerr << ind << "Map " << expression;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << " [Hashed]" << endl;
-    // for (auto i : expression->elements()) {
-    //   debug_ast(i.first, ind + " key: ");
-    //   debug_ast(i.second, ind + " val: ");
-    // }
-  } else if (dynamic_cast<List*>(node)) {
-    List* expression = dynamic_cast<List*>(node);
-    cerr << ind << "List " << expression;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << " (" << expression->length() << ") " <<
-      (expression->separator() == Sass::List::Separator::COMMA ? "Comma " : "Space ") <<
-      " [delayed: " << expression->is_delayed() << "] " <<
-      " [interpolant: " << expression->is_interpolant() << "] " <<
-      " [arglist: " << expression->is_arglist() << "] " <<
-      endl;
-    for(auto i : expression->elements()) { debug_ast(i, ind + " ", env); }
-  } else if (dynamic_cast<Content*>(node)) {
-    Content* expression = dynamic_cast<Content*>(node);
-    cerr << ind << "Content " << expression;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << " [Statement]" << endl;
-  } else if (dynamic_cast<Boolean*>(node)) {
-    Boolean* expression = dynamic_cast<Boolean*>(node);
-    cerr << ind << "Boolean " << expression;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << " [" << expression->value() << "]" << endl;
-  } else if (dynamic_cast<Color*>(node)) {
-    Color* expression = dynamic_cast<Color*>(node);
-    cerr << ind << "Color " << expression;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << " [" << expression->r() << ":"  << expression->g() << ":" << expression->b() << "@" << expression->a() << "]" << endl;
-  } else if (dynamic_cast<Number*>(node)) {
-    Number* expression = dynamic_cast<Number*>(node);
-    cerr << ind << "Number " << expression;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << " [" << expression->value() << expression->unit() << "]" << endl;
-  } else if (dynamic_cast<String_Quoted*>(node)) {
-    String_Quoted* expression = dynamic_cast<String_Quoted*>(node);
-    cerr << ind << "String_Quoted " << expression;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << " [" << prettyprint(expression->value()) << "]";
-    if (expression->is_delayed()) cerr << " [delayed]";
-    if (expression->sass_fix_1291()) cerr << " [sass_fix_1291]";
-    if (expression->quote_mark()) cerr << " [quote_mark: " << expression->quote_mark() << "]";
-    cerr << " <" << prettyprint(expression->pstate().token.ws_before()) << ">" << endl;
-  } else if (dynamic_cast<String_Constant*>(node)) {
-    String_Constant* expression = dynamic_cast<String_Constant*>(node);
-    cerr << ind << "String_Constant " << expression;
-    if (expression->concrete_type()) {
-      cerr << " " << expression->concrete_type();
-    }
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << " [" << prettyprint(expression->value()) << "]";
-    if (expression->is_delayed()) cerr << " [delayed]";
-    if (expression->sass_fix_1291()) cerr << " [sass_fix_1291]";
-    cerr << " <" << prettyprint(expression->pstate().token.ws_before()) << ">" << endl;
-  } else if (dynamic_cast<String_Schema*>(node)) {
-    String_Schema* expression = dynamic_cast<String_Schema*>(node);
-    cerr << ind << "String_Schema " << expression;
-    cerr << " " << expression->concrete_type();
-    if (expression->is_delayed()) cerr << " [delayed]";
-    if (expression->has_interpolants()) cerr << " [has_interpolants]";
-    cerr << " <" << prettyprint(expression->pstate().token.ws_before()) << ">" << endl;
-    for(auto i : expression->elements()) { debug_ast(i, ind + " ", env); }
-  } else if (dynamic_cast<String*>(node)) {
-    String* expression = dynamic_cast<String*>(node);
-    cerr << ind << "String " << expression;
-    cerr << " " << expression->concrete_type();
-    cerr << " (" << pstate_source_position(node) << ")";
-    if (expression->sass_fix_1291()) cerr << " [sass_fix_1291]";
-    cerr << " <" << prettyprint(expression->pstate().token.ws_before()) << ">" << endl;
-  } else if (dynamic_cast<Expression*>(node)) {
-    Expression* expression = dynamic_cast<Expression*>(node);
-    cerr << ind << "Expression " << expression;
-    cerr << " (" << pstate_source_position(node) << ")";
-    switch (expression->concrete_type()) {
-      case Expression::Concrete_Type::NONE: cerr << " [NONE]"; break;
-      case Expression::Concrete_Type::BOOLEAN: cerr << " [BOOLEAN]"; break;
-      case Expression::Concrete_Type::NUMBER: cerr << " [NUMBER]"; break;
-      case Expression::Concrete_Type::COLOR: cerr << " [COLOR]"; break;
-      case Expression::Concrete_Type::STRING: cerr << " [STRING]"; break;
-      case Expression::Concrete_Type::LIST: cerr << " [LIST]"; break;
-      case Expression::Concrete_Type::MAP: cerr << " [MAP]"; break;
-      case Expression::Concrete_Type::SELECTOR: cerr << " [SELECTOR]"; break;
-      case Expression::Concrete_Type::NULL_VAL: cerr << " [NULL_VAL]"; break;
-      case Expression::Concrete_Type::NUM_TYPES: cerr << " [NUM_TYPES]"; break;
-    }
-    cerr << endl;
-  } else if (dynamic_cast<Has_Block*>(node)) {
-    Has_Block* has_block = dynamic_cast<Has_Block*>(node);
-    cerr << ind << "Has_Block " << has_block;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << " " << has_block->tabs() << endl;
-    if (has_block->block()) for(auto i : has_block->block()->elements()) { debug_ast(i, ind + " ", env); }
-  } else if (dynamic_cast<Statement*>(node)) {
-    Statement* statement = dynamic_cast<Statement*>(node);
-    cerr << ind << "Statement " << statement;
-    cerr << " (" << pstate_source_position(node) << ")";
-    cerr << " " << statement->tabs() << endl;
-  }
-
-  if (ind == "") cerr << "####################################################################\n";
-}
-
-#endif // SASS_DEBUGGER
diff --git a/libsass/emitter.cpp b/libsass/emitter.cpp
deleted file mode 100644
--- a/libsass/emitter.cpp
+++ /dev/null
@@ -1,258 +0,0 @@
-#include "util.hpp"
-#include "context.hpp"
-#include "output.hpp"
-#include "emitter.hpp"
-#include "utf8_string.hpp"
-
-namespace Sass {
-  using namespace std;
-
-  Emitter::Emitter(Context* ctx)
-  : wbuf(),
-    ctx(ctx),
-    indentation(0),
-    scheduled_space(0),
-    scheduled_linefeed(0),
-    scheduled_delimiter(false),
-    in_comment(false),
-    in_wrapped(false),
-    in_media_block(false),
-    in_declaration(false),
-    in_space_array(false),
-    in_comma_array(false)
-  { }
-
-  // return buffer as string
-  string Emitter::get_buffer(void)
-  {
-    return wbuf.buffer;
-  }
-
-  Output_Style Emitter::output_style(void)
-  {
-    return ctx ? ctx->output_style : COMPRESSED;
-  }
-
-  // PROXY METHODS FOR SOURCE MAPS
-
-  void Emitter::add_source_index(size_t idx)
-  { wbuf.smap.source_index.push_back(idx); }
-
-  string Emitter::generate_source_map(Context &ctx)
-  { return wbuf.smap.generate_source_map(ctx); }
-
-  void Emitter::set_filename(const string& str)
-  { wbuf.smap.file = str; }
-
-  void Emitter::add_open_mapping(AST_Node* node)
-  { wbuf.smap.add_open_mapping(node); }
-  void Emitter::add_close_mapping(AST_Node* node)
-  { wbuf.smap.add_close_mapping(node); }
-  ParserState Emitter::remap(const ParserState& pstate)
-  { return wbuf.smap.remap(pstate); }
-
-  // MAIN BUFFER MANIPULATION
-
-  // add outstanding delimiter
-  void Emitter::finalize(void)
-  {
-    scheduled_space = 0;
-    if (scheduled_linefeed)
-      scheduled_linefeed = 1;
-    flush_schedules();
-  }
-
-  // flush scheduled space/linefeed
-  void Emitter::flush_schedules(void)
-  {
-    // check the schedule
-    if (scheduled_linefeed) {
-      string linefeeds = "";
-
-      for (size_t i = 0; i < scheduled_linefeed; i++)
-        linefeeds += ctx ? ctx->linefeed : "\n";
-      scheduled_space = 0;
-      scheduled_linefeed = 0;
-      append_string(linefeeds);
-
-    } else if (scheduled_space) {
-      string spaces(scheduled_space, ' ');
-      scheduled_space = 0;
-      append_string(spaces);
-    }
-    if (scheduled_delimiter) {
-      scheduled_delimiter = false;
-      append_string(";");
-    }
-  }
-
-  // prepend some text or token to the buffer
-  void Emitter::prepend_output(const OutputBuffer& output)
-  {
-    wbuf.smap.prepend(output);
-    wbuf.buffer = output.buffer + wbuf.buffer;
-  }
-
-  // prepend some text or token to the buffer
-  void Emitter::prepend_string(const string& text)
-  {
-    wbuf.smap.prepend(Offset(text));
-    wbuf.buffer = text + wbuf.buffer;
-  }
-
-  // append some text or token to the buffer
-  void Emitter::append_string(const string& text)
-  {
-    // write space/lf
-    flush_schedules();
-
-    if (in_comment && output_style() == COMPACT) {
-      // unescape comment nodes
-      string out = comment_to_string(text);
-      // add to buffer
-      wbuf.buffer += out;
-      // account for data in source-maps
-      wbuf.smap.append(Offset(out));
-    } else {
-      // add to buffer
-      wbuf.buffer += text;
-      // account for data in source-maps
-      wbuf.smap.append(Offset(text));
-    }
-  }
-
-  // append some white-space only text
-  void Emitter::append_wspace(const string& text)
-  {
-    if (text.empty()) return;
-    if (peek_linefeed(text.c_str())) {
-      scheduled_space = 0;
-      append_mandatory_linefeed();
-    }
-  }
-
-  // append some text or token to the buffer
-  // this adds source-mappings for node start and end
-  void Emitter::append_token(const string& text, AST_Node* node)
-  {
-    flush_schedules();
-    add_open_mapping(node);
-    append_string(text);
-    add_close_mapping(node);
-  }
-
-  // HELPER METHODS
-
-  void Emitter::append_indentation()
-  {
-    if (output_style() == COMPRESSED) return;
-    if (output_style() == COMPACT) return;
-    if (scheduled_linefeed && indentation)
-      scheduled_linefeed = 1;
-    string indent = "";
-    for (size_t i = 0; i < indentation; i++)
-      indent += ctx ? ctx->indent : "  ";
-    append_string(indent);
-  }
-
-  void Emitter::append_delimiter()
-  {
-    scheduled_delimiter = true;
-    if (output_style() == COMPACT) {
-      if (indentation == 0) {
-        append_mandatory_linefeed();
-      } else {
-        append_mandatory_space();
-      }
-    } else if (output_style() != COMPRESSED) {
-      append_optional_linefeed();
-    }
-  }
-
-  void Emitter::append_comma_separator()
-  {
-    scheduled_space = 0;
-    append_string(",");
-    append_optional_space();
-  }
-
-  void Emitter::append_colon_separator()
-  {
-    scheduled_space = 0;
-    append_string(":");
-    append_optional_space();
-  }
-
-  void Emitter::append_mandatory_space()
-  {
-    scheduled_space = 1;
-  }
-
-  void Emitter::append_optional_space()
-  {
-    if (output_style() != COMPRESSED && buffer().size()) {
-      char lst = buffer().at(buffer().length() - 1);
-      if (!isspace(lst) || scheduled_delimiter) {
-        append_mandatory_space();
-      }
-    }
-  }
-
-  void Emitter::append_special_linefeed()
-  {
-    if (output_style() == COMPACT) {
-      append_mandatory_linefeed();
-      for (size_t p = 0; p < indentation; p++)
-        append_string(ctx ? ctx->indent : "  ");
-    }
-  }
-
-  void Emitter::append_optional_linefeed()
-  {
-    if (output_style() == COMPACT) {
-      append_mandatory_space();
-    } else {
-      append_mandatory_linefeed();
-    }
-  }
-
-  void Emitter::append_mandatory_linefeed()
-  {
-    if (output_style() != COMPRESSED) {
-      scheduled_linefeed = 1;
-      scheduled_space = 0;
-      // flush_schedules();
-    }
-  }
-
-  void Emitter::append_scope_opener(AST_Node* node)
-  {
-    append_optional_space();
-    flush_schedules();
-    if (node) add_open_mapping(node);
-    append_string("{");
-    append_optional_linefeed();
-    // append_optional_space();
-    ++ indentation;
-  }
-  void Emitter::append_scope_closer(AST_Node* node)
-  {
-    -- indentation;
-    scheduled_linefeed = 0;
-    if (output_style() == COMPRESSED)
-      scheduled_delimiter = false;
-    if (output_style() == EXPANDED) {
-      append_optional_linefeed();
-      append_indentation();
-    } else {
-      append_optional_space();
-    }
-    append_string("}");
-    if (node) add_close_mapping(node);
-    append_optional_linefeed();
-    if (indentation != 0) return;
-    if (output_style() != COMPRESSED)
-      scheduled_linefeed = 2;
-  }
-
-}
diff --git a/libsass/emitter.hpp b/libsass/emitter.hpp
deleted file mode 100644
--- a/libsass/emitter.hpp
+++ /dev/null
@@ -1,89 +0,0 @@
-#ifndef SASS_EMITTER_H
-#define SASS_EMITTER_H
-
-#include <string>
-#include "source_map.hpp"
-#include "ast_fwd_decl.hpp"
-
-namespace Sass {
-  class Context;
-  using namespace std;
-
-  class Emitter {
-
-    public:
-      Emitter(Context* ctx);
-      virtual ~Emitter() { };
-
-    protected:
-      OutputBuffer wbuf;
-    public:
-      const string buffer(void) { return wbuf.buffer; }
-      const SourceMap smap(void) { return wbuf.smap; }
-      const OutputBuffer output(void) { return wbuf; }
-      // proxy methods for source maps
-      void add_source_index(size_t idx);
-      void set_filename(const string& str);
-      void add_open_mapping(AST_Node* node);
-      void add_close_mapping(AST_Node* node);
-      string generate_source_map(Context &ctx);
-      ParserState remap(const ParserState& pstate);
-
-    public:
-      Context* ctx;
-      size_t indentation;
-      size_t scheduled_space;
-      size_t scheduled_linefeed;
-      bool scheduled_delimiter;
-
-    public:
-      // output strings different in comments
-      bool in_comment;
-      // selector list does not get linefeeds
-      bool in_wrapped;
-      // lists always get a space after delimiter
-      bool in_media_block;
-      // nested list must not have parentheses
-      bool in_declaration;
-      // nested lists need parentheses
-      bool in_space_array;
-      bool in_comma_array;
-
-    public:
-      // return buffer as string
-      string get_buffer(void);
-      // flush scheduled space/linefeed
-      Output_Style output_style(void);
-      // add outstanding linefeed
-      void finalize(void);
-      // flush scheduled space/linefeed
-      void flush_schedules(void);
-      // prepend some text or token to the buffer
-      void prepend_string(const string& text);
-      void prepend_output(const OutputBuffer& out);
-      // append some text or token to the buffer
-      void append_string(const string& text);
-      // append some white-space only text
-      void append_wspace(const string& text);
-      // append some text or token to the buffer
-      // this adds source-mappings for node start and end
-      void append_token(const string& text, AST_Node* node);
-
-    public: // syntax sugar
-      void append_indentation();
-      void append_optional_space(void);
-      void append_mandatory_space(void);
-      void append_special_linefeed(void);
-      void append_optional_linefeed(void);
-      void append_mandatory_linefeed(void);
-      void append_scope_opener(AST_Node* node = 0);
-      void append_scope_closer(AST_Node* node = 0);
-      void append_comma_separator(void);
-      void append_colon_separator(void);
-      void append_delimiter(void);
-
-  };
-
-}
-
-#endif
diff --git a/libsass/environment.hpp b/libsass/environment.hpp
deleted file mode 100644
--- a/libsass/environment.hpp
+++ /dev/null
@@ -1,163 +0,0 @@
-#ifndef SASS_ENVIRONMENT_H
-#define SASS_ENVIRONMENT_H
-
-#include <map>
-#include <string>
-#include <iostream>
-
-#include "ast_fwd_decl.hpp"
-#include "ast_def_macros.hpp"
-#include "memory_manager.hpp"
-
-namespace Sass {
-  using std::string;
-  using std::map;
-  using std::cerr;
-  using std::endl;
-
-  template <typename T>
-  class Environment {
-    // TODO: test with unordered_map
-    map<string, T> local_frame_;
-    ADD_PROPERTY(Environment*, parent);
-
-  public:
-    Memory_Manager<AST_Node> mem;
-    Environment() : local_frame_(map<string, T>()), parent_(0) { }
-
-    // link parent to create a stack
-    void link(Environment& env) { parent_ = &env; }
-    void link(Environment* env) { parent_ = env; }
-
-    // this is used to find the global frame
-    // which is the second last on the stack
-    bool is_lexical() const
-    {
-      return !! parent_ && parent_->parent_;
-    }
-
-    // only match the real root scope
-    // there is still a parent around
-    // not sure what it is actually use for
-    // I guess we store functions etc. there
-    bool is_root_scope() const
-    {
-      return parent_ && ! parent_->parent_;
-    }
-
-    // scope operates on the current frame
-
-    map<string, T>& local_frame() {
-      return local_frame_;
-    }
-
-    bool has_local(const string& key) const
-    { return local_frame_.count(key); }
-
-    T& get_local(const string& key)
-    { return local_frame_[key]; }
-
-    void set_local(const string& key, T val)
-    { local_frame_[key] = val; }
-
-    void del_local(const string& key)
-    { local_frame_.erase(key); }
-
-
-    // global operates on the global frame
-    // which is the second last on the stack
-
-    Environment* global_env()
-    {
-      Environment* cur = this;
-      while (cur->is_lexical()) {
-        cur = cur->parent_;
-      }
-      return cur;
-    }
-
-    bool has_global(const string& key)
-    { return global_env()->has(key); }
-
-    T& get_global(const string& key)
-    { return (*global_env())[key]; }
-
-    void set_global(const string& key, T val)
-    { global_env()->local_frame_[key] = val; }
-
-    void del_global(const string& key)
-    { global_env()->local_frame_.erase(key); }
-
-    // see if we have a lexical variable
-    // move down the stack but stop before we
-    // reach the global frame (is not included)
-    bool has_lexical(const string& key) const
-    {
-      auto cur = this;
-      while (cur->is_lexical()) {
-        if (cur->has_local(key)) return true;
-        cur = cur->parent_;
-      }
-      return false;
-    }
-
-    // see if we have a lexical we could update
-    // either update already existing lexical value
-    // or if flag is set, we create one if no lexical found
-    void set_lexical(const string& key, T val)
-    {
-      auto cur = this;
-      while (cur->is_lexical()) {
-        if (cur->has_local(key)) {
-          cur->set_local(key, val);
-          return;
-        }
-        cur = cur->parent_;
-      }
-      set_local(key, val);
-    }
-
-    // look on the full stack for key
-    // include all scopes available
-    bool has(const string& key) const
-    {
-      auto cur = this;
-      while (cur) {
-        if (cur->has_local(key)) {
-          return true;
-        }
-        cur = cur->parent_;
-      }
-      return false;
-    }
-
-    // use array access for getter and setter functions
-    T& operator[](const string& key)
-    {
-      auto cur = this;
-      while (cur) {
-        if (cur->has_local(key)) {
-          return cur->get_local(key);
-        }
-        cur = cur->parent_;
-      }
-      return get_local(key);
-    }
-
-    #ifdef DEBUG
-    void print()
-    {
-      for (typename map<string, T>::iterator i = local_frame_.begin(); i != local_frame_.end(); ++i) {
-        cerr << i->first << endl;
-      }
-      if (parent_) {
-        cerr << "---" << endl;
-        parent_->print();
-      }
-    }
-    #endif
-
-  };
-}
-
-#endif
diff --git a/libsass/error_handling.cpp b/libsass/error_handling.cpp
deleted file mode 100644
--- a/libsass/error_handling.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-#include "prelexer.hpp"
-#include "backtrace.hpp"
-#include "error_handling.hpp"
-
-namespace Sass {
-
-  Sass_Error::Sass_Error(Type type, ParserState pstate, string message)
-  : type(type), pstate(pstate), message(message)
-  { }
-
-  void warn(string msg, ParserState pstate)
-  {
-    cerr << "Warning: " << msg<< endl;
-  }
-
-  void warn(string msg, ParserState pstate, Backtrace* bt)
-  {
-    Backtrace top(bt, pstate, "");
-    msg += top.to_string();
-    warn(msg, pstate);
-  }
-
-  void error(string msg, ParserState pstate)
-  {
-    throw Sass_Error(Sass_Error::syntax, pstate, msg);
-  }
-
-  void error(string msg, ParserState pstate, Backtrace* bt)
-  {
-    Backtrace top(bt, pstate, "");
-    msg += "\n" + top.to_string();
-    error(msg, pstate);
-  }
-
-}
diff --git a/libsass/error_handling.hpp b/libsass/error_handling.hpp
deleted file mode 100644
--- a/libsass/error_handling.hpp
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifndef SASS_ERROR_HANDLING_H
-#define SASS_ERROR_HANDLING_H
-
-#include <string>
-
-#include "position.hpp"
-
-namespace Sass {
-  using namespace std;
-
-  struct Backtrace;
-
-  struct Sass_Error {
-    enum Type { read, write, syntax, evaluation };
-
-    Type type;
-    ParserState pstate;
-    string message;
-
-    Sass_Error(Type type, ParserState pstate, string message);
-
-  };
-
-  void warn(string msg, ParserState pstate);
-  void warn(string msg, ParserState pstate, Backtrace* bt);
-
-  void error(string msg, ParserState pstate);
-  void error(string msg, ParserState pstate, Backtrace* bt);
-
-}
-
-#endif
diff --git a/libsass/eval.cpp b/libsass/eval.cpp
deleted file mode 100644
--- a/libsass/eval.cpp
+++ /dev/null
@@ -1,1379 +0,0 @@
-#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 "to_c.hpp"
-#include "context.hpp"
-#include "backtrace.hpp"
-#include "prelexer.hpp"
-#include "parser.hpp"
-
-namespace Sass {
-  using namespace std;
-
-  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
-  typedef double (*bop)(double, double);
-  bop ops[Binary_Expression::NUM_OPS] = {
-    0, 0, // and, or
-    0, 0, 0, 0, 0, 0, // eq, neq, gt, gte, lt, lte
-    add, sub, mul, div, fmod
-  };
-
-  Eval::Eval(Context& ctx, Contextualize* contextualize, Listize* listize, Env* env, Backtrace* bt)
-  : ctx(ctx), contextualize(contextualize), listize(listize), env(env), backtrace(bt) { }
-  Eval::~Eval() { }
-
-  Eval* Eval::with(Env* e, Backtrace* bt) // for setting the env before eval'ing an expression
-  {
-    contextualize = contextualize->with(0, e, bt);
-    env = e;
-    backtrace = bt;
-    return this;
-  }
-
-  Eval* Eval::with(Selector* c, Env* e, Backtrace* bt, Selector* p, Selector* ex) // for setting the env before eval'ing an expression
-  {
-    contextualize = contextualize->with(c, e, bt, p, ex);
-    env = e;
-    backtrace = bt;
-    return this;
-  }
-
-  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)
-  {
-    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 runtime_error("Env not in sync");
-            }
-            return 0;
-          }
-          cur = cur->parent();
-        }
-        throw runtime_error("Env not in sync");
-      }
-      else if (env->has_global(var)) {
-        if (AST_Node* node = env->get_global(var)) {
-          Expression* e = dynamic_cast<Expression*>(node);
-          if (!e || e->concrete_type() == Expression::NULL_VAL) {
-            env->set_global(var, a->value()->perform(this));
-          }
-        }
-      }
-      else if (env->is_lexical()) {
-        env->set_local(var, a->value()->perform(this));
-      }
-      else {
-        env->set_local(var, a->value()->perform(this));
-      }
-    }
-    else {
-      env->set_lexical(var, a->value()->perform(this));
-    }
-    return 0;
-  }
-
-  Expression* Eval::operator()(If* i)
-  {
-    if (*i->predicate()->perform(this)) {
-      return i->consequent()->perform(this);
-    }
-    else {
-      Block* alt = i->alternative();
-      if (alt) return alt->perform(this);
-    }
-    return 0;
-  }
-
-  // For does not create a new env scope
-  // But iteration vars are reset afterwards
-  Expression* Eval::operator()(For* f)
-  {
-    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()) {
-      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
-    Number* it = 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)
-  {
-    vector<string> variables(e->variables());
-    Expression* expr = e->list()->perform(this);
-    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 = new (ctx.mem) List(expr->pstate(), 1, List::COMMA);
-      *list << expr;
-    }
-    else {
-      list = static_cast<List*>(expr);
-    }
-    // remember variables and then reset them
-    vector<AST_Node*> old_vars(variables.size());
-    for (size_t i = 0, L = variables.size(); i < L; ++i) {
-      old_vars[i] = env->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 = new (ctx.mem) List(map->pstate(), 2, List::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) {
-        List* variable = 0;
-        if ((*list)[i]->concrete_type() != Expression::LIST || variables.size() == 1) {
-          variable = new (ctx.mem) List((*list)[i]->pstate(), 1, List::COMMA);
-          *variable << (*list)[i];
-        }
-        else {
-          variable = static_cast<List*>((*list)[i]);
-        }
-        for (size_t j = 0, K = variables.size(); j < K; ++j) {
-          if (j < variable->length()) {
-            env->set_local(variables[j], (*variable)[j]);
-          }
-          else {
-            env->set_local(variables[j], new (ctx.mem) Null(expr->pstate()));
-          }
-          val = body->perform(this);
-          if (val) break;
-        }
-        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);
-
-    // 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));
-      Sass_Value* c_val = c_func(c_args, c_function, ctx.c_options);
-      sass_delete_value(c_args);
-      sass_delete_value(c_val);
-      return 0;
-
-    }
-
-    string result(unquote(message->perform(&to_string)));
-    Backtrace top(backtrace, w->pstate(), "");
-    cerr << "WARNING: " << result;
-    cerr << top.to_string(true);
-    cerr << endl << endl;
-    return 0;
-  }
-
-  Expression* Eval::operator()(Error* e)
-  {
-    Expression* message = e->message()->perform(this);
-    To_String to_string(&ctx);
-
-    // 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));
-      Sass_Value* c_val = c_func(c_args, c_function, ctx.c_options);
-      sass_delete_value(c_args);
-      sass_delete_value(c_val);
-      return 0;
-
-    }
-
-    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);
-
-    // 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));
-      Sass_Value* c_val = c_func(c_args, c_function, ctx.c_options);
-      sass_delete_value(c_args);
-      sass_delete_value(c_val);
-      return 0;
-
-    }
-
-    string cwd(ctx.get_cwd());
-    string result(unquote(message->perform(&to_string)));
-    string rel_path(Sass::File::resolve_relative_path(d->pstate().path, cwd, cwd));
-    cerr << rel_path << ":" << d->pstate().line << ":" << " DEBUG: " << result;
-    cerr << endl;
-    return 0;
-  }
-
-  Expression* Eval::operator()(List* l)
-  {
-    if (l->is_expanded()) return l;
-    List* ll = 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;
-    Map* mm = new (ctx.mem) Map(m->pstate(),
-                                  m->length());
-    for (auto key : m->keys()) {
-      *mm << std::make_pair(key->perform(this), m->at(key)->perform(this));
-    }
-
-    // check for duplicate keys
-    if (mm->has_duplicate_key()) {
-      To_String to_string(&ctx);
-      error("Duplicate key \"" + mm->get_duplicate_key()->perform(&to_string) + "\" in map " + m->perform(&to_string) + ".", m->pstate());
-    }
-
-    mm->is_expanded(true);
-    return mm;
-  }
-
-  // -- only need to define two comparisons, and the rest can be implemented in terms of them
-  bool eq(Expression*, Expression*, Context&, Eval*);
-  bool lt(Expression*, Expression*, Context&);
-  // -- arithmetic on the combinations that matter
-  Expression* op_numbers(Context&, Binary_Expression*, Expression*, Expression*);
-  Expression* op_number_color(Context&, Binary_Expression::Type, Expression*, Expression*);
-  Expression* op_color_number(Context&, Binary_Expression::Type, Expression*, Expression*);
-  Expression* op_colors(Context&, Binary_Expression::Type, Expression*, Expression*);
-  Expression* op_strings(Context&, Binary_Expression::Type, Expression*, Expression*);
-
-  Expression* Eval::operator()(Binary_Expression* b)
-  {
-    Binary_Expression::Type op_type = b->type();
-    // don't eval delayed expressions (the '/' when used as a separator)
-    if (op_type == Binary_Expression::DIV && b->is_delayed()) return b;
-    // 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)) lhs = lhs->perform(this);
-
-    switch (op_type) {
-      case Binary_Expression::AND:
-        return *lhs ? b->right()->perform(this) : lhs;
-        break;
-
-      case Binary_Expression::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 == Binary_Expression::EQ ||
-        op_type == Binary_Expression::NEQ ||
-        op_type == Binary_Expression::GT ||
-        op_type == Binary_Expression::GTE ||
-        op_type == Binary_Expression::LT ||
-        op_type == Binary_Expression::LTE)
-    {
-      rhs->is_expanded(false);
-      rhs->set_delayed(false);
-      rhs = rhs->perform(this);
-    }
-    else
-    {
-      rhs->is_delayed(false);
-      rhs = rhs->perform(this);
-    }
-
-    // see if it's a relational expression
-    switch(op_type) {
-      case Binary_Expression::EQ:  return new (ctx.mem) Boolean(b->pstate(), eq(lhs, rhs, ctx));
-      case Binary_Expression::NEQ: return new (ctx.mem) Boolean(b->pstate(), !eq(lhs, rhs, ctx));
-      case Binary_Expression::GT:  return new (ctx.mem) Boolean(b->pstate(), !lt(lhs, rhs, ctx) && !eq(lhs, rhs, ctx));
-      case Binary_Expression::GTE: return new (ctx.mem) Boolean(b->pstate(), !lt(lhs, rhs, ctx));
-      case Binary_Expression::LT:  return new (ctx.mem) Boolean(b->pstate(), lt(lhs, rhs, ctx));
-      case Binary_Expression::LTE: return new (ctx.mem) Boolean(b->pstate(), lt(lhs, rhs, ctx) || eq(lhs, rhs, ctx));
-
-      default:                     break;
-    }
-
-    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 op_numbers(ctx, b, lhs, rhs);
-    }
-    if (l_type == Expression::NUMBER && r_type == Expression::COLOR) {
-      return op_number_color(ctx, op_type, lhs, rhs);
-    }
-    if (l_type == Expression::COLOR && r_type == Expression::NUMBER) {
-      return op_color_number(ctx, op_type, lhs, rhs);
-    }
-    if (l_type == Expression::COLOR && r_type == Expression::COLOR) {
-      return op_colors(ctx, op_type, lhs, rhs);
-    }
-
-    Expression* ex = op_strings(ctx, op_type, lhs, rhs);
-    if (String_Constant* str = (String_Constant*) ex)
-    {
-      if (str->concrete_type() != Expression::STRING) return ex;
-      String_Constant* lstr = dynamic_cast<String_Constant*>(lhs);
-      String_Constant* rstr = dynamic_cast<String_Constant*>(rhs);
-      if (String_Constant* org = lstr ? lstr : rstr)
-      { str->quote_mark(org->quote_mark()); }
-    }
-    return ex;
-
-  }
-
-  Expression* Eval::operator()(Unary_Expression* u)
-  {
-    Expression* operand = u->operand()->perform(this);
-    if (u->type() == Unary_Expression::NOT) {
-      Boolean* result = new (ctx.mem) Boolean(u->pstate(), (bool)*operand);
-      result->value(!result->value());
-      return result;
-    }
-    else if (operand->concrete_type() == Expression::NUMBER) {
-      Number* result = 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(new (ctx.mem) String_Constant(u->pstate(), ""));
-      }
-      else u->operand(operand);
-      String_Constant* result = new (ctx.mem) String_Constant(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) {
-        ostringstream stm;
-        stm << "Stack depth exceeded max of " << Constants::MaxCallStack;
-        error(stm.str(), c->pstate(), backtrace);
-    }
-    string name(Util::normalize_underscores(c->name()));
-    string full_name(name + "[f]");
-    Arguments* args = c->arguments();
-    if (full_name != "if[f]") {
-      args = static_cast<Arguments*>(args->perform(this));
-    }
-
-    // try to use generic function
-    if (!env->has(full_name)) {
-      if (env->has("*[f]")) {
-        full_name = "*[f]";
-      }
-    }
-
-    // if it doesn't exist, just pass it through as a literal
-    if (!env->has(full_name)) {
-      Function_Call* lit = new (ctx.mem) Function_Call(c->pstate(),
-                                                       c->name(),
-                                                       args);
-      To_String to_string(&ctx);
-      return new (ctx.mem) String_Constant(c->pstate(),
-                                           lit->perform(&to_string));
-    }
-
-    Expression*     result = c;
-    Definition*     def    = static_cast<Definition*>((*env)[full_name]);
-    Block*          body   = def->block();
-    Native_Function func   = def->native_function();
-    Sass_Function_Entry c_function = def->c_function();
-
-    if (full_name != "if[f]") {
-      for (size_t i = 0, L = args->length(); i < L; ++i) {
-        (*args)[i]->value((*args)[i]->value()->perform(this));
-      }
-    }
-
-    Parameters* params = def->parameters();
-    Env new_env;
-    new_env.link(def->environment());
-    // bind("function " + c->name(), params, args, ctx, &new_env, this);
-    // Env* old_env = env;
-    // env = &new_env;
-
-    // Backtrace here(backtrace, c->path(), c->line(), ", in function `" + c->name() + "`");
-    // backtrace = &here;
-
-    // if it's user-defined, eval the body
-    if (body) {
-
-      bind("function " + c->name(), params, args, ctx, &new_env, this);
-      Env* old_env = env;
-      env = &new_env;
-
-      Backtrace here(backtrace, c->pstate(), ", in function `" + c->name() + "`");
-      backtrace = &here;
-
-      result = body->perform(this);
-      if (!result) {
-        error(string("function ") + c->name() + " did not return a value", c->pstate());
-      }
-      backtrace = here.parent;
-      env = old_env;
-    }
-    // if it's native, invoke the underlying CPP function
-    else if (func) {
-
-      bind("function " + c->name(), params, args, ctx, &new_env, this);
-      Env* old_env = env;
-      env = &new_env;
-
-      Backtrace here(backtrace, c->pstate(), ", in function `" + c->name() + "`");
-      backtrace = &here;
-
-      result = func(*env, *old_env, ctx, def->signature(), c->pstate(), backtrace);
-
-      backtrace = here.parent;
-      env = old_env;
-    }
-    // else if it's a user-defined c function
-    else if (c_function) {
-
-      Sass_Function_Fn c_func = sass_function_get_function(c_function);
-      if (full_name == "*[f]") {
-        String_Constant *str = new (ctx.mem) String_Constant(c->pstate(), c->name());
-        Arguments* new_args = new (ctx.mem) Arguments(c->pstate());
-        *new_args << new (ctx.mem) Argument(c->pstate(), str);
-        *new_args += args;
-        args = new_args;
-      }
-
-      // populates env with default values for params
-      bind("function " + c->name(), params, args, ctx, &new_env, this);
-      Env* old_env = env;
-      env = &new_env;
-
-      Backtrace here(backtrace, c->pstate(), ", in function `" + c->name() + "`");
-      backtrace = &here;
-
-      To_C to_c;
-      union Sass_Value* c_args = sass_make_list(env->local_frame().size(), SASS_COMMA);
-      for(size_t i = 0; i < params[0].length(); i++) {
-        string key = params[0][i]->name();
-        AST_Node* node = env->local_frame().at(key);
-        Expression* arg = static_cast<Expression*>(node);
-        sass_list_set_value(c_args, i, arg->perform(&to_c));
-      }
-      Sass_Value* c_val = c_func(c_args, c_function, ctx.c_options);
-      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, ctx, backtrace, c->pstate());
-
-      backtrace = here.parent;
-      sass_delete_value(c_args);
-      if (c_val != c_args)
-        sass_delete_value(c_val);
-      env = old_env;
-    }
-    // else it's an overloaded native function; resolve it
-    else if (def->is_overload_stub()) {
-      size_t arity = args->length();
-      stringstream ss;
-      ss << full_name << arity;
-      string resolved_name(ss.str());
-      if (!env->has(resolved_name)) error("overloaded function `" + string(c->name()) + "` given wrong number of arguments", c->pstate());
-      Definition* resolved_def = static_cast<Definition*>((*env)[resolved_name]);
-      params = resolved_def->parameters();
-      Env newer_env;
-      newer_env.link(resolved_def->environment());
-      bind("function " + c->name(), params, args, ctx, &newer_env, this);
-      Env* old_env = env;
-      env = &newer_env;
-
-      Backtrace here(backtrace, c->pstate(), ", in function `" + c->name() + "`");
-      backtrace = &here;
-
-      result = resolved_def->native_function()(*env, *old_env, ctx, resolved_def->signature(), c->pstate(), backtrace);
-
-      backtrace = here.parent;
-      env = old_env;
-    }
-
-    // backtrace = here.parent;
-    // env = old_env;
-
-
-    // link back to function definition
-    // only do this for custom functions
-    if (result->pstate().file == string::npos)
-      result->pstate(c->pstate());
-
-    do {
-      result->is_delayed(result->concrete_type() == Expression::STRING);
-      result = result->perform(this);
-    } while (result->concrete_type() == Expression::NONE);
-    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 = 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);
-    string name(v->name());
-    Expression* value = 0;
-    if (env->has(name)) value = static_cast<Expression*>((*env)[name]);
-    else error("Undefined variable: \"" + v->name() + "\".", v->pstate());
-    // cerr << "name: " << v->name() << "; type: " << typeid(*value).name() << "; value: " << value->perform(&to_string) << 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 = 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 = new (ctx.mem) String_Quoted(*str);
-      } else if (auto str = dynamic_cast<String_Constant*>(value)) {
-        if (str->quote_mark()) {
-          value = new (ctx.mem) String_Quoted(str->pstate(), str->perform(&to_string));
-        } else {
-          value = new (ctx.mem) String_Constant(str->pstate(), unquote(str->value()));
-        }
-      }
-    }
-    else if (value->concrete_type() == Expression::LIST) {
-      value = new (ctx.mem) List(*static_cast<List*>(value));
-    }
-    else if (value->concrete_type() == Expression::MAP) {
-      value = new (ctx.mem) Map(*static_cast<Map*>(value));
-    }
-    else if (value->concrete_type() == Expression::BOOLEAN) {
-      value = new (ctx.mem) Boolean(*static_cast<Boolean*>(value));
-    }
-    else if (value->concrete_type() == Expression::COLOR) {
-      value = new (ctx.mem) Color(*static_cast<Color*>(value));
-    }
-    else if (value->concrete_type() == Expression::NULL_VAL) {
-      value = new (ctx.mem) Null(value->pstate());
-    }
-
-    // cerr << "\ttype is now: " << typeid(*value).name() << endl << 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 string& text = t->value();
-    size_t num_pos = text.find_first_not_of(" \n\r\t");
-    if (num_pos == string::npos) num_pos = text.length();
-    size_t unit_pos = text.find_first_not_of("-+0123456789.", num_pos);
-    if (unit_pos == string::npos) unit_pos = text.length();
-    const string& num = text.substr(num_pos, unit_pos - num_pos);
-
-    switch (t->type())
-    {
-      case Textual::NUMBER:
-        result = new (ctx.mem) Number(t->pstate(),
-                                      sass_atof(num.c_str()),
-                                      "",
-                                      zero);
-        break;
-      case Textual::PERCENTAGE:
-        result = new (ctx.mem) Number(t->pstate(),
-                                      sass_atof(num.c_str()),
-                                      "%",
-                                      zero);
-        break;
-      case Textual::DIMENSION:
-        result = new (ctx.mem) Number(t->pstate(),
-                                      sass_atof(num.c_str()),
-                                      Token(number(text.c_str())),
-                                      zero);
-        break;
-      case Textual::HEX: {
-        string hext(t->value().substr(1)); // chop off the '#'
-        if (hext.length() == 6) {
-          string r(hext.substr(0,2));
-          string g(hext.substr(2,2));
-          string b(hext.substr(4,2));
-          result = 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 = new (ctx.mem) Color(t->pstate(),
-                                       static_cast<double>(strtol(string(2,hext[0]).c_str(), NULL, 16)),
-                                       static_cast<double>(strtol(string(2,hext[1]).c_str(), NULL, 16)),
-                                       static_cast<double>(strtol(string(2,hext[2]).c_str(), NULL, 16)),
-                                       1, false,
-                                       t->value());
-        }
-      } break;
-    }
-    return result;
-  }
-
-  Expression* Eval::operator()(Number* n)
-  {
-    n->normalize();
-    // behave according to as ruby sass (add leading zero)
-    return new (ctx.mem) Number(n->pstate(),
-                                n->value(),
-                                n->unit(),
-                                true);
-  }
-
-  Expression* Eval::operator()(Boolean* b)
-  {
-    return b;
-  }
-
-  char is_quoted(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;
-    }
-  }
-
-  string Eval::interpolation(Expression* s) {
-    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 interpolation(new (ctx.mem) String_Constant(*str_quoted));
-        } else {
-          return string_escape(quote(str_quoted->value(), str_quoted->quote_mark()));
-        }
-      } else {
-        return evacuate_escapes(str_quoted->value());
-      }
-    } else if (String_Constant* str_constant = dynamic_cast<String_Constant*>(s)) {
-      string str = str_constant->value();
-      if (!str_constant->quote_mark()) str = unquote(str);
-      return evacuate_escapes(str);
-    } else if (String_Schema* str_schema = dynamic_cast<String_Schema*>(s)) {
-      string res = "";
-      for(auto i : str_schema->elements())
-        res += (interpolation(i));
-      //ToDo: do this in one step
-      auto esc = evacuate_escapes(res);
-      auto unq = unquote(esc);
-      if (unq == esc) {
-        return string_to_output(res);
-      } else {
-        return evacuate_quotes(unq);
-      }
-    } else if (List* list = dynamic_cast<List*>(s)) {
-      string acc = ""; // ToDo: different output styles
-      string sep = list->separator() == List::Separator::COMMA ? "," : " ";
-      if (ctx.output_style != COMPRESSED && sep == ",") sep += " ";
-      bool initial = false;
-      for(auto item : list->elements()) {
-        if (initial) acc += sep;
-        acc += interpolation(item);
-        initial = true;
-      }
-      return evacuate_quotes(acc);
-    } else if (Variable* var = dynamic_cast<Variable*>(s)) {
-      string name(var->name());
-      if (!env->has(name)) error("Undefined variable: \"" + var->name() + "\".", var->pstate());
-      Expression* value = static_cast<Expression*>((*env)[name]);
-      return evacuate_quotes(interpolation(value));
-    } else if (Binary_Expression* var = dynamic_cast<Binary_Expression*>(s)) {
-      var->is_delayed(false);
-      Expression* ex = var->perform(this);
-      return evacuate_quotes(interpolation(ex));
-    } else if (Function_Call* var = dynamic_cast<Function_Call*>(s)) {
-      Expression* ex = var->perform(this);
-      return evacuate_quotes(interpolation(ex));
-    } else if (Parent_Selector* var = dynamic_cast<Parent_Selector*>(s)) {
-      Expression* ex = var->perform(this);
-      return evacuate_quotes(interpolation(ex));
-    } else if (Unary_Expression* var = dynamic_cast<Unary_Expression*>(s)) {
-      Expression* ex = var->perform(this);
-      return evacuate_quotes(interpolation(ex));
-    } else if (Selector* var = dynamic_cast<Selector*>(s)) {
-      Expression* ex = var->perform(this);
-      return evacuate_quotes(interpolation(ex));
-    } else {
-      To_String to_string(&ctx);
-      // to_string.in_decl_list = true;
-      return evacuate_quotes(s->perform(&to_string));
-    }
-  }
-
-  Expression* Eval::operator()(String_Schema* s)
-  {
-    string acc;
-    for (size_t i = 0, L = s->length(); i < L; ++i) {
-      // if (String_Quoted* str_quoted = dynamic_cast<String_Quoted*>((*s)[i])) {
-        // if (!str_quoted->is_delayed()) str_quoted->value(string_eval_escapes(str_quoted->value()));
-      // }
-      acc += interpolation((*s)[i]);
-    }
-    String_Quoted* str = new (ctx.mem) String_Quoted(s->pstate(), acc);
-    if (!str->quote_mark()) {
-      str->value(string_unescape(str->value()));
-    } else if (str->quote_mark()) {
-      str->quote_mark('*');
-    }
-    return str;
-  }
-
-  Expression* Eval::operator()(String_Constant* s)
-  {
-    if (!s->quote_mark() && !s->is_delayed() && ctx.names_to_colors.count(s->value())) {
-      Color* c = new (ctx.mem) Color(*ctx.names_to_colors[s->value()]);
-      c->pstate(s->pstate());
-      c->disp(s->value());
-      return c;
-    }
-    return s;
-  }
-
-  Expression* Eval::operator()(Feature_Query* q)
-  {
-    Feature_Query* qq = new (ctx.mem) Feature_Query(q->pstate(),
-                                                    q->length());
-    for (size_t i = 0, L = q->length(); i < L; ++i) {
-      *qq << static_cast<Feature_Query_Condition*>((*q)[i]->perform(this));
-    }
-    return qq;
-  }
-
-  Expression* Eval::operator()(Feature_Query_Condition* c)
-  {
-    String* feature = c->feature();
-    Expression* value = c->value();
-    value = (value ? value->perform(this) : 0);
-    Feature_Query_Condition* cc = new (ctx.mem) Feature_Query_Condition(c->pstate(),
-                                                 c->length(),
-                                                 feature,
-                                                 value,
-                                                 c->operand(),
-                                                 c->is_root());
-    for (size_t i = 0, L = c->length(); i < L; ++i) {
-      *cc << static_cast<Feature_Query_Condition*>((*c)[i]->perform(this));
-    }
-    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 = 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 = 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 = new (ctx.mem) String_Constant(feature->pstate(),
-                                              dynamic_cast<String_Quoted*>(feature)->value());
-    }
-    Expression* value = e->value();
-    value = (value ? value->perform(this) : 0);
-    if (value && dynamic_cast<String_Quoted*>(value)) {
-      value = new (ctx.mem) String_Constant(value->pstate(),
-                                            dynamic_cast<String_Quoted*>(value)->value());
-    }
-    return new (ctx.mem) Media_Query_Expression(e->pstate(),
-                                                feature,
-                                                value,
-                                                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 = new (ctx.mem) List(val->pstate(),
-                                           0,
-                                           List::COMMA,
-                                           true);
-        *wrapper << val;
-        val = wrapper;
-      }
-    }
-    return new (ctx.mem) Argument(a->pstate(),
-                                  val,
-                                  a->name(),
-                                  is_rest_argument,
-                                  is_keyword_argument);
-  }
-
-  Expression* Eval::operator()(Arguments* a)
-  {
-    Arguments* aa = 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;
-  }
-
-  Expression* Eval::operator()(Parent_Selector* p)
-  {
-    // no idea why both calls are needed
-    Selector* s = p->perform(contextualize);
-    if (!s) s = p->selector()->perform(contextualize);
-    // access to parent selector may return 0
-    Selector_List* l = static_cast<Selector_List*>(s);
-    // some spec tests cause this (might be a valid case!)
-    // if (!s) { cerr << "Parent Selector eval error" << endl; }
-    if (!s) { l = new (ctx.mem) Selector_List(p->pstate()); }
-    return l->perform(listize);
-  }
-
-  inline Expression* Eval::fallback_impl(AST_Node* n)
-  {
-    return static_cast<Expression*>(n);
-  }
-
-  // All the binary helpers.
-
-  bool eq(Expression* lhs, Expression* rhs, Context& ctx)
-  {
-    Expression::Concrete_Type ltype = lhs->concrete_type();
-    Expression::Concrete_Type rtype = rhs->concrete_type();
-    if (ltype != rtype) return false;
-    switch (ltype) {
-
-      case Expression::BOOLEAN: {
-        return static_cast<Boolean*>(lhs)->value() ==
-               static_cast<Boolean*>(rhs)->value();
-      } break;
-
-      case Expression::NUMBER: {
-        return *static_cast<Number*>(lhs) ==
-               *static_cast<Number*>(rhs);
-      } break;
-
-      case Expression::COLOR: {
-        Color* l = static_cast<Color*>(lhs);
-        Color* r = static_cast<Color*>(rhs);
-        return l->r() == r->r() &&
-               l->g() == r->g() &&
-               l->b() == r->b() &&
-               l->a() == r->a();
-      } break;
-
-      case Expression::STRING: {
-        string slhs = static_cast<String_Quoted*>(lhs)->value();
-        string srhs = static_cast<String_Quoted*>(rhs)->value();
-        return unquote(slhs) == unquote(srhs) &&
-               (!(is_quoted(slhs) || is_quoted(srhs)) || slhs[0] == srhs[0]);
-      } break;
-
-      case Expression::LIST: {
-        List* l = static_cast<List*>(lhs);
-        List* r = static_cast<List*>(rhs);
-        if (l->length() != r->length()) return false;
-        if (l->separator() != r->separator()) return false;
-        for (size_t i = 0, L = l->length(); i < L; ++i) {
-          if (!eq((*l)[i], (*r)[i], ctx)) return false;
-        }
-        return true;
-      } break;
-
-      case Expression::MAP: {
-        Map* l = static_cast<Map*>(lhs);
-        Map* r = static_cast<Map*>(rhs);
-        if (l->length() != r->length()) return false;
-        for (auto key : l->keys())
-          if (!eq(l->at(key), r->at(key), ctx)) return false;
-        return true;
-      } break;
-      case Expression::NULL_VAL: {
-        return true;
-      } break;
-
-      default: break;
-    }
-    return false;
-  }
-
-  bool lt(Expression* lhs, Expression* rhs, Context& ctx)
-  {
-    if (lhs->concrete_type() != Expression::NUMBER ||
-        rhs->concrete_type() != Expression::NUMBER)
-      error("may only compare numbers", lhs->pstate());
-    Number* l = static_cast<Number*>(lhs);
-    Number* r = static_cast<Number*>(rhs);
-    Number tmp_r(*r);
-    tmp_r.normalize(l->find_convertible_unit());
-    string l_unit(l->unit());
-    string r_unit(tmp_r.unit());
-    if (!l_unit.empty() && !r_unit.empty() && l->unit() != tmp_r.unit()) {
-      error("cannot compare numbers with incompatible units", l->pstate());
-    }
-    return l->value() < tmp_r.value();
-  }
-
-  Expression* op_numbers(Context& ctx, Binary_Expression* b, Expression* lhs, Expression* rhs)
-  {
-    Number* l = static_cast<Number*>(lhs);
-    Number* r = static_cast<Number*>(rhs);
-    double lv = l->value();
-    double rv = r->value();
-    Binary_Expression::Type op = b->type();
-    if (op == Binary_Expression::DIV && !rv) {
-      return new (ctx.mem) String_Constant(l->pstate(), "Infinity");
-    }
-    if (op == Binary_Expression::MOD && !rv) {
-      error("division by zero", r->pstate());
-    }
-
-    Number tmp(*r);
-    tmp.normalize(l->find_convertible_unit());
-    string l_unit(l->unit());
-    string r_unit(tmp.unit());
-    if (l_unit != r_unit && !l_unit.empty() && !r_unit.empty() &&
-        (op == Binary_Expression::ADD || op == Binary_Expression::SUB)) {
-      error("Incompatible units: '"+r_unit+"' and '"+l_unit+"'.", l->pstate());
-    }
-    Number* v = new (ctx.mem) Number(*l);
-    v->pstate(b->pstate());
-    if (l_unit.empty() && (op == Binary_Expression::ADD || op == Binary_Expression::SUB || op == Binary_Expression::MOD)) {
-      v->numerator_units() = r->numerator_units();
-      v->denominator_units() = r->denominator_units();
-    }
-
-    if (op == Binary_Expression::MUL) {
-      v->value(ops[op](lv, rv));
-      for (size_t i = 0, S = r->numerator_units().size(); i < S; ++i) {
-        v->numerator_units().push_back(r->numerator_units()[i]);
-      }
-      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 == Binary_Expression::DIV) {
-      v->value(ops[op](lv, rv));
-      for (size_t i = 0, S = r->numerator_units().size(); i < S; ++i) {
-        v->denominator_units().push_back(r->numerator_units()[i]);
-      }
-      for (size_t i = 0, S = r->denominator_units().size(); i < S; ++i) {
-        v->numerator_units().push_back(r->denominator_units()[i]);
-      }
-    } else {
-      v->value(ops[op](lv, tmp.value()));
-    }
-    v->normalize();
-    return v;
-  }
-
-  Expression* op_number_color(Context& ctx, Binary_Expression::Type op, Expression* lhs, Expression* rhs)
-  {
-    Number* l = static_cast<Number*>(lhs);
-    Color* r = static_cast<Color*>(rhs);
-    // TODO: currently SASS converts colors to standard form when adding to strings;
-    // when https://github.com/nex3/sass/issues/363 is added this can be removed to
-    // preserve the original value
-    r->disp("");
-    double lv = l->value();
-    switch (op) {
-      case Binary_Expression::ADD:
-      case Binary_Expression::MUL: {
-        return new (ctx.mem) Color(l->pstate(),
-                                   ops[op](lv, r->r()),
-                                   ops[op](lv, r->g()),
-                                   ops[op](lv, r->b()),
-                                   r->a());
-      } break;
-      case Binary_Expression::SUB:
-      case Binary_Expression::DIV: {
-        string sep(op == Binary_Expression::SUB ? "-" : "/");
-        To_String to_string(&ctx);
-        string color(r->sixtuplet() && (ctx.output_style != COMPRESSED) ?
-                     r->perform(&to_string) :
-                     Util::normalize_sixtuplet(r->perform(&to_string)));
-        return new (ctx.mem) String_Constant(l->pstate(),
-                                             l->perform(&to_string)
-                                             + sep
-                                             + color);
-      } break;
-      case Binary_Expression::MOD: {
-        error("cannot divide a number by a color", r->pstate());
-      } break;
-      default: break; // caller should ensure that we don't get here
-    }
-    // unreachable
-    return l;
-  }
-
-  Expression* op_color_number(Context& ctx, Binary_Expression::Type op, Expression* lhs, Expression* rhs)
-  {
-    Color* l = static_cast<Color*>(lhs);
-    Number* r = static_cast<Number*>(rhs);
-    double rv = r->value();
-    if (op == Binary_Expression::DIV && !rv) error("division by zero", r->pstate());
-    return new (ctx.mem) Color(l->pstate(),
-                               ops[op](l->r(), rv),
-                               ops[op](l->g(), rv),
-                               ops[op](l->b(), rv),
-                               l->a());
-  }
-
-  Expression* op_colors(Context& ctx, Binary_Expression::Type op, Expression* lhs, Expression* rhs)
-  {
-    Color* l = static_cast<Color*>(lhs);
-    Color* r = static_cast<Color*>(rhs);
-    if (l->a() != r->a()) {
-      error("alpha channels must be equal when combining colors", r->pstate());
-    }
-    if ((op == Binary_Expression::DIV || op == Binary_Expression::MOD) &&
-        (!r->r() || !r->g() ||!r->b())) {
-      error("division by zero", r->pstate());
-    }
-    return new (ctx.mem) Color(l->pstate(),
-                               ops[op](l->r(), r->r()),
-                               ops[op](l->g(), r->g()),
-                               ops[op](l->b(), r->b()),
-                               l->a());
-  }
-
-  Expression* op_strings(Context& ctx, Binary_Expression::Type op, Expression* lhs, Expression*rhs)
-  {
-    To_String to_string(&ctx);
-    Expression::Concrete_Type ltype = lhs->concrete_type();
-    Expression::Concrete_Type rtype = rhs->concrete_type();
-
-    string lstr(lhs->perform(&to_string));
-    string rstr(rhs->perform(&to_string));
-
-    bool l_str_quoted = ((Sass::String*)lhs) && ((Sass::String*)lhs)->sass_fix_1291();
-    bool r_str_quoted = ((Sass::String*)rhs) && ((Sass::String*)rhs)->sass_fix_1291();
-    bool l_str_color = ltype == Expression::STRING && ctx.names_to_colors.count(lstr) && !l_str_quoted;
-    bool r_str_color = rtype == Expression::STRING && ctx.names_to_colors.count(rstr) && !r_str_quoted;
-
-    if (l_str_color && r_str_color) {
-      return op_colors(ctx, op, ctx.names_to_colors[lstr], ctx.names_to_colors[rstr]);
-    }
-    else if (l_str_color && rtype == Expression::COLOR) {
-      return op_colors(ctx, op, ctx.names_to_colors[lstr], rhs);
-    }
-    else if (l_str_color && rtype == Expression::NUMBER) {
-      return op_color_number(ctx, op, ctx.names_to_colors[lstr], rhs);
-    }
-    else if (ltype == Expression::COLOR && r_str_color) {
-      return op_number_color(ctx, op, lhs, ctx.names_to_colors[rstr]);
-    }
-    else if (ltype == Expression::NUMBER && r_str_color) {
-      return op_number_color(ctx, op, lhs, ctx.names_to_colors[rstr]);
-    }
-    if (op == Binary_Expression::MUL) error("invalid operands for multiplication", lhs->pstate());
-    if (op == Binary_Expression::MOD) error("invalid operands for modulo", lhs->pstate());
-    string sep;
-    switch (op) {
-      case Binary_Expression::SUB: sep = "-"; break;
-      case Binary_Expression::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\".", lhs->pstate());
-    string result((lstr) + sep + (rstr));
-    String_Quoted* str = new (ctx.mem) String_Quoted(lhs->pstate(), result);
-    str->quote_mark(0);
-    return str;
-  }
-
-  Expression* cval_to_astnode(Sass_Value* v, Context& ctx, Backtrace* backtrace, ParserState pstate)
-  {
-    using std::strlen;
-    using std::strcpy;
-    Expression* e = 0;
-    switch (sass_value_get_tag(v)) {
-      case SASS_BOOLEAN: {
-        e = new (ctx.mem) Boolean(pstate, !!sass_boolean_get_value(v));
-      } break;
-      case SASS_NUMBER: {
-        e = new (ctx.mem) Number(pstate, sass_number_get_value(v), sass_number_get_unit(v));
-      } break;
-      case SASS_COLOR: {
-        e = new (ctx.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: {
-        e = new (ctx.mem) String_Constant(pstate, sass_string_get_value(v));
-      } break;
-      case SASS_LIST: {
-        List* l = new (ctx.mem) List(pstate, sass_list_get_length(v), sass_list_get_separator(v) == SASS_COMMA ? List::COMMA : List::SPACE);
-        for (size_t i = 0, L = sass_list_get_length(v); i < L; ++i) {
-          *l << cval_to_astnode(sass_list_get_value(v, i), ctx, backtrace, pstate);
-        }
-        e = l;
-      } break;
-      case SASS_MAP: {
-        Map* m = new (ctx.mem) 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), ctx, backtrace, pstate),
-            cval_to_astnode(sass_map_get_value(v, i), ctx, backtrace, pstate));
-        }
-        e = m;
-      } break;
-      case SASS_NULL: {
-        e = new (ctx.mem) Null(pstate);
-      } break;
-      case SASS_ERROR: {
-        error("Error in C function: " + string(sass_error_get_message(v)), pstate, backtrace);
-      } break;
-      case SASS_WARNING: {
-        error("Warning in C function: " + string(sass_warning_get_message(v)), pstate, backtrace);
-      } break;
-    }
-    return e;
-  }
-
-}
diff --git a/libsass/eval.hpp b/libsass/eval.hpp
deleted file mode 100644
--- a/libsass/eval.hpp
+++ /dev/null
@@ -1,88 +0,0 @@
-#ifndef SASS_EVAL_H
-#define SASS_EVAL_H
-
-#include <iostream>
-
-#include "context.hpp"
-#include "position.hpp"
-#include "operation.hpp"
-#include "environment.hpp"
-#include "contextualize.hpp"
-#include "listize.hpp"
-#include "sass_values.h"
-
-namespace Sass {
-  using namespace std;
-
-  typedef Environment<AST_Node*> Env;
-  struct Backtrace;
-  class Contextualize;
-  class Listize;
-
-  class Eval : public Operation_CRTP<Expression*, Eval> {
-
-    Context&   ctx;
-
-    Expression* fallback_impl(AST_Node* n);
-
-  public:
-    Contextualize* contextualize;
-    Listize*   listize;
-    Env*       env;
-    Backtrace* backtrace;
-    Eval(Context&, Contextualize*, Listize*, Env*, Backtrace*);
-    virtual ~Eval();
-    Eval* with(Env* e, Backtrace* bt); // for setting the env before eval'ing an expression
-    Eval* with(Selector* c, Env* e, Backtrace* bt, Selector* placeholder = 0, Selector* extender = 0); // for setting the env before eval'ing an expression
-    using Operation<Expression*>::operator();
-
-    // 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* 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_Constant*);
-    Expression* operator()(Media_Query*);
-    Expression* operator()(Media_Query_Expression*);
-    Expression* operator()(At_Root_Expression*);
-    Expression* operator()(Feature_Query*);
-    Expression* operator()(Feature_Query_Condition*);
-    Expression* operator()(Null*);
-    Expression* operator()(Argument*);
-    Expression* operator()(Arguments*);
-    Expression* operator()(Comment*);
-    Expression* operator()(Parent_Selector* p);
-
-    template <typename U>
-    Expression* fallback(U x) { return fallback_impl(x); }
-
-  private:
-    string interpolation(Expression* s);
-
-  };
-
-  Expression* cval_to_astnode(Sass_Value* v, Context& ctx, Backtrace* backtrace, ParserState pstate = ParserState("[AST]"));
-
-  bool eq(Expression*, Expression*, Context&);
-  bool lt(Expression*, Expression*, Context&);
-}
-
-#endif
diff --git a/libsass/expand.cpp b/libsass/expand.cpp
deleted file mode 100644
--- a/libsass/expand.cpp
+++ /dev/null
@@ -1,575 +0,0 @@
-#include <iostream>
-#include <typeinfo>
-
-#include "expand.hpp"
-#include "bind.hpp"
-#include "eval.hpp"
-#include "contextualize_eval.hpp"
-#include "to_string.hpp"
-#include "backtrace.hpp"
-#include "context.hpp"
-#include "parser.hpp"
-
-namespace Sass {
-
-  Expand::Expand(Context& ctx, Eval* eval, Contextualize_Eval* contextualize_eval, Env* env, Backtrace* bt)
-  : ctx(ctx),
-    eval(eval),
-    contextualize_eval(contextualize_eval),
-    env(env),
-    block_stack(vector<Block*>()),
-    property_stack(vector<String*>()),
-    selector_stack(vector<Selector*>()),
-    at_root_selector_stack(vector<Selector*>()),
-    in_at_root(false),
-    in_keyframes(false),
-    backtrace(bt)
-  { selector_stack.push_back(0); }
-
-  Statement* Expand::operator()(Block* b)
-  {
-    Env new_env;
-    new_env.link(*env);
-    env = &new_env;
-    Block* bb = new (ctx.mem) Block(b->pstate(), b->length(), b->is_root());
-    block_stack.push_back(bb);
-    append_block(b);
-    block_stack.pop_back();
-    env = env->parent();
-    return bb;
-  }
-
-  Statement* Expand::operator()(Ruleset* r)
-  {
-    bool old_in_at_root = in_at_root;
-    in_at_root = false;
-
-    if (in_keyframes) {
-      To_String to_string;
-      Keyframe_Rule* k = new (ctx.mem) Keyframe_Rule(r->pstate(), r->block()->perform(this)->block());
-      if (r->selector()) k->selector(r->selector()->perform(contextualize_eval->with(0, env, backtrace)));
-      in_at_root = old_in_at_root;
-      old_in_at_root = false;
-      return k;
-    }
-
-    Contextualize_Eval* contextual = contextualize_eval->with(selector_stack.back(), env, backtrace);
-    // if (old_in_at_root && !r->selector()->has_reference())
-    //   contextual = contextualize_eval->with(selector_stack.back(), env, backtrace);
-
-    Selector* sel_ctx = r->selector()->perform(contextual);
-    if (sel_ctx == 0) throw "Cannot expand null selector";
-
-    Emitter emitter(&ctx);
-    Inspect isp(emitter);
-    sel_ctx->perform(&isp);
-    string str = isp.get_buffer();
-    str += ";";
-
-    Parser p(ctx, r->pstate());
-    p.block_stack.push_back(r->selector() ? r->selector()->last_block() : 0);
-    p.last_media_block = r->selector() ? r->selector()->media_block() : 0;
-    p.source   = str.c_str();
-    p.position = str.c_str();
-    p.end      = str.c_str() + strlen(str.c_str());
-    Selector_List* sel_lst = p.parse_selector_group();
-    // sel_lst->pstate(isp.remap(sel_lst->pstate()));
-
-    for(size_t i = 0; i < sel_lst->length(); i++) {
-
-      Complex_Selector* pIter = (*sel_lst)[i];
-      while (pIter) {
-        Compound_Selector* pHead = pIter->head();
-        // pIter->pstate(isp.remap(pIter->pstate()));
-        if (pHead) {
-          // pHead->pstate(isp.remap(pHead->pstate()));
-          // (*pHead)[0]->pstate(isp.remap((*pHead)[0]->pstate()));
-        }
-        pIter = pIter->tail();
-      }
-    }
-    sel_ctx = sel_lst;
-
-    selector_stack.push_back(sel_ctx);
-    Block* blk = r->block()->perform(this)->block();
-    Ruleset* rr = new (ctx.mem) Ruleset(r->pstate(),
-                                        sel_ctx,
-                                        blk);
-    rr->tabs(r->tabs());
-    selector_stack.pop_back();
-    in_at_root = old_in_at_root;
-    old_in_at_root = false;
-    return rr;
-  }
-
-  Statement* Expand::operator()(Propset* p)
-  {
-    property_stack.push_back(p->property_fragment());
-    Block* expanded_block = p->block()->perform(this)->block();
-
-    Block* current_block = block_stack.back();
-    for (size_t i = 0, L = expanded_block->length(); i < L; ++i) {
-      Statement* stm = (*expanded_block)[i];
-      if (typeid(*stm) == typeid(Declaration)) {
-        Declaration* dec = static_cast<Declaration*>(stm);
-        String_Schema* combined_prop = new (ctx.mem) String_Schema(p->pstate());
-        if (!property_stack.empty()) {
-          *combined_prop << property_stack.back()
-                         << new (ctx.mem) String_Constant(p->pstate(), "-")
-                         << dec->property(); // TODO: eval the prop into a string constant
-        }
-        else {
-          *combined_prop << dec->property();
-        }
-        dec->property(combined_prop);
-        *current_block << 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);
-      }
-    }
-
-    property_stack.pop_back();
-
-    return 0;
-  }
-
-  Statement* Expand::operator()(Feature_Block* f)
-  {
-    Expression* feature_queries = f->feature_queries()->perform(eval->with(env, backtrace));
-    Feature_Block* ff = new (ctx.mem) Feature_Block(f->pstate(),
-                                                    static_cast<Feature_Query*>(feature_queries),
-                                                    f->block()->perform(this)->block());
-    ff->selector(selector_stack.back());
-    return ff;
-  }
-
-  Statement* Expand::operator()(Media_Block* m)
-  {
-    To_String to_string(&ctx);
-    Expression* mq = m->media_queries()->perform(eval->with(env, backtrace));
-    mq = Parser::from_c_str(mq->perform(&to_string).c_str(), ctx, mq->pstate()).parse_media_queries();
-    Media_Block* mm = new (ctx.mem) Media_Block(m->pstate(),
-                                                static_cast<List*>(mq),
-                                                m->block()->perform(this)->block(),
-                                                selector_stack.back());
-    mm->tabs(m->tabs());
-    return mm;
-  }
-
-  Statement* Expand::operator()(At_Root_Block* a)
-  {
-    in_at_root = true;
-    at_root_selector_stack.push_back(0);
-    Block* ab = a->block();
-    Expression* ae = a->expression();
-    if (ae) ae = ae->perform(eval->with(env, backtrace));
-    else ae = new (ctx.mem) At_Root_Expression(a->pstate());
-    Block* bb = ab ? ab->perform(this)->block() : 0;
-    At_Root_Block* aa = new (ctx.mem) At_Root_Block(a->pstate(),
-                                                    bb,
-                                                    static_cast<At_Root_Expression*>(ae));
-    at_root_selector_stack.pop_back();
-    in_at_root = false;
-    return aa;
-  }
-
-  Statement* Expand::operator()(At_Rule* a)
-  {
-    bool old_in_keyframes = in_keyframes;
-    in_keyframes = a->is_keyframes();
-    Block* ab = a->block();
-    Selector* as = a->selector();
-    Expression* av = a->value();
-    if (as) as = as->perform(contextualize_eval->with(0, env, backtrace));
-    else if (av) av = av->perform(eval->with(env, backtrace));
-    Block* bb = ab ? ab->perform(this)->block() : 0;
-    At_Rule* aa = new (ctx.mem) At_Rule(a->pstate(),
-                                        a->keyword(),
-                                        as,
-                                        bb);
-    if (av) aa->value(av);
-    in_keyframes = old_in_keyframes;
-    return aa;
-  }
-
-  Statement* Expand::operator()(Declaration* d)
-  {
-    String* old_p = d->property();
-    String* new_p = static_cast<String*>(old_p->perform(eval->with(env, backtrace)));
-    Selector* p = selector_stack.size() <= 1 ? 0 : selector_stack.back();
-    Expression* value = d->value()->perform(eval->with(p, env, backtrace));
-    if (value->is_invisible() && !d->is_important()) return 0;
-    Declaration* decl = new (ctx.mem) Declaration(d->pstate(),
-                                                  new_p,
-                                                  value,
-                                                  d->is_important());
-    decl->tabs(d->tabs());
-    return decl;
-  }
-
-  Statement* Expand::operator()(Assignment* a)
-  {
-    string var(a->variable());
-    Selector* p = selector_stack.size() <= 1 ? 0 : selector_stack.back();
-    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(eval->with(p, env, backtrace)));
-          }
-        }
-        else {
-          env->set_global(var, a->value()->perform(eval->with(p, env, backtrace)));
-        }
-      }
-      else {
-        env->set_global(var, a->value()->perform(eval->with(p, env, backtrace)));
-      }
-    }
-    else if (a->is_default()) {
-      if (env->has_lexical(var)) {
-        auto cur = env;
-        while (cur && cur->is_lexical()) {
-          if (cur->has_local(var)) {
-            if (AST_Node* node = cur->get_local(var)) {
-              Expression* e = dynamic_cast<Expression*>(node);
-              if (!e || e->concrete_type() == Expression::NULL_VAL) {
-                cur->set_local(var, a->value()->perform(eval->with(p, env, backtrace)));
-              }
-            }
-            else {
-              throw runtime_error("Env not in sync");
-            }
-            return 0;
-          }
-          cur = cur->parent();
-        }
-        throw runtime_error("Env not in sync");
-      }
-      else if (env->has_global(var)) {
-        if (AST_Node* node = env->get_global(var)) {
-          Expression* e = dynamic_cast<Expression*>(node);
-          if (!e || e->concrete_type() == Expression::NULL_VAL) {
-            env->set_global(var, a->value()->perform(eval->with(p, env, backtrace)));
-          }
-        }
-      }
-      else if (env->is_lexical()) {
-        env->set_local(var, a->value()->perform(eval->with(p, env, backtrace)));
-      }
-      else {
-        env->set_local(var, a->value()->perform(eval->with(p, env, backtrace)));
-      }
-    }
-    else {
-      env->set_lexical(var, a->value()->perform(eval->with(p, env, backtrace)));
-    }
-    return 0;
-  }
-
-  Statement* Expand::operator()(Import* imp)
-  {
-    Import* result = new (ctx.mem) Import(imp->pstate());
-    for ( size_t i = 0, S = imp->urls().size(); i < S; ++i) {
-      result->urls().push_back(imp->urls()[i]->perform(eval->with(env, backtrace)));
-    }
-    return result;
-  }
-
-  Statement* Expand::operator()(Import_Stub* i)
-  {
-    append_block(ctx.style_sheets[i->file_name()]);
-    return 0;
-  }
-
-  Statement* Expand::operator()(Warning* w)
-  {
-    // eval handles this too, because warnings may occur in functions
-    w->perform(eval->with(env, backtrace));
-    return 0;
-  }
-
-  Statement* Expand::operator()(Error* e)
-  {
-    // eval handles this too, because errors may occur in functions
-    e->perform(eval->with(env, backtrace));
-    return 0;
-  }
-
-  Statement* Expand::operator()(Debug* d)
-  {
-    // eval handles this too, because warnings may occur in functions
-    d->perform(eval->with(env, backtrace));
-    return 0;
-  }
-
-  Statement* Expand::operator()(Comment* c)
-  {
-    // TODO: eval the text, once we're parsing/storing it as a String_Schema
-    return new (ctx.mem) Comment(c->pstate(), static_cast<String*>(c->text()->perform(eval->with(env, backtrace))), c->is_important());
-  }
-
-  Statement* Expand::operator()(If* i)
-  {
-    if (*i->predicate()->perform(eval->with(env, backtrace))) {
-      append_block(i->consequent());
-    }
-    else {
-      Block* alt = i->alternative();
-      if (alt) append_block(alt);
-    }
-    return 0;
-  }
-
-  // For does not create a new env scope
-  // But iteration vars are reset afterwards
-  Statement* Expand::operator()(For* f)
-  {
-    string variable(f->variable());
-    Expression* low = f->lower_bound()->perform(eval->with(env, backtrace));
-    if (low->concrete_type() != Expression::NUMBER) {
-      error("lower bound of `@for` directive must be numeric", low->pstate(), backtrace);
-    }
-    Expression* high = f->upper_bound()->perform(eval->with(env, backtrace));
-    if (high->concrete_type() != Expression::NUMBER) {
-      error("upper bound of `@for` directive must be numeric", high->pstate(), backtrace);
-    }
-    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()) {
-      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
-    Number* it = 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();
-    if (start < end) {
-      if (f->is_inclusive()) ++end;
-      for (double i = start;
-           i < end;
-           ++i) {
-        it->value(i);
-        env->set_local(variable, it);
-        append_block(body);
-      }
-    } else {
-      if (f->is_inclusive()) --end;
-      for (double i = start;
-           i > end;
-           --i) {
-        it->value(i);
-        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);
-    return 0;
-  }
-
-  // Eval does not create a new env scope
-  // But iteration vars are reset afterwards
-  Statement* Expand::operator()(Each* e)
-  {
-    vector<string> variables(e->variables());
-    Expression* expr = e->list()->perform(eval->with(env, backtrace));
-    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 = new (ctx.mem) List(expr->pstate(), 1, List::COMMA);
-      *list << expr;
-    }
-    else {
-      list = static_cast<List*>(expr);
-    }
-    // remember variables and then reset them
-    vector<AST_Node*> old_vars(variables.size());
-    for (size_t i = 0, L = variables.size(); i < L; ++i) {
-      old_vars[i] = env->has_local(variables[i]) ? env->get_local(variables[i]) : 0;
-      env->set_local(variables[i], 0);
-    }
-    Block* body = e->block();
-
-    if (map) {
-      for (auto key : map->keys()) {
-        Expression* k = key->perform(eval->with(env, backtrace));
-        Expression* v = map->at(key)->perform(eval->with(env, backtrace));
-
-        if (variables.size() == 1) {
-          List* variable = new (ctx.mem) List(map->pstate(), 2, List::SPACE);
-          *variable << k;
-          *variable << v;
-          env->set_local(variables[0], variable);
-        } else {
-          env->set_local(variables[0], k);
-          env->set_local(variables[1], v);
-        }
-        append_block(body);
-      }
-    }
-    else {
-      for (size_t i = 0, L = list->length(); i < L; ++i) {
-        List* variable = 0;
-        if ((*list)[i]->concrete_type() != Expression::LIST  || variables.size() == 1) {
-          variable = new (ctx.mem) List((*list)[i]->pstate(), 1, List::COMMA);
-          *variable << (*list)[i];
-        }
-        else {
-          variable = static_cast<List*>((*list)[i]);
-        }
-        for (size_t j = 0, K = variables.size(); j < K; ++j) {
-          if (j < variable->length()) {
-            env->set_local(variables[j], (*variable)[j]->perform(eval->with(env, backtrace)));
-          }
-          else {
-            env->set_local(variables[j], new (ctx.mem) Null(expr->pstate()));
-          }
-        }
-        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]);
-    }
-    return 0;
-  }
-
-  Statement* Expand::operator()(While* w)
-  {
-    Expression* pred = w->predicate();
-    Block* body = w->block();
-    while (*pred->perform(eval->with(env, backtrace))) {
-      append_block(body);
-    }
-    return 0;
-  }
-
-  Statement* Expand::operator()(Return* 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 = static_cast<Selector_List*>(selector_stack.back());
-    if (!extender) return 0;
-    Contextualize_Eval* eval = contextualize_eval->with(0, env, backtrace);
-    Selector_List* selector_list = static_cast<Selector_List*>(e->selector());
-    Selector_List* contextualized = static_cast<Selector_List*>(selector_list->perform(eval));
-    // ToDo: remove once feature proves stable!
-    // if (contextualized->length() != 1) {
-    //   error("selector groups may not be extended", extendee->pstate(), backtrace);
-    // }
-    for (auto complex_sel : contextualized->elements()) {
-      Complex_Selector* c = complex_sel;
-      if (!c->head() || c->tail()) {
-        error("nested selectors may not be extended", c->pstate(), backtrace);
-      }
-      Compound_Selector* compound_sel = c->head();
-      compound_sel->is_optional(selector_list->is_optional());
-      // // need to convert the compound selector into a by-value data structure
-      // vector<string> target_vec;
-      // for (size_t i = 0, L = compound_sel->length(); i < L; ++i)
-      // { target_vec.push_back((*compound_sel)[i]->perform(&to_string)); }
-      for (size_t i = 0, L = extender->length(); i < L; ++i) {
-        // let's test this out
-        // cerr << "REGISTERING EXTENSION REQUEST: " << (*extender)[i]->perform(&to_string) << " <- " << compound_sel->perform(&to_string) << endl;
-        ctx.subset_map.put(compound_sel->to_str_vec(), make_pair((*extender)[i], compound_sel));
-      }
-    }
-    return 0;
-  }
-
-  Statement* Expand::operator()(Definition* d)
-  {
-    Definition* dd = new (ctx.mem) Definition(*d);
-    env->local_frame()[d->name() +
-                        (d->type() == Definition::MIXIN ? "[m]" : "[f]")] = dd;
-    // set the static link so we can have lexical scoping
-    dd->environment(env);
-    return 0;
-  }
-
-  Statement* Expand::operator()(Mixin_Call* c)
-  {
-    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();
-    Selector* p = selector_stack.size() <= 1 ? 0 : selector_stack.back();
-
-    Arguments* args = static_cast<Arguments*>(c->arguments()
-                                               ->perform(eval->with(p, env, backtrace)));
-    Backtrace here(backtrace, c->pstate(), ", in mixin `" + c->name() + "`");
-    backtrace = &here;
-    Env new_env;
-    new_env.link(def->environment());
-    if (c->block()) {
-      // represent mixin content blocks as thunks/closures
-      Definition* thunk = new (ctx.mem) Definition(c->pstate(),
-                                                   "@content",
-                                                   new (ctx.mem) Parameters(c->pstate()),
-                                                   c->block(),
-                                                   &ctx,
-                                                   Definition::MIXIN);
-      thunk->environment(env);
-      new_env.local_frame()["@content[m]"] = thunk;
-    }
-    bind("mixin " + c->name(), params, args, ctx, &new_env, eval);
-    Env* old_env = env;
-    env = &new_env;
-    append_block(body);
-    env = old_env;
-    backtrace = here.parent;
-    return 0;
-  }
-
-  Statement* Expand::operator()(Content* c)
-  {
-    // convert @content directives into mixin calls to the underlying thunk
-    if (!env->has("@content[m]")) return 0;
-    Mixin_Call* call = new (ctx.mem) Mixin_Call(c->pstate(),
-                                                "@content",
-                                                new (ctx.mem) Arguments(c->pstate()));
-    return call->perform(this);
-  }
-
-  inline Statement* Expand::fallback_impl(AST_Node* n)
-  {
-    error("unknown internal error; please contact the LibSass maintainers", n->pstate(), backtrace);
-    String_Constant* msg = new (ctx.mem) String_Constant(ParserState("[WARN]"), string("`Expand` doesn't handle ") + typeid(*n).name());
-    return new (ctx.mem) Warning(ParserState("[WARN]"), msg);
-  }
-
-  inline void Expand::append_block(Block* b)
-  {
-    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) *current_block << ith;
-    }
-  }
-}
diff --git a/libsass/expand.hpp b/libsass/expand.hpp
deleted file mode 100644
--- a/libsass/expand.hpp
+++ /dev/null
@@ -1,78 +0,0 @@
-#ifndef SASS_EXPAND_H
-#define SASS_EXPAND_H
-
-#include <map>
-#include <vector>
-#include <iostream>
-
-#include "ast.hpp"
-#include "eval.hpp"
-#include "operation.hpp"
-#include "environment.hpp"
-#include "contextualize.hpp"
-
-namespace Sass {
-  using namespace std;
-
-  class Context;
-  class Eval;
-  class Contextualize_Eval;
-  typedef Environment<AST_Node*> Env;
-  struct Backtrace;
-
-  class Expand : public Operation_CRTP<Statement*, Expand> {
-
-    Context&          ctx;
-    Eval*             eval;
-    Contextualize_Eval*    contextualize_eval;
-    Env*              env;
-    vector<Block*>    block_stack;
-    vector<String*>   property_stack;
-    vector<Selector*> selector_stack;
-    vector<Selector*> at_root_selector_stack;
-    bool              in_at_root;
-    bool              in_keyframes;
-    Backtrace*        backtrace;
-
-    Statement* fallback_impl(AST_Node* n);
-
-  public:
-    Expand(Context&, Eval*, Contextualize_Eval*, Env*, Backtrace*);
-    virtual ~Expand() { }
-
-    using Operation<Statement*>::operator();
-
-    Statement* operator()(Block*);
-    Statement* operator()(Ruleset*);
-    Statement* operator()(Propset*);
-    Statement* operator()(Media_Block*);
-    Statement* operator()(Feature_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*);
-
-    template <typename U>
-    Statement* fallback(U x) { return fallback_impl(x); }
-
-    void append_block(Block*);
-  };
-
-}
-
-#endif
diff --git a/libsass/extend.cpp b/libsass/extend.cpp
deleted file mode 100644
--- a/libsass/extend.cpp
+++ /dev/null
@@ -1,2010 +0,0 @@
-#include "extend.hpp"
-#include "context.hpp"
-#include "contextualize.hpp"
-#include "to_string.hpp"
-#include "backtrace.hpp"
-#include "paths.hpp"
-#include "parser.hpp"
-#include "node.hpp"
-#include "sass_util.hpp"
-#include "debug.hpp"
-#include <iostream>
-#include <deque>
-
-/*
- NOTES:
-
- - The print* functions print to cerr. This allows our testing frameworks (like sass-spec) to ignore the output, which
-   is very helpful when debugging. The format of the output is mainly to wrap things in square brackets to match what
-   ruby already outputs (to make comparisons easier).
-
- - For the direct porting effort, we're trying to port method-for-method until we get all the tests passing.
-   Where applicable, I've tried to include the ruby code above the function for reference until all our tests pass.
-   The ruby code isn't always directly portable, so I've tried to include any modified ruby code that was actually
-   used for the porting.
-
- - DO NOT try to optimize yet. We get a tremendous benefit out of comparing the output of each stage of the extend to the ruby
-   output at the same stage. This makes it much easier to determine where problems are. Try to keep as close to
-   the ruby code as you can until we have all the sass-spec tests passing. Then, we should optimize. However, if you see
-   something that could probably be optimized, let's not forget it. Add a // TODO: or // IMPROVEMENT: comment.
-
- - Coding conventions in this file (these may need to be changed before merging back into master)
-   - Very basic hungarian notation:
-     p prefix for pointers (pSelector)
-     no prefix for value types and references (selector)
-   - Use STL iterators where possible
-   - prefer verbose naming over terse naming
-   - use typedefs for STL container types for make maintenance easier
-
- - You may see a lot of comments that say "// TODO: is this the correct combinator?". See the comment referring to combinators
-   in extendCompoundSelector for a more extensive explanation of my confusion. I think our divergence in data model from ruby
-   sass causes this to be necessary.
-
-
- GLOBAL TODOS:
-
- - wrap the contents of the print functions in DEBUG preprocesser conditionals so they will be optimized away in non-debug mode.
-
- - consider making the extend* functions member functions to avoid passing around ctx and subsetMap map around. This has the
-   drawback that the implementation details of the operator are then exposed to the outside world, which is not ideal and
-   can cause additional compile time dependencies.
-
- - mark the helper methods in this file static to given them compilation unit linkage.
-
- - implement parent directive matching
-
- - fix compilation warnings for unused Extend members if we really don't need those references anymore.
- */
-
-
-namespace Sass {
-
-
-  typedef pair<Complex_Selector*, Compound_Selector*> ExtensionPair;
-  typedef vector<ExtensionPair> SubsetMapEntries;
-
-
-
-#ifdef DEBUG
-
-  // TODO: move the ast specific ostream operators into ast.hpp/ast.cpp
-  ostream& operator<<(ostream& os, const Complex_Selector::Combinator combinator) {
-    switch (combinator) {
-      case Complex_Selector::ANCESTOR_OF: os << "\" \""; break;
-      case Complex_Selector::PARENT_OF:   os << "\">\""; break;
-      case Complex_Selector::PRECEDES:    os << "\"~\""; break;
-      case Complex_Selector::ADJACENT_TO: os << "\"+\""; break;
-    }
-
-    return os;
-  }
-
-
-  ostream& operator<<(ostream& os, Compound_Selector& compoundSelector) {
-    To_String to_string;
-    os << compoundSelector.perform(&to_string);
-    return os;
-  }
-
-
-  // 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;
-
-    if (message) {
-      cerr << message;
-    }
-
-    if (pCompoundSelector) {
-      cerr << *pCompoundSelector;
-    } else {
-      cerr << "NULL";
-    }
-
-    if (newline) {
-      cerr << endl;
-    }
-  }
-
-
-  ostream& operator<<(ostream& os, Complex_Selector& complexSelector) {
-    To_String to_string;
-
-    os << "[";
-    Complex_Selector* pIter = &complexSelector;
-    bool first = true;
-    while (pIter) {
-      if (pIter->combinator() != Complex_Selector::ANCESTOR_OF) {
-        if (!first) {
-          os << ", ";
-        }
-        first = false;
-        os << pIter->combinator();
-      }
-
-      if (!first) {
-        os << ", ";
-      }
-      first = false;
-
-      if (pIter->head()) {
-        os << pIter->head()->perform(&to_string);
-      } else {
-        os << "NULL_HEAD";
-      }
-
-      pIter = pIter->tail();
-    }
-    os << "]";
-
-    return os;
-  }
-
-
-  // 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;
-
-    if (message) {
-      cerr << message;
-    }
-
-    if (pComplexSelector) {
-      cerr << *pComplexSelector;
-    } else {
-      cerr << "NULL";
-    }
-
-    if (newline) {
-      cerr << endl;
-    }
-  }
-
-
-  // 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) {
-      cerr << message;
-    }
-
-    // Convert to a deque of strings so we can sort since order doesn't matter in a set. This should cut down on
-    // the differences we see when debug printing.
-    typedef deque<string> SourceStrings;
-    SourceStrings sourceStrings;
-    for (SourcesSet::iterator iterator = sources.begin(), iteratorEnd = sources.end(); iterator != iteratorEnd; ++iterator) {
-      Complex_Selector* pSource = *iterator;
-      stringstream sstream;
-      sstream << complexSelectorToNode(pSource, ctx);
-      sourceStrings.push_back(sstream.str());
-    }
-
-    // Sort to get consistent output
-    std::sort(sourceStrings.begin(), sourceStrings.end());
-
-    cerr << "SourcesSet[";
-    for (SourceStrings::iterator iterator = sourceStrings.begin(), iteratorEnd = sourceStrings.end(); iterator != iteratorEnd; ++iterator) {
-      string source = *iterator;
-      if (iterator != sourceStrings.begin()) {
-        cerr << ", ";
-      }
-      cerr << source;
-    }
-    cerr << "]";
-
-    if (newline) {
-      cerr << endl;
-    }
-  }
-
-
-  ostream& operator<<(ostream& os, SubsetMapEntries& entries) {
-    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
-
-      if (iterator != entries.begin()) {
-        os << ", ";
-      }
-
-      os << "(";
-
-      if (pExtComplexSelector) {
-        cerr << *pExtComplexSelector;
-      } else {
-        cerr << "NULL";
-      }
-
-      os << " -> ";
-
-      if (pExtCompoundSelector) {
-        cerr << *pExtCompoundSelector;
-      } else {
-        cerr << "NULL";
-      }
-
-      os << ")";
-
-    }
-
-    os << "]";
-
-    return os;
-  }
-#endif
-
-  static bool parentSuperselector(Complex_Selector* pOne, Complex_Selector* 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*/);
-
-    pOne->set_innermost(&fakeParentContainer, Complex_Selector::ANCESTOR_OF);
-    pTwo->set_innermost(&fakeParentContainer, Complex_Selector::ANCESTOR_OF);
-
-    bool isSuperselector = pOne->is_superselector_of(pTwo);
-
-    pOne->clear_innermost();
-    pTwo->clear_innermost();
-
-    return isSuperselector;
-  }
-
-  void nodeToComplexSelectorDeque(const Node& node, ComplexSelectorDeque& out, Context& ctx) {
-    for (NodeDeque::iterator iter = node.collection()->begin(), iterEnd = node.collection()->end(); iter != iterEnd; iter++) {
-      Node& child = *iter;
-      out.push_back(nodeToComplexSelector(child, ctx));
-    }
-  }
-
-  Node complexSelectorDequeToNode(const ComplexSelectorDeque& deque, Context& ctx) {
-    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));
-    }
-
-    return result;
-  }
-
-  class LcsCollectionComparator {
-  public:
-    LcsCollectionComparator(Context& ctx) : mCtx(ctx) {}
-
-    Context& mCtx;
-
-    bool operator()(Complex_Selector* pOne, Complex_Selector* pTwo, Complex_Selector*& pOut) const {
-      /*
-      This code is based on the following block from ruby sass' subweave
-        do |s1, s2|
-          next s1 if s1 == s2
-          next unless s1.first.is_a?(SimpleSequence) && s2.first.is_a?(SimpleSequence)
-          next s2 if parent_superselector?(s1, s2)
-          next s1 if parent_superselector?(s2, s1)
-        end
-      */
-
-      if (selectors_equal(*pOne, *pTwo, true /*simpleSelectorOrderDependent*/)) {
-        pOut = pOne;
-        return true;
-      }
-
-      if (pOne->combinator() != Complex_Selector::ANCESTOR_OF || pTwo->combinator() != Complex_Selector::ANCESTOR_OF) {
-        return false;
-      }
-
-      if (parentSuperselector(pOne, pTwo, mCtx)) {
-        pOut = pTwo;
-        return true;
-      }
-
-      if (parentSuperselector(pTwo, pOne, mCtx)) {
-        pOut = pOne;
-        return true;
-      }
-
-      return false;
-    }
-  };
-
-
-  /*
-  This is the equivalent of ruby's Sass::Util.lcs_backtrace.
-
-  # Computes a single longest common subsequence for arrays x and y.
-  # Algorithm from http://en.wikipedia.org/wiki/Longest_common_subsequence_problem#Reading_out_an_LCS
-  */
-  void lcs_backtrace(const LCSTable& c, ComplexSelectorDeque& x, ComplexSelectorDeque& y, int i, int j, const LcsCollectionComparator& comparator, ComplexSelectorDeque& out) {
-    //DEBUG_PRINTLN(LCS, "LCSBACK: X=" << x << " Y=" << y << " I=" << i << " J=" << j)
-    // TODO: make printComplexSelectorDeque and use DEBUG_EXEC AND DEBUG_PRINTLN HERE to get equivalent output
-
-    if (i == 0 || j == 0) {
-      DEBUG_PRINTLN(LCS, "RETURNING EMPTY")
-      return;
-    }
-
-
-    Complex_Selector* pCompareOut = NULL;
-    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);
-      out.push_back(pCompareOut);
-      return;
-    }
-
-    if (c[i][j - 1] > c[i - 1][j]) {
-      DEBUG_PRINTLN(LCS, "RETURNING AFTER TABLE COMPARE")
-      lcs_backtrace(c, x, y, i, j - 1, comparator, out);
-      return;
-    }
-
-    DEBUG_PRINTLN(LCS, "FINAL RETURN")
-    lcs_backtrace(c, x, y, i - 1, j, comparator, out);
-    return;
-  }
-
-  /*
-  This is the equivalent of ruby's Sass::Util.lcs_table.
-
-  # Calculates the memoization table for the Least Common Subsequence algorithm.
-  # Algorithm from http://en.wikipedia.org/wiki/Longest_common_subsequence_problem#Computing_the_length_of_the_LCS
-  */
-  void lcs_table(const ComplexSelectorDeque& x, const ComplexSelectorDeque& y, const LcsCollectionComparator& comparator, LCSTable& out) {
-    //DEBUG_PRINTLN(LCS, "LCSTABLE: X=" << x << " Y=" << y)
-    // TODO: make printComplexSelectorDeque and use DEBUG_EXEC AND DEBUG_PRINTLN HERE to get equivalent output
-
-    LCSTable c(x.size(), vector<int>(y.size()));
-
-    // These shouldn't be necessary since the vector will be initialized to 0 already.
-    // x.size.times {|i| c[i][0] = 0}
-    // y.size.times {|j| c[0][j] = 0}
-
-    for (size_t i = 1; i < x.size(); i++) {
-      for (size_t j = 1; j < y.size(); j++) {
-        Complex_Selector* pCompareOut = NULL;
-
-        if (comparator(x[i], y[j], pCompareOut)) {
-          c[i][j] = c[i - 1][j - 1] + 1;
-        } else {
-          c[i][j] = max(c[i][j - 1], c[i - 1][j]);
-        }
-      }
-    }
-
-    out = c;
-  }
-
-  /*
-  This is the equivalent of ruby's Sass::Util.lcs.
-
-  # Computes a single longest common subsequence for `x` and `y`.
-  # If there are more than one longest common subsequences,
-  # the one returned is that which starts first in `x`.
-
-  # @param x [NodeCollection]
-  # @param y [NodeCollection]
-  # @comparator An equality check between elements of `x` and `y`.
-  # @return [NodeCollection] The LCS
-
-  http://en.wikipedia.org/wiki/Longest_common_subsequence_problem
-  */
-  void lcs(ComplexSelectorDeque& x, ComplexSelectorDeque& y, const LcsCollectionComparator& comparator, Context& ctx, ComplexSelectorDeque& out) {
-    //DEBUG_PRINTLN(LCS, "LCS: X=" << x << " Y=" << y)
-    // TODO: make printComplexSelectorDeque and use DEBUG_EXEC AND DEBUG_PRINTLN HERE to get equivalent output
-
-    x.push_front(NULL);
-    y.push_front(NULL);
-
-    LCSTable table;
-    lcs_table(x, y, comparator, table);
-
-    return lcs_backtrace(table, x, y, static_cast<int>(x.size()) - 1, static_cast<int>(y.size()) - 1, comparator, out);
-  }
-
-
-  /*
-   This is the equivalent of ruby's Sequence.trim.
-
-   The following is the modified version of the ruby code that was more portable to C++. You
-   should be able to drop it into ruby 3.2.19 and get the same results from ruby sass.
-
-        # Avoid truly horrific quadratic behavior. TODO: I think there
-        # may be a way to get perfect trimming without going quadratic.
-        return seqses if seqses.size > 100
-
-        # Keep the results in a separate array so we can be sure we aren't
-        # comparing against an already-trimmed selector. This ensures that two
-        # identical selectors don't mutually trim one another.
-        result = seqses.dup
-
-        # This is n^2 on the sequences, but only comparing between
-        # separate sequences should limit the quadratic behavior.
-        seqses.each_with_index do |seqs1, i|
-          tempResult = []
-
-          for seq1 in seqs1 do
-            max_spec = 0
-            for seq in _sources(seq1) do
-              max_spec = [max_spec, seq.specificity].max
-            end
-
-
-            isMoreSpecificOuter = false
-            for seqs2 in result do
-              if seqs1.equal?(seqs2) then
-                next
-              end
-
-              # Second Law of Extend: the specificity of a generated selector
-              # should never be less than the specificity of the extending
-              # selector.
-              #
-              # See https://github.com/nex3/sass/issues/324.
-              isMoreSpecificInner = false
-              for seq2 in seqs2 do
-                isMoreSpecificInner = _specificity(seq2) >= max_spec && _superselector?(seq2, seq1)
-                if isMoreSpecificInner then
-                  break
-                end
-              end
-
-              if isMoreSpecificInner then
-                isMoreSpecificOuter = true
-                break
-              end
-            end
-
-            if !isMoreSpecificOuter then
-              tempResult.push(seq1)
-            end
-          end
-
-          result[i] = tempResult
-
-        end
-
-        result
-   */
-  /*
-   - IMPROVEMENT: We could probably work directly in the output trimmed deque.
-   */
-  static Node trim(Node& seqses, Context& ctx) {
-    // See the comments in the above ruby code before embarking on understanding this function.
-
-    // Avoid poor performance in extreme cases.
-    if (seqses.collection()->size() > 100) {
-      return seqses;
-    }
-
-
-    DEBUG_PRINTLN(TRIM, "TRIM: " << seqses)
-
-
-    Node result = Node::createCollection();
-    result.plus(seqses);
-
-    DEBUG_PRINTLN(TRIM, "RESULT INITIAL: " << result)
-
-    // Normally we use the standard STL iterators, but in this case, we need to access the result collection by index since we're
-    // iterating the input collection, computing a value, and then setting the result in the output collection. We have to keep track
-    // of the index manually.
-    int toTrimIndex = 0;
-
-    for (NodeDeque::iterator seqsesIter = seqses.collection()->begin(), seqsesIterEnd = seqses.collection()->end(); seqsesIter != seqsesIterEnd; ++seqsesIter) {
-      Node& seqs1 = *seqsesIter;
-
-      DEBUG_PRINTLN(TRIM, "SEQS1: " << seqs1 << " " << toTrimIndex)
-
-      Node tempResult = Node::createCollection();
-
-      for (NodeDeque::iterator seqs1Iter = seqs1.collection()->begin(), seqs1EndIter = seqs1.collection()->end(); seqs1Iter != seqs1EndIter; ++seqs1Iter) {
-        Node& seq1 = *seqs1Iter;
-
-        Complex_Selector* 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.
-        //
-        // TODO: I'm pretty sure there's a bug in the sources code. It was implemented for sass-spec's 182_test_nested_extend_loop test.
-        // While the test passes, I compared the state of each trim call to verify correctness. The last trim call had incorrect sources. We
-        // had an extra source that the ruby version did not have. Without a failing test case, this is going to be extra hard to find. My
-        // best guess at this point is that we're cloning an object somewhere and maintaining the sources when we shouldn't be. This is purely
-        // a guess though.
-        unsigned long maxSpecificity = 0;
-        SourcesSet sources = pSeq1->sources();
-
-        DEBUG_PRINTLN(TRIM, "TRIMASDF SEQ1: " << seq1)
-        DEBUG_EXEC(TRIM, printSourcesSet(sources, ctx, "TRIMASDF SOURCES: "))
-
-        for (SourcesSet::iterator sourcesSetIterator = sources.begin(), sourcesSetIteratorEnd = sources.end(); sourcesSetIterator != sourcesSetIteratorEnd; ++sourcesSetIterator) {
-          const Complex_Selector* const pCurrentSelector = *sourcesSetIterator;
-          maxSpecificity = max(maxSpecificity, pCurrentSelector->specificity());
-        }
-
-        DEBUG_PRINTLN(TRIM, "MAX SPECIFICITY: " << maxSpecificity)
-
-        bool isMoreSpecificOuter = false;
-
-        int resultIndex = 0;
-
-        for (NodeDeque::iterator resultIter = result.collection()->begin(), resultIterEnd = result.collection()->end(); resultIter != resultIterEnd; ++resultIter) {
-          Node& seqs2 = *resultIter;
-
-          DEBUG_PRINTLN(TRIM, "SEQS1: " << seqs1)
-          DEBUG_PRINTLN(TRIM, "SEQS2: " << seqs2)
-
-          // Do not compare the same sequence to itself. The ruby call we're trying to
-          // emulate is: seqs1.equal?(seqs2). equal? is an object comparison, not an equivalency comparision.
-          // Since we have the same pointers in seqes and results, we can do a pointer comparision. seqs1 is
-          // derived from seqses and seqs2 is derived from result.
-          if (seqs1.collection() == seqs2.collection()) {
-            DEBUG_PRINTLN(TRIM, "CONTINUE")
-            continue;
-          }
-
-          bool isMoreSpecificInner = false;
-
-          for (NodeDeque::iterator seqs2Iter = seqs2.collection()->begin(), seqs2IterEnd = seqs2.collection()->end(); seqs2Iter != seqs2IterEnd; ++seqs2Iter) {
-            Node& seq2 = *seqs2Iter;
-
-            Complex_Selector* pSeq2 = nodeToComplexSelector(seq2, ctx);
-
-            DEBUG_PRINTLN(TRIM, "SEQ2 SPEC: " << pSeq2->specificity())
-            DEBUG_PRINTLN(TRIM, "IS SPEC: " << pSeq2->specificity() << " >= " << maxSpecificity << " " << (pSeq2->specificity() >= maxSpecificity ? "true" : "false"))
-            DEBUG_PRINTLN(TRIM, "IS SUPER: " << (pSeq2->is_superselector_of(pSeq1) ? "true" : "false"))
-
-            isMoreSpecificInner = pSeq2->specificity() >= maxSpecificity && pSeq2->is_superselector_of(pSeq1);
-
-            if (isMoreSpecificInner) {
-              DEBUG_PRINTLN(TRIM, "FOUND MORE SPECIFIC")
-              break;
-            }
-          }
-
-          // If we found something more specific, we're done. Let the outer loop know and stop iterating.
-          if (isMoreSpecificInner) {
-            isMoreSpecificOuter = true;
-            break;
-          }
-
-          resultIndex++;
-        }
-
-        if (!isMoreSpecificOuter) {
-          DEBUG_PRINTLN(TRIM, "PUSHING: " << seq1)
-          tempResult.collection()->push_back(seq1);
-        }
-
-      }
-
-      DEBUG_PRINTLN(TRIM, "RESULT BEFORE ASSIGN: " << result)
-      DEBUG_PRINTLN(TRIM, "TEMP RESULT: " << toTrimIndex << " " << tempResult)
-      (*result.collection())[toTrimIndex] = tempResult;
-
-      toTrimIndex++;
-
-      DEBUG_PRINTLN(TRIM, "RESULT: " << result)
-    }
-
-    return result;
-  }
-
-
-
-  static bool parentSuperselector(const Node& one, const Node& two, 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*/);
-
-    Complex_Selector* pOneWithFakeParent = nodeToComplexSelector(one, ctx);
-    pOneWithFakeParent->set_innermost(&fakeParentContainer, Complex_Selector::ANCESTOR_OF);
-    Complex_Selector* pTwoWithFakeParent = nodeToComplexSelector(two, ctx);
-    pTwoWithFakeParent->set_innermost(&fakeParentContainer, Complex_Selector::ANCESTOR_OF);
-
-    return pOneWithFakeParent->is_superselector_of(pTwoWithFakeParent);
-  }
-
-
-  class ParentSuperselectorChunker {
-  public:
-    ParentSuperselectorChunker(Node& lcs, Context& ctx) : mLcs(lcs), mCtx(ctx) {}
-    Node& mLcs;
-    Context& mCtx;
-
-    bool operator()(const Node& seq) const {
-      // {|s| parent_superselector?(s.first, lcs.first)}
-      return parentSuperselector(seq.collection()->front(), mLcs.collection()->front(), mCtx);
-    }
-  };
-
-  class SubweaveEmptyChunker {
-  public:
-    bool operator()(const Node& seq) const {
-      // {|s| s.empty?}
-
-      return seq.collection()->empty();
-    }
-  };
-
-  /*
-  # Takes initial subsequences of `seq1` and `seq2` and returns all
-  # orderings of those subsequences. The initial subsequences are determined
-  # by a block.
-  #
-  # Destructively removes the initial subsequences of `seq1` and `seq2`.
-  #
-  # For example, given `(A B C | D E)` and `(1 2 | 3 4 5)` (with `|`
-  # denoting the boundary of the initial subsequence), this would return
-  # `[(A B C 1 2), (1 2 A B C)]`. The sequences would then be `(D E)` and
-  # `(3 4 5)`.
-  #
-  # @param seq1 [Array]
-  # @param seq2 [Array]
-  # @yield [a] Used to determine when to cut off the initial subsequences.
-  #   Called repeatedly for each sequence until it returns true.
-  # @yieldparam a [Array] A final subsequence of one input sequence after
-  #   cutting off some initial subsequence.
-  # @yieldreturn [Boolean] Whether or not to cut off the initial subsequence
-  #   here.
-  # @return [Array<Array>] All possible orderings of the initial subsequences.
-  def chunks(seq1, seq2)
-    chunk1 = []
-    chunk1 << seq1.shift until yield seq1
-    chunk2 = []
-    chunk2 << seq2.shift until yield seq2
-    return [] if chunk1.empty? && chunk2.empty?
-    return [chunk2] if chunk1.empty?
-    return [chunk1] if chunk2.empty?
-    [chunk1 + chunk2, chunk2 + chunk1]
-  end
-  */
-  template<typename ChunkerType>
-  static Node chunks(Node& seq1, Node& seq2, const ChunkerType& chunker) {
-    Node chunk1 = Node::createCollection();
-    while (!chunker(seq1)) {
-      chunk1.collection()->push_back(seq1.collection()->front());
-      seq1.collection()->pop_front();
-    }
-
-    Node chunk2 = Node::createCollection();
-    while (!chunker(seq2)) {
-      chunk2.collection()->push_back(seq2.collection()->front());
-      seq2.collection()->pop_front();
-    }
-
-    if (chunk1.collection()->empty() && chunk2.collection()->empty()) {
-      DEBUG_PRINTLN(CHUNKS, "RETURNING BOTH EMPTY")
-      return Node::createCollection();
-    }
-
-    if (chunk1.collection()->empty()) {
-      Node chunk2Wrapper = Node::createCollection();
-      chunk2Wrapper.collection()->push_back(chunk2);
-      DEBUG_PRINTLN(CHUNKS, "RETURNING ONE EMPTY")
-      return chunk2Wrapper;
-    }
-
-    if (chunk2.collection()->empty()) {
-      Node chunk1Wrapper = Node::createCollection();
-      chunk1Wrapper.collection()->push_back(chunk1);
-      DEBUG_PRINTLN(CHUNKS, "RETURNING TWO EMPTY")
-      return chunk1Wrapper;
-    }
-
-    Node perms = Node::createCollection();
-
-    Node firstPermutation = Node::createCollection();
-    firstPermutation.collection()->insert(firstPermutation.collection()->end(), chunk1.collection()->begin(), chunk1.collection()->end());
-    firstPermutation.collection()->insert(firstPermutation.collection()->end(), chunk2.collection()->begin(), chunk2.collection()->end());
-    perms.collection()->push_back(firstPermutation);
-
-    Node secondPermutation = Node::createCollection();
-    secondPermutation.collection()->insert(secondPermutation.collection()->end(), chunk2.collection()->begin(), chunk2.collection()->end());
-    secondPermutation.collection()->insert(secondPermutation.collection()->end(), chunk1.collection()->begin(), chunk1.collection()->end());
-    perms.collection()->push_back(secondPermutation);
-
-    DEBUG_PRINTLN(CHUNKS, "RETURNING PERM")
-
-    return perms;
-  }
-
-
-  static Node groupSelectors(Node& seq, Context& ctx) {
-    Node newSeq = Node::createCollection();
-
-    Node tail = Node::createCollection();
-    tail.plus(seq);
-
-    while (!tail.collection()->empty()) {
-      Node head = Node::createCollection();
-
-      do {
-        head.collection()->push_back(tail.collection()->front());
-        tail.collection()->pop_front();
-      } while (!tail.collection()->empty() && (head.collection()->back().isCombinator() || tail.collection()->front().isCombinator()));
-
-      newSeq.collection()->push_back(head);
-    }
-
-    return newSeq;
-  }
-
-
-  static void getAndRemoveInitialOps(Node& seq, Node& ops) {
-    NodeDeque& seqCollection = *(seq.collection());
-    NodeDeque& opsCollection = *(ops.collection());
-
-    while (seqCollection.size() > 0 && seqCollection.front().isCombinator()) {
-      opsCollection.push_back(seqCollection.front());
-      seqCollection.pop_front();
-    }
-  }
-
-
-  static void getAndRemoveFinalOps(Node& seq, Node& ops) {
-    NodeDeque& seqCollection = *(seq.collection());
-    NodeDeque& opsCollection = *(ops.collection());
-
-    while (seqCollection.size() > 0 && seqCollection.back().isCombinator()) {
-      opsCollection.push_back(seqCollection.back()); // Purposefully reversed to match ruby code
-      seqCollection.pop_back();
-    }
-  }
-
-
-  /*
-      def merge_initial_ops(seq1, seq2)
-        ops1, ops2 = [], []
-        ops1 << seq1.shift while seq1.first.is_a?(String)
-        ops2 << seq2.shift while seq2.first.is_a?(String)
-
-        newline = false
-        newline ||= !!ops1.shift if ops1.first == "\n"
-        newline ||= !!ops2.shift if ops2.first == "\n"
-
-        # If neither sequence is a subsequence of the other, they cannot be
-        # merged successfully
-        lcs = Sass::Util.lcs(ops1, ops2)
-        return unless lcs == ops1 || lcs == ops2
-        return (newline ? ["\n"] : []) + (ops1.size > ops2.size ? ops1 : ops2)
-      end
-  */
-  static Node mergeInitialOps(Node& seq1, Node& seq2, Context& ctx) {
-    Node ops1 = Node::createCollection();
-    Node ops2 = Node::createCollection();
-
-    getAndRemoveInitialOps(seq1, ops1);
-    getAndRemoveInitialOps(seq2, ops2);
-
-    // TODO: Do we have this information available to us?
-    // newline = false
-    // newline ||= !!ops1.shift if ops1.first == "\n"
-    // newline ||= !!ops2.shift if ops2.first == "\n"
-
-    // If neither sequence is a subsequence of the other, they cannot be merged successfully
-    DefaultLcsComparator lcsDefaultComparator;
-    Node opsLcs = lcs(ops1, ops2, lcsDefaultComparator, ctx);
-
-    if (!(opsLcs == ops1 || opsLcs == ops2)) {
-      return Node::createNil();
-    }
-
-    // TODO: more newline logic
-    // return (newline ? ["\n"] : []) + (ops1.size > ops2.size ? ops1 : ops2)
-
-    return (ops1.collection()->size() > ops2.collection()->size() ? ops1 : ops2);
-  }
-
-
-  /*
-      def merge_final_ops(seq1, seq2, res = [])
-
-
-        # This code looks complicated, but it's actually just a bunch of special
-        # cases for interactions between different combinators.
-        op1, op2 = ops1.first, ops2.first
-        if op1 && op2
-          sel1 = seq1.pop
-          sel2 = seq2.pop
-          if op1 == '~' && op2 == '~'
-            if sel1.superselector?(sel2)
-              res.unshift sel2, '~'
-            elsif sel2.superselector?(sel1)
-              res.unshift sel1, '~'
-            else
-              merged = sel1.unify(sel2.members, sel2.subject?)
-              res.unshift [
-                [sel1, '~', sel2, '~'],
-                [sel2, '~', sel1, '~'],
-                ([merged, '~'] if merged)
-              ].compact
-            end
-          elsif (op1 == '~' && op2 == '+') || (op1 == '+' && op2 == '~')
-            if op1 == '~'
-              tilde_sel, plus_sel = sel1, sel2
-            else
-              tilde_sel, plus_sel = sel2, sel1
-            end
-
-            if tilde_sel.superselector?(plus_sel)
-              res.unshift plus_sel, '+'
-            else
-              merged = plus_sel.unify(tilde_sel.members, tilde_sel.subject?)
-              res.unshift [
-                [tilde_sel, '~', plus_sel, '+'],
-                ([merged, '+'] if merged)
-              ].compact
-            end
-          elsif op1 == '>' && %w[~ +].include?(op2)
-            res.unshift sel2, op2
-            seq1.push sel1, op1
-          elsif op2 == '>' && %w[~ +].include?(op1)
-            res.unshift sel1, op1
-            seq2.push sel2, op2
-          elsif op1 == op2
-            return unless merged = sel1.unify(sel2.members, sel2.subject?)
-            res.unshift merged, op1
-          else
-            # Unknown selector combinators can't be unified
-            return
-          end
-          return merge_final_ops(seq1, seq2, res)
-        elsif op1
-          seq2.pop if op1 == '>' && seq2.last && seq2.last.superselector?(seq1.last)
-          res.unshift seq1.pop, op1
-          return merge_final_ops(seq1, seq2, res)
-        else # op2
-          seq1.pop if op2 == '>' && seq1.last && seq1.last.superselector?(seq2.last)
-          res.unshift seq2.pop, op2
-          return merge_final_ops(seq1, seq2, res)
-        end
-      end
-  */
-  static Node mergeFinalOps(Node& seq1, Node& seq2, Context& ctx, Node& res) {
-
-    Node ops1 = Node::createCollection();
-    Node ops2 = Node::createCollection();
-
-    getAndRemoveFinalOps(seq1, ops1);
-    getAndRemoveFinalOps(seq2, ops2);
-
-    // TODO: do we have newlines to remove?
-    // ops1.reject! {|o| o == "\n"}
-    // ops2.reject! {|o| o == "\n"}
-
-    if (ops1.collection()->empty() && ops2.collection()->empty()) {
-      return res;
-    }
-
-    if (ops1.collection()->size() > 1 || ops2.collection()->size() > 1) {
-      DefaultLcsComparator lcsDefaultComparator;
-      Node opsLcs = lcs(ops1, ops2, lcsDefaultComparator, ctx);
-
-      // 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)) {
-        return Node::createNil();
-      }
-
-      if (ops1.collection()->size() > ops2.collection()->size()) {
-        res.collection()->insert(res.collection()->begin(), ops1.collection()->rbegin(), ops1.collection()->rend());
-      } else {
-        res.collection()->insert(res.collection()->begin(), ops2.collection()->rbegin(), ops2.collection()->rend());
-      }
-
-      return res;
-    }
-
-    if (!ops1.collection()->empty() && !ops2.collection()->empty()) {
-
-      Node op1 = ops1.collection()->front();
-      Node op2 = ops2.collection()->front();
-
-      Node sel1 = seq1.collection()->back();
-      seq1.collection()->pop_back();
-
-      Node sel2 = seq2.collection()->back();
-      seq2.collection()->pop_back();
-
-      if (op1.combinator() == Complex_Selector::PRECEDES && op2.combinator() == Complex_Selector::PRECEDES) {
-
-        if (sel1.selector()->is_superselector_of(sel2.selector())) {
-
-          res.collection()->push_front(op1 /*PRECEDES - could have been op2 as well*/);
-          res.collection()->push_front(sel2);
-
-        } else if (sel2.selector()->is_superselector_of(sel1.selector())) {
-
-          res.collection()->push_front(op1 /*PRECEDES - could have been op2 as well*/);
-          res.collection()->push_front(sel1);
-
-        } else {
-
-          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
-          // 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);
-          pMergedWrapper->head(pMerged);
-
-          DEBUG_EXEC(ALL, printCompoundSelector(pMerged, "MERGED: "))
-
-          Node newRes = Node::createCollection();
-
-          Node firstPerm = Node::createCollection();
-          firstPerm.collection()->push_back(sel1);
-          firstPerm.collection()->push_back(Node::createCombinator(Complex_Selector::PRECEDES));
-          firstPerm.collection()->push_back(sel2);
-          firstPerm.collection()->push_back(Node::createCombinator(Complex_Selector::PRECEDES));
-          newRes.collection()->push_back(firstPerm);
-
-          Node secondPerm = Node::createCollection();
-          secondPerm.collection()->push_back(sel2);
-          secondPerm.collection()->push_back(Node::createCombinator(Complex_Selector::PRECEDES));
-          secondPerm.collection()->push_back(sel1);
-          secondPerm.collection()->push_back(Node::createCombinator(Complex_Selector::PRECEDES));
-          newRes.collection()->push_back(secondPerm);
-
-          if (pMerged) {
-            Node mergedPerm = Node::createCollection();
-            mergedPerm.collection()->push_back(Node::createSelector(pMergedWrapper, ctx));
-            mergedPerm.collection()->push_back(Node::createCombinator(Complex_Selector::PRECEDES));
-            newRes.collection()->push_back(mergedPerm);
-          }
-
-          res.collection()->push_front(newRes);
-
-          DEBUG_PRINTLN(ALL, "RESULT: " << res)
-
-        }
-
-      } else if (((op1.combinator() == Complex_Selector::PRECEDES && op2.combinator() == Complex_Selector::ADJACENT_TO)) || ((op1.combinator() == Complex_Selector::ADJACENT_TO && op2.combinator() == Complex_Selector::PRECEDES))) {
-
-          Node tildeSel = sel1;
-          Node tildeOp = op1;
-          Node plusSel = sel2;
-          Node plusOp = op2;
-          if (op1.combinator() != Complex_Selector::PRECEDES) {
-            tildeSel = sel2;
-            tildeOp = op2;
-            plusSel = sel1;
-            plusOp = op1;
-          }
-
-          if (tildeSel.selector()->is_superselector_of(plusSel.selector())) {
-
-            res.collection()->push_front(plusOp);
-            res.collection()->push_front(plusSel);
-
-          } else {
-
-            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
-            // 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);
-            pMergedWrapper->head(pMerged);
-
-            DEBUG_EXEC(ALL, printCompoundSelector(pMerged, "MERGED: "))
-
-            Node newRes = Node::createCollection();
-
-            Node firstPerm = Node::createCollection();
-            firstPerm.collection()->push_back(tildeSel);
-            firstPerm.collection()->push_back(Node::createCombinator(Complex_Selector::PRECEDES));
-            firstPerm.collection()->push_back(plusSel);
-            firstPerm.collection()->push_back(Node::createCombinator(Complex_Selector::ADJACENT_TO));
-            newRes.collection()->push_back(firstPerm);
-
-            if (pMerged) {
-              Node mergedPerm = Node::createCollection();
-              mergedPerm.collection()->push_back(Node::createSelector(pMergedWrapper, ctx));
-              mergedPerm.collection()->push_back(Node::createCombinator(Complex_Selector::ADJACENT_TO));
-              newRes.collection()->push_back(mergedPerm);
-            }
-
-            res.collection()->push_front(newRes);
-
-            DEBUG_PRINTLN(ALL, "RESULT: " << res)
-
-          }
-      } else if (op1.combinator() == Complex_Selector::PARENT_OF && (op2.combinator() == Complex_Selector::PRECEDES || op2.combinator() == Complex_Selector::ADJACENT_TO)) {
-
-        res.collection()->push_front(op2);
-        res.collection()->push_front(sel2);
-
-        seq2.collection()->push_back(sel1);
-        seq2.collection()->push_back(op1);
-
-      } else if (op2.combinator() == Complex_Selector::PARENT_OF && (op1.combinator() == Complex_Selector::PRECEDES || op1.combinator() == Complex_Selector::ADJACENT_TO)) {
-
-        res.collection()->push_front(op1);
-        res.collection()->push_front(sel1);
-
-        seq2.collection()->push_back(sel2);
-        seq2.collection()->push_back(op2);
-
-      } else if (op1.combinator() == op2.combinator()) {
-
-        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
-        // 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);
-        pMergedWrapper->head(pMerged);
-
-        DEBUG_EXEC(ALL, printCompoundSelector(pMerged, "MERGED: "))
-
-        if (!pMerged) {
-          return Node::createNil();
-        }
-
-        res.collection()->push_front(op1);
-        res.collection()->push_front(Node::createSelector(pMergedWrapper, ctx));
-
-        DEBUG_PRINTLN(ALL, "RESULT: " << res)
-
-      } else {
-        return Node::createNil();
-      }
-
-      return mergeFinalOps(seq1, seq2, ctx, res);
-
-    } else if (!ops1.collection()->empty()) {
-
-      Node op1 = ops1.collection()->front();
-
-      if (op1.combinator() == Complex_Selector::PARENT_OF && !seq2.collection()->empty() && seq2.collection()->back().selector()->is_superselector_of(seq1.collection()->back().selector())) {
-        seq2.collection()->pop_back();
-      }
-
-      // TODO: consider unshift(NodeCollection, Node)
-      res.collection()->push_front(op1);
-      res.collection()->push_front(seq1.collection()->back());
-      seq1.collection()->pop_back();
-
-      return mergeFinalOps(seq1, seq2, ctx, res);
-
-    } else { // !ops2.collection()->empty()
-
-      Node op2 = ops2.collection()->front();
-
-      if (op2.combinator() == Complex_Selector::PARENT_OF && !seq1.collection()->empty() && seq1.collection()->back().selector()->is_superselector_of(seq2.collection()->back().selector())) {
-        seq1.collection()->pop_back();
-      }
-
-      res.collection()->push_front(op2);
-      res.collection()->push_front(seq2.collection()->back());
-      seq2.collection()->pop_back();
-
-      return mergeFinalOps(seq1, seq2, ctx, res);
-
-    }
-
-  }
-
-
-  /*
-    This is the equivalent of ruby's Sequence.subweave.
-
-    Here is the original subweave code for reference during porting.
-
-      def subweave(seq1, seq2)
-        return [seq2] if seq1.empty?
-        return [seq1] if seq2.empty?
-
-        seq1, seq2 = seq1.dup, seq2.dup
-        return unless init = merge_initial_ops(seq1, seq2)
-        return unless fin = merge_final_ops(seq1, seq2)
-        seq1 = group_selectors(seq1)
-        seq2 = group_selectors(seq2)
-        lcs = Sass::Util.lcs(seq2, seq1) do |s1, s2|
-          next s1 if s1 == s2
-          next unless s1.first.is_a?(SimpleSequence) && s2.first.is_a?(SimpleSequence)
-          next s2 if parent_superselector?(s1, s2)
-          next s1 if parent_superselector?(s2, s1)
-        end
-
-        diff = [[init]]
-        until lcs.empty?
-          diff << chunks(seq1, seq2) {|s| parent_superselector?(s.first, lcs.first)} << [lcs.shift]
-          seq1.shift
-          seq2.shift
-        end
-        diff << chunks(seq1, seq2) {|s| s.empty?}
-        diff += fin.map {|sel| sel.is_a?(Array) ? sel : [sel]}
-        diff.reject! {|c| c.empty?}
-
-        result = Sass::Util.paths(diff).map {|p| p.flatten}.reject {|p| path_has_two_subjects?(p)}
-
-        result
-      end
-  */
-  static Node subweave(Node& one, Node& two, Context& ctx) {
-    // Check for the simple cases
-    if (one.collection()->size() == 0) {
-      Node out = Node::createCollection();
-      out.collection()->push_back(two);
-      return out;
-    }
-    if (two.collection()->size() == 0) {
-      Node out = Node::createCollection();
-      out.collection()->push_back(one);
-      return out;
-    }
-
-
-
-    Node seq1 = Node::createCollection();
-    seq1.plus(one);
-    Node seq2 = Node::createCollection();
-    seq2.plus(two);
-
-    DEBUG_PRINTLN(SUBWEAVE, "SUBWEAVE ONE: " << seq1)
-    DEBUG_PRINTLN(SUBWEAVE, "SUBWEAVE TWO: " << seq2)
-
-    Node init = mergeInitialOps(seq1, seq2, ctx);
-    if (init.isNil()) {
-      return Node::createNil();
-    }
-
-    DEBUG_PRINTLN(SUBWEAVE, "INIT: " << init)
-
-    Node res = Node::createCollection();
-    Node fin = mergeFinalOps(seq1, seq2, ctx, res);
-    if (fin.isNil()) {
-      return Node::createNil();
-    }
-
-    DEBUG_PRINTLN(SUBWEAVE, "FIN: " << fin)
-
-
-    // Moving this line up since fin isn't modified between now and when it happened before
-    // fin.map {|sel| sel.is_a?(Array) ? sel : [sel]}
-
-    for (NodeDeque::iterator finIter = fin.collection()->begin(), finEndIter = fin.collection()->end();
-           finIter != finEndIter; ++finIter) {
-
-      Node& childNode = *finIter;
-
-      if (!childNode.isCollection()) {
-        Node wrapper = Node::createCollection();
-        wrapper.collection()->push_back(childNode);
-        childNode = wrapper;
-      }
-
-    }
-
-    DEBUG_PRINTLN(SUBWEAVE, "FIN MAPPED: " << fin)
-
-
-
-    Node groupSeq1 = groupSelectors(seq1, ctx);
-    DEBUG_PRINTLN(SUBWEAVE, "SEQ1: " << groupSeq1)
-
-    Node groupSeq2 = groupSelectors(seq2, ctx);
-    DEBUG_PRINTLN(SUBWEAVE, "SEQ2: " << groupSeq2)
-
-
-    ComplexSelectorDeque groupSeq1Converted;
-    nodeToComplexSelectorDeque(groupSeq1, groupSeq1Converted, ctx);
-
-    ComplexSelectorDeque groupSeq2Converted;
-    nodeToComplexSelectorDeque(groupSeq2, groupSeq2Converted, ctx);
-
-    ComplexSelectorDeque out;
-    LcsCollectionComparator collectionComparator(ctx);
-    lcs(groupSeq2Converted, groupSeq1Converted, collectionComparator, ctx, out);
-    Node seqLcs = complexSelectorDequeToNode(out, ctx);
-
-    DEBUG_PRINTLN(SUBWEAVE, "SEQLCS: " << seqLcs)
-
-
-    Node initWrapper = Node::createCollection();
-    initWrapper.collection()->push_back(init);
-    Node diff = Node::createCollection();
-    diff.collection()->push_back(initWrapper);
-
-    DEBUG_PRINTLN(SUBWEAVE, "DIFF INIT: " << diff)
-
-
-    while (!seqLcs.collection()->empty()) {
-      ParentSuperselectorChunker superselectorChunker(seqLcs, ctx);
-      Node chunksResult = chunks(groupSeq1, groupSeq2, superselectorChunker);
-      diff.collection()->push_back(chunksResult);
-
-      Node lcsWrapper = Node::createCollection();
-      lcsWrapper.collection()->push_back(seqLcs.collection()->front());
-      seqLcs.collection()->pop_front();
-      diff.collection()->push_back(lcsWrapper);
-
-      groupSeq1.collection()->pop_front();
-      groupSeq2.collection()->pop_front();
-    }
-
-    DEBUG_PRINTLN(SUBWEAVE, "DIFF POST LCS: " << diff)
-
-
-    DEBUG_PRINTLN(SUBWEAVE, "CHUNKS: ONE=" << groupSeq1 << " TWO=" << groupSeq2)
-
-
-    SubweaveEmptyChunker emptyChunker;
-    Node chunksResult = chunks(groupSeq1, groupSeq2, emptyChunker);
-    diff.collection()->push_back(chunksResult);
-
-
-    DEBUG_PRINTLN(SUBWEAVE, "DIFF POST CHUNKS: " << diff)
-
-
-    diff.collection()->insert(diff.collection()->end(), fin.collection()->begin(), fin.collection()->end());
-
-    DEBUG_PRINTLN(SUBWEAVE, "DIFF POST FIN MAPPED: " << diff)
-
-    // JMA - filter out the empty nodes (use a new collection, since iterator erase() invalidates the old collection)
-    Node diffFiltered = Node::createCollection();
-    for (NodeDeque::iterator diffIter = diff.collection()->begin(), diffEndIter = diff.collection()->end();
-           diffIter != diffEndIter; ++diffIter) {
-      Node& node = *diffIter;
-      if (node.collection() && !node.collection()->empty()) {
-        diffFiltered.collection()->push_back(node);
-      }
-    }
-    diff = diffFiltered;
-
-    DEBUG_PRINTLN(SUBWEAVE, "DIFF POST REJECT: " << diff)
-
-
-    Node pathsResult = paths(diff, ctx);
-
-    DEBUG_PRINTLN(SUBWEAVE, "PATHS: " << pathsResult)
-
-
-    // We're flattening in place
-    for (NodeDeque::iterator pathsIter = pathsResult.collection()->begin(), pathsEndIter = pathsResult.collection()->end();
-      pathsIter != pathsEndIter; ++pathsIter) {
-
-      Node& child = *pathsIter;
-      child = flatten(child, ctx);
-    }
-
-    DEBUG_PRINTLN(SUBWEAVE, "FLATTENED: " << pathsResult)
-
-
-    /*
-      TODO: implement
-      rejected = mapped.reject {|p| path_has_two_subjects?(p)}
-      $stderr.puts "REJECTED: #{rejected}"
-     */
-
-
-    return pathsResult;
-
-  }
-  /*
-  // disabled to avoid clang warning [-Wunused-function]
-  static Node subweaveNaive(const Node& one, const Node& two, Context& ctx) {
-    Node out = Node::createCollection();
-
-    // Check for the simple cases
-    if (one.isNil()) {
-      out.collection()->push_back(two.clone(ctx));
-    } else if (two.isNil()) {
-      out.collection()->push_back(one.clone(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);
-      firstPerm.plus(twoCloned);
-      out.collection()->push_back(firstPerm);
-
-      Node secondPerm = two.clone(ctx);
-      Node oneCloned = one.clone(ctx);
-      secondPerm.plus(oneCloned );
-      out.collection()->push_back(secondPerm);
-    }
-
-    return out;
-  }
-  */
-
-
-  /*
-   This is the equivalent of ruby's Sequence.weave.
-
-   The following is the modified version of the ruby code that was more portable to C++. You
-   should be able to drop it into ruby 3.2.19 and get the same results from ruby sass.
-
-      def weave(path)
-        # This function works by moving through the selector path left-to-right,
-        # building all possible prefixes simultaneously. These prefixes are
-        # `befores`, while the remaining parenthesized suffixes is `afters`.
-        befores = [[]]
-        afters = path.dup
-
-        until afters.empty?
-          current = afters.shift.dup
-          last_current = [current.pop]
-
-          tempResult = []
-
-          for before in befores do
-            sub = subweave(before, current)
-            if sub.nil?
-              next
-            end
-
-            for seqs in sub do
-              tempResult.push(seqs + last_current)
-            end
-          end
-
-          befores = tempResult
-
-        end
-
-        return befores
-      end
-   */
-  /*
-      def weave(path)
-        befores = [[]]
-        afters = path.dup
-
-        until afters.empty?
-          current = afters.shift.dup
-
-          last_current = [current.pop]
-
-
-          tempResult = []
-
-          for before in befores do
-            sub = subweave(before, current)
-
-            if sub.nil?
-              next []
-            end
-
-
-            for seqs in sub do
-              toPush = seqs + last_current
-
-              tempResult.push(seqs + last_current)
-            end
-
-          end
-
-          befores = tempResult
-
-        end
-
-        return befores
-      end
-  */
-  static Node weave(Node& path, Context& ctx) {
-
-    DEBUG_PRINTLN(WEAVE, "WEAVE: " << path)
-
-    Node befores = Node::createCollection();
-    befores.collection()->push_back(Node::createCollection());
-
-    Node afters = Node::createCollection();
-    afters.plus(path);
-
-    while (!afters.collection()->empty()) {
-      Node current = afters.collection()->front().clone(ctx);
-      afters.collection()->pop_front();
-      DEBUG_PRINTLN(WEAVE, "CURRENT: " << current)
-
-      Node last_current = Node::createCollection();
-      last_current.collection()->push_back(current.collection()->back());
-      current.collection()->pop_back();
-      DEBUG_PRINTLN(WEAVE, "CURRENT POST POP: " << current)
-      DEBUG_PRINTLN(WEAVE, "LAST CURRENT: " << last_current)
-
-      Node tempResult = Node::createCollection();
-
-      for (NodeDeque::iterator beforesIter = befores.collection()->begin(), beforesEndIter = befores.collection()->end(); beforesIter != beforesEndIter; beforesIter++) {
-        Node& before = *beforesIter;
-
-        Node sub = subweave(before, current, ctx);
-
-        DEBUG_PRINTLN(WEAVE, "SUB: " << sub)
-
-        if (sub.isNil()) {
-          return Node::createCollection();
-        }
-
-        for (NodeDeque::iterator subIter = sub.collection()->begin(), subEndIter = sub.collection()->end(); subIter != subEndIter; subIter++) {
-          Node& seqs = *subIter;
-
-          Node toPush = Node::createCollection();
-          toPush.plus(seqs);
-          toPush.plus(last_current);
-
-          tempResult.collection()->push_back(toPush);
-
-        }
-      }
-
-      befores = tempResult;
-
-    }
-
-    return befores;
-  }
-
-
-
-  // This forward declaration is needed since extendComplexSelector calls extendCompoundSelector, which may recursively
-  // call extendComplexSelector again.
-  static Node extendComplexSelector(
-    Complex_Selector* pComplexSelector,
-    Context& ctx,
-    ExtensionSubsetMap& subsetMap,
-    set<Compound_Selector> seen);
-
-
-
-  /*
-   This is the equivalent of ruby's SimpleSequence.do_extend.
-
-    // TODO: I think I have some modified ruby code to put here. Check.
-  */
-  /*
-   ISSUES:
-   - Previous TODO: Do we need to group the results by extender?
-   - What does subject do in?: next unless unified = seq.members.last.unify(self_without_sel, subject?)
-   - IMPROVEMENT: The search for uniqueness at the end is not ideal since it's has to loop over everything...
-   - IMPROVEMENT: Check if the final search for uniqueness is doing anything that extendComplexSelector isn't already doing...
-   */
-  template<typename KeyType>
-  class GroupByToAFunctor {
-  public:
-    KeyType operator()(ExtensionPair& extPair) const {
-      Complex_Selector* pSelector = extPair.first;
-      return *pSelector;
-    }
-  };
-  static Node extendCompoundSelector(
-    Compound_Selector* pSelector,
-    Context& ctx,
-    ExtensionSubsetMap& subsetMap,
-    set<Compound_Selector> seen) {
-
-    DEBUG_EXEC(EXTEND_COMPOUND, printCompoundSelector(pSelector, "EXTEND COMPOUND: "))
-
-    Node extendedSelectors = Node::createCollection();
-
-    To_String to_string;
-
-    SubsetMapEntries entries = subsetMap.get_v(pSelector->to_str_vec());
-
-
-    typedef vector<pair<Complex_Selector, vector<ExtensionPair> > > GroupedByToAResult;
-
-    GroupByToAFunctor<Complex_Selector> extPairKeyFunctor;
-    GroupedByToAResult arr;
-    group_by_to_a(entries, extPairKeyFunctor, arr);
-
-
-    typedef pair<Compound_Selector*, Complex_Selector*> SelsNewSeqPair;
-    typedef vector<SelsNewSeqPair> SelsNewSeqPairCollection;
-
-
-    SelsNewSeqPairCollection holder;
-
-
-    for (GroupedByToAResult::iterator groupedIter = arr.begin(), groupedIterEnd = arr.end(); groupedIter != groupedIterEnd; groupedIter++) {
-      pair<Complex_Selector, vector<ExtensionPair> >& groupedPair = *groupedIter;
-
-      Complex_Selector& seq = groupedPair.first;
-      vector<ExtensionPair>& group = groupedPair.second;
-
-//      DEBUG_EXEC(EXTEND_COMPOUND, printComplexSelector(&seq, "SEQ: "))
-
-
-      Compound_Selector* pSels = new (ctx.mem) Compound_Selector(pSelector->pstate());
-      for (vector<ExtensionPair>::iterator groupIter = group.begin(), groupIterEnd = group.end(); groupIter != groupIterEnd; groupIter++) {
-        ExtensionPair& pair = *groupIter;
-        Compound_Selector* pCompound = pair.second;
-        for (size_t index = 0; index < pCompound->length(); index++) {
-          Simple_Selector* pSimpleSelector = (*pCompound)[index];
-          (*pSels) << pSimpleSelector;
-        }
-      }
-
-
-
-//      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
-
-
-
-      // TODO: This can return a Compound_Selector with no elements. Should that just be returning NULL?
-      Compound_Selector* pSelectorWithoutExtendSelectors = pSelector->minus(pExtCompoundSelector, ctx);
-
-
-//      DEBUG_EXEC(EXTEND_COMPOUND, printCompoundSelector(pSelector, "MEMBERS: "))
-//      DEBUG_EXEC(EXTEND_COMPOUND, printCompoundSelector(pSelectorWithoutExtendSelectors, "SELF_WO_SEL: "))
-
-
-      Compound_Selector* pInnermostCompoundSelector = pExtComplexSelector->base();
-      Compound_Selector* pUnifiedSelector = NULL;
-
-      if (!pInnermostCompoundSelector) {
-        pInnermostCompoundSelector = new (ctx.mem) Compound_Selector(pSelector->pstate());
-      }
-
-      pUnifiedSelector = pInnermostCompoundSelector->unify_with(pSelectorWithoutExtendSelectors, ctx);
-
-//      DEBUG_EXEC(EXTEND_COMPOUND, printCompoundSelector(pInnermostCompoundSelector, "LHS: "))
-//      DEBUG_EXEC(EXTEND_COMPOUND, printCompoundSelector(pSelectorWithoutExtendSelectors, "RHS: "))
-//      DEBUG_EXEC(EXTEND_COMPOUND, printCompoundSelector(pUnifiedSelector, "UNIFIED: "))
-
-      if (!pUnifiedSelector || pUnifiedSelector->length() == 0) {
-        continue;
-      }
-
-
-
-      // TODO: implement the parent directive match (if necessary based on test failures)
-      // next if group.map {|e, _| check_directives_match!(e, parent_directives)}.none?
-
-
-
-
-      // TODO: This seems a little fishy to me. See if it causes any problems. From the ruby, we should be able to just
-      // 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);
-      Complex_Selector* pNewInnerMost = new (ctx.mem) Complex_Selector(pSelector->pstate(), Complex_Selector::ANCESTOR_OF, pUnifiedSelector, NULL);
-      Complex_Selector::Combinator combinator = pNewSelector->clear_innermost();
-      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.";
-      }
-      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.";
-      }
-#endif
-
-
-      if (pSelector && pSelector->has_line_feed()) pNewSelector->has_line_feed(true);
-
-      // Set the sources on our new Complex_Selector to the sources of this simple sequence plus the thing we're extending.
-      DEBUG_PRINTLN(EXTEND_COMPOUND, "SOURCES SETTING ON NEW SEQ: " << complexSelectorToNode(pNewSelector, ctx))
-
-      DEBUG_EXEC(EXTEND_COMPOUND, SourcesSet oldSet = pNewSelector->sources(); printSourcesSet(oldSet, ctx, "SOURCES NEW SEQ BEGIN: "))
-
-      SourcesSet newSourcesSet = pSelector->sources();
-      DEBUG_EXEC(EXTEND_COMPOUND, printSourcesSet(newSourcesSet, ctx, "SOURCES THIS EXTEND: "))
-
-      newSourcesSet.insert(pExtComplexSelector);
-      DEBUG_EXEC(EXTEND_COMPOUND, printSourcesSet(newSourcesSet, ctx, "SOURCES WITH NEW SOURCE: "))
-
-      pNewSelector->addSources(newSourcesSet, ctx);
-
-      DEBUG_EXEC(EXTEND_COMPOUND, SourcesSet newSet = pNewSelector->sources(); printSourcesSet(newSet, ctx, "SOURCES ON NEW SELECTOR AFTER ADD: "))
-      DEBUG_EXEC(EXTEND_COMPOUND, printSourcesSet(pSelector->sources(), ctx, "SOURCES THIS EXTEND WHICH SHOULD BE SAME STILL: "))
-
-
-
-      holder.push_back(make_pair(pSels, pNewSelector));
-    }
-
-
-    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;
-
-
-      if (seen.find(*pSels) != seen.end()) {
-        continue;
-      }
-
-
-      set<Compound_Selector> recurseSeen(seen);
-      recurseSeen.insert(*pSels);
-
-
-      DEBUG_PRINTLN(EXTEND_COMPOUND, "RECURSING DO EXTEND: " << complexSelectorToNode(pNewSelector, ctx))
-
-      Node recurseExtendedSelectors = extendComplexSelector(pNewSelector, ctx, subsetMap, recurseSeen);
-
-      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;
-
-//        DEBUG_PRINTLN(EXTEND_COMPOUND, "EXTENDED AT THIS POINT: " << extendedSelectors)
-//        DEBUG_PRINTLN(EXTEND_COMPOUND, "SELECTOR EXISTS ALREADY: " << newSelector << " " << extendedSelectors.contains(newSelector, false /*simpleSelectorOrderDependent*/));
-
-        if (!extendedSelectors.contains(newSelector, false /*simpleSelectorOrderDependent*/)) {
-//          DEBUG_PRINTLN(EXTEND_COMPOUND, "ADDING NEW SELECTOR")
-          extendedSelectors.collection()->push_back(newSelector);
-        }
-      }
-    }
-
-    DEBUG_EXEC(EXTEND_COMPOUND, printCompoundSelector(pSelector, "EXTEND COMPOUND END: "))
-
-    return extendedSelectors;
-  }
-
-
-  static bool complexSelectorHasExtension(
-    Complex_Selector* pComplexSelector,
-    Context& ctx,
-    ExtensionSubsetMap& subsetMap) {
-
-    bool hasExtension = false;
-
-    Complex_Selector* pIter = pComplexSelector;
-
-    while (!hasExtension && pIter) {
-      Compound_Selector* pHead = pIter->head();
-
-      if (pHead) {
-        SubsetMapEntries entries = subsetMap.get_v(pHead->to_str_vec());
-        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.second->media_block() == 0) continue;
-          if (pComplexSelector->media_block() &&
-              ext.second->media_block()->media_queries() &&
-              pComplexSelector->media_block()->media_queries()
-          ) {
-            string query_left(ext.second->media_block()->media_queries()->perform(&to_string));
-            string query_right(pComplexSelector->media_block()->media_queries()->perform(&to_string));
-            if (query_left == query_right) continue;
-          }
-
-          // fail if one goes across media block boundaries
-          stringstream err;
-          string cwd(Sass::File::get_cwd());
-          ParserState pstate(ext.second->pstate());
-          string rel_path(Sass::File::resolve_relative_path(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 << " on line " << pstate.line+1 << " of " << rel_path << "\n";
-          error(err.str(), pComplexSelector->pstate());
-        }
-        if (entries.size() > 0) hasExtension = true;
-      }
-
-      pIter = pIter->tail();
-    }
-
-    if (!hasExtension) {
-      /* ToDo: don't break stuff
-      stringstream err;
-      To_String to_string(&ctx);
-      string cwd(Sass::File::get_cwd());
-      string sel1(pComplexSelector->perform(&to_string));
-      Compound_Selector* pExtendSelector = 0;
-      for (auto i : subsetMap.values()) {
-        if (i.first == pComplexSelector) {
-          pExtendSelector = i.second;
-          break;
-        }
-      }
-      if (!pExtendSelector || !pExtendSelector->is_optional()) {
-        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;
-  }
-
-
-  /*
-   This is the equivalent of ruby's Sequence.do_extend.
-
-   // TODO: I think I have some modified ruby code to put here. Check.
-   */
-  /*
-   ISSUES:
-   - check to automatically include combinators doesn't transfer over to libsass' data model where
-     the combinator and compound selector are one unit
-     next [[sseq_or_op]] unless sseq_or_op.is_a?(SimpleSequence)
-   */
-  static Node extendComplexSelector(
-    Complex_Selector* pComplexSelector,
-    Context& ctx,
-    ExtensionSubsetMap& subsetMap,
-    set<Compound_Selector> seen) {
-
-    pComplexSelector->tail()->has_line_feed(pComplexSelector->has_line_feed());
-
-    Node complexSelector = complexSelectorToNode(pComplexSelector, ctx);
-    DEBUG_PRINTLN(EXTEND_COMPLEX, "EXTEND COMPLEX: " << complexSelector)
-
-    Node extendedNotExpanded = Node::createCollection();
-
-    for (NodeDeque::iterator complexSelIter = complexSelector.collection()->begin(), complexSelIterEnd = complexSelector.collection()->end(); complexSelIter != complexSelIterEnd; ++complexSelIter) {
-      Node& sseqOrOp = *complexSelIter;
-
-      DEBUG_PRINTLN(EXTEND_COMPLEX, "LOOP: " << sseqOrOp)
-
-      // If it's not a selector (meaning it's a combinator), just include it automatically
-      if (!sseqOrOp.isSelector()) {
-        // Wrap our Combinator in two collections to match ruby. This is essentially making a collection Node
-        // with one collection child. The collection child represents a Complex_Selector that is only a combinator.
-        Node outer = Node::createCollection();
-        Node inner = Node::createCollection();
-        outer.collection()->push_back(inner);
-        inner.collection()->push_back(sseqOrOp);
-        extendedNotExpanded.collection()->push_back(outer);
-        continue;
-      }
-
-      Compound_Selector* pCompoundSelector = sseqOrOp.selector()->head();
-
-      Node extended = extendCompoundSelector(pCompoundSelector, ctx, subsetMap, seen);
-
-      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();
-
-      bool isSuperselector = false;
-      for (NodeDeque::iterator iterator = extended.collection()->begin(), endIterator = extended.collection()->end();
-           iterator != endIterator; ++iterator) {
-        Node& childNode = *iterator;
-        Complex_Selector* pExtensionSelector = nodeToComplexSelector(childNode, ctx);
-        if (pExtensionSelector->is_superselector_of(pJustCurrentCompoundSelector)) {
-          isSuperselector = true;
-          break;
-        }
-      }
-
-      if (!isSuperselector) {
-        extended.collection()->push_front(complexSelectorToNode(pJustCurrentCompoundSelector, ctx));
-      }
-
-      DEBUG_PRINTLN(EXTEND_COMPLEX, "CHOICES UNSHIFTED: " << extended)
-
-      // Aggregate our current extensions
-      extendedNotExpanded.collection()->push_back(extended);
-    }
-
-
-    DEBUG_PRINTLN(EXTEND_COMPLEX, "EXTENDED NOT EXPANDED: " << extendedNotExpanded)
-
-
-
-    // Ruby Equivalent: paths
-    Node paths = Sass::paths(extendedNotExpanded, ctx);
-
-    DEBUG_PRINTLN(EXTEND_COMPLEX, "PATHS: " << paths)
-
-
-
-    // Ruby Equivalent: weave
-    Node weaves = Node::createCollection();
-
-    for (NodeDeque::iterator pathsIter = paths.collection()->begin(), pathsEndIter = paths.collection()->end(); pathsIter != pathsEndIter; ++pathsIter) {
-      Node& path = *pathsIter;
-      Node weaved = weave(path, ctx);
-      weaves.collection()->push_back(weaved);
-    }
-
-    DEBUG_PRINTLN(EXTEND_COMPLEX, "WEAVES: " << weaves)
-
-
-
-    // Ruby Equivalent: trim
-    Node trimmed = trim(weaves, ctx);
-
-    DEBUG_PRINTLN(EXTEND_COMPLEX, "TRIMMED: " << trimmed)
-
-
-    // Ruby Equivalent: flatten
-    Node extendedSelectors = flatten(trimmed, ctx, 1);
-
-    DEBUG_PRINTLN(EXTEND_COMPLEX, ">>>>> EXTENDED: " << extendedSelectors)
-
-
-    DEBUG_PRINTLN(EXTEND_COMPLEX, "EXTEND COMPLEX END: " << complexSelector)
-
-
-    return extendedSelectors;
-  }
-
-
-
-  /*
-   This is the equivalent of ruby's CommaSequence.do_extend.
-  */
-  static Selector_List* extendSelectorList(Selector_List* pSelectorList, Context& ctx, ExtensionSubsetMap& subsetMap, bool& extendedSomething) {
-
-    To_String to_string(&ctx);
-
-    Selector_List* pNewSelectors = new (ctx.mem) Selector_List(pSelectorList->pstate(), pSelectorList->length());
-
-    extendedSomething = false;
-
-    for (size_t index = 0, length = pSelectorList->length(); index < length; index++) {
-      Complex_Selector* 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, subsetMap)) {
-        *pNewSelectors << pSelector;
-        continue;
-      }
-
-      extendedSomething = true;
-
-      set<Compound_Selector> seen;
-      Node extendedSelectors = extendComplexSelector(pSelector, ctx, subsetMap, seen);
-
-      if (!pSelector->has_placeholder()) {
-        if (!extendedSelectors.contains(complexSelectorToNode(pSelector, ctx), true /*simpleSelectorOrderDependent*/)) {
-          *pNewSelectors << pSelector;
-        }
-      }
-
-      for (NodeDeque::iterator iterator = extendedSelectors.collection()->begin(), iteratorEnd = extendedSelectors.collection()->end(); iterator != iteratorEnd; ++iterator) {
-        Node& childNode = *iterator;
-        *pNewSelectors << nodeToComplexSelector(childNode, ctx);
-      }
-    }
-
-    return pNewSelectors;
-
-  }
-
-
-  bool shouldExtendBlock(Block* 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:
-    //
-    //    .a {
-    //      .b {
-    //        x: y;
-    //      }
-    //    }
-    //
-    // We end up visiting two rulesets (one with the selector .a and the other with the selector .a .b).
-    // In this case, we don't want to try to pull rules onto .a since they won't get output anyway since
-    // 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];
-
-      if (typeid(*stm) == typeid(Ruleset)) {
-        // Do nothing. This doesn't count as a statement that causes extension since we'll iterate over this rule set in a future visit and try to extend it.
-      }
-      else {
-        return true;
-      }
-    }
-
-    return false;
-
-  }
-
-
-  // Extend a ruleset by extending the selectors and updating them on the ruleset. The block's rules don't need to change.
-  template <typename ObjectType>
-  static void extendObjectWithSelectorAndBlock(ObjectType* pObject, Context& ctx, ExtensionSubsetMap& subsetMap) {
-    To_String to_string(&ctx);
-
-    DEBUG_PRINTLN(EXTEND_OBJECT, "FOUND SELECTOR: " << static_cast<Selector_List*>(pObject->selector())->perform(&to_string))
-
-    // Ruby sass seems to filter nodes that don't have any content well before we get here. I'm not sure the repercussions
-    // of doing so, so for now, let's just not extend things that won't be output later.
-    if (!shouldExtendBlock(pObject->block())) {
-      DEBUG_PRINTLN(EXTEND_OBJECT, "RETURNING WITHOUT EXTEND ATTEMPT")
-      return;
-    }
-
-    bool extendedSomething = false;
-    Selector_List* pNewSelectorList = extendSelectorList(static_cast<Selector_List*>(pObject->selector()), ctx, subsetMap, 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))
-
-      // re-parse in order to restructure expanded placeholder nodes correctly.
-      //
-      // TODO: I don't know if this is needed, but it was in the original C++ implementation, so I kept it. Try running the tests without re-parsing.
-      // this probably messes up source-maps
-      pObject->selector(
-        Parser::from_c_str(
-          (pNewSelectorList->perform(&to_string) + ";").c_str(),
-          ctx,
-          pNewSelectorList->pstate()
-        ).parse_selector_group()
-      );
-    } else {
-      DEBUG_PRINTLN(EXTEND_OBJECT, "EXTEND DID NOT TRY TO EXTEND ANYTHING")
-    }
-  }
-
-
-
-  Extend::Extend(Context& ctx, ExtensionSubsetMap& ssm)
-  : ctx(ctx), subset_map(ssm)
-  { }
-
-  void Extend::operator()(Block* b)
-  {
-    for (size_t i = 0, L = b->length(); i < L; ++i) {
-      (*b)[i]->perform(this);
-    }
-  }
-
-  void Extend::operator()(Ruleset* pRuleset)
-  {
-    extendObjectWithSelectorAndBlock(pRuleset, ctx, subset_map);
-
-    pRuleset->block()->perform(this);
-  }
-
-  void Extend::operator()(Feature_Block* pFeatureBlock)
-  {
-    if (pFeatureBlock->selector()) {
-      extendObjectWithSelectorAndBlock(pFeatureBlock, ctx, subset_map);
-    }
-
-    pFeatureBlock->block()->perform(this);
-  }
-
-  void Extend::operator()(Media_Block* pMediaBlock)
-  {
-    if (pMediaBlock->selector()) {
-      extendObjectWithSelectorAndBlock(pMediaBlock, ctx, subset_map);
-    }
-
-    pMediaBlock->block()->perform(this);
-  }
-
-  void Extend::operator()(At_Rule* a)
-  {
-    if (a->block()) a->block()->perform(this);
-  }
-}
diff --git a/libsass/extend.hpp b/libsass/extend.hpp
deleted file mode 100644
--- a/libsass/extend.hpp
+++ /dev/null
@@ -1,45 +0,0 @@
-#ifndef SASS_EXTEND_H
-#define SASS_EXTEND_H
-
-#include <map>
-#include <set>
-#include <vector>
-#include <iostream>
-
-#include "ast.hpp"
-#include "operation.hpp"
-#include "subset_map.hpp"
-
-namespace Sass {
-  using namespace std;
-
-  class Context;
-
-  typedef Subset_Map<string, pair<Complex_Selector*, Compound_Selector*> > ExtensionSubsetMap;
-
-  class Extend : public Operation_CRTP<void, Extend> {
-
-    Context&            ctx;
-    ExtensionSubsetMap& subset_map;
-
-    void fallback_impl(AST_Node* n) { };
-
-  public:
-    Extend(Context&, ExtensionSubsetMap&);
-    virtual ~Extend() { }
-
-    using Operation<void>::operator();
-
-    void operator()(Block*);
-    void operator()(Ruleset*);
-    void operator()(Feature_Block*);
-    void operator()(Media_Block*);
-    void operator()(At_Rule*);
-
-    template <typename U>
-    void fallback(U x) { return fallback_impl(x); }
-  };
-
-}
-
-#endif
diff --git a/libsass/file.cpp b/libsass/file.cpp
deleted file mode 100644
--- a/libsass/file.cpp
+++ /dev/null
@@ -1,349 +0,0 @@
-#ifdef _WIN32
-#include <direct.h>
-#define getcwd _getcwd
-#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
-#else
-#include <unistd.h>
-#endif
-
-#include <iostream>
-#include <fstream>
-#include <cctype>
-#include <vector>
-#include <algorithm>
-#include <sys/stat.h>
-#include "file.hpp"
-#include "context.hpp"
-#include "utf8_string.hpp"
-#include "sass2scss.h"
-
-#ifdef _WIN32
-#include <windows.h>
-#endif
-
-#ifndef FS_CASE_SENSITIVE
-#ifdef _WIN32
-#define FS_CASE_SENSITIVE 0
-#else
-#define FS_CASE_SENSITIVE 1
-#endif
-#endif
-
-namespace Sass {
-  namespace File {
-    using namespace std;
-
-    // return the current directory
-    // always with forward slashes
-    string get_cwd()
-    {
-      const size_t wd_len = 1024;
-      char wd[wd_len];
-      string cwd = getcwd(wd, wd_len);
-      #ifdef _WIN32
-        //convert backslashes to forward slashes
-        replace(cwd.begin(), cwd.end(), '\\', '/');
-      #endif
-      if (cwd[cwd.length() - 1] != '/') cwd += '/';
-      return cwd;
-    }
-
-    // test if path exists and is a file
-    bool file_exists(const string& path)
-    {
-      #ifdef _WIN32
-        wstring wpath = UTF_8::convert_to_utf16(path);
-        DWORD dwAttrib = GetFileAttributesW(wpath.c_str());
-        return (dwAttrib != INVALID_FILE_ATTRIBUTES &&
-               (!(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)));
-      #else
-        struct stat st_buf;
-        return (stat (path.c_str(), &st_buf) == 0) &&
-               (!S_ISDIR (st_buf.st_mode));
-      #endif
-    }
-
-    // return if given path is absolute
-    // works with *nix and windows paths
-    bool is_absolute_path(const string& path)
-    {
-      #ifdef _WIN32
-        if (path.length() >= 2 && isalpha(path[0]) && path[1] == ':') return true;
-      #endif
-      return path[0] == '/';
-    }
-
-    // helper function to find the last directory seperator
-    inline size_t find_last_folder_separator(const string& path, size_t limit = string::npos)
-    {
-      size_t pos = string::npos;
-      size_t pos_p = path.find_last_of('/', limit);
-      #ifdef _WIN32
-        size_t pos_w = path.find_last_of('\\', limit);
-      #else
-        size_t pos_w = string::npos;
-      #endif
-      if (pos_p != string::npos && pos_w != string::npos) {
-        pos = max(pos_p, pos_w);
-      }
-      else if (pos_p != string::npos) {
-        pos = pos_p;
-      }
-      else {
-        pos = pos_w;
-      }
-      return pos;
-    }
-
-    // return only the directory part of path
-    string dir_name(const string& path)
-    {
-      size_t pos = find_last_folder_separator(path);
-      if (pos == string::npos) return "";
-      else return path.substr(0, pos+1);
-    }
-
-    // return only the filename part of path
-    string base_name(const string& path)
-    {
-      size_t pos = find_last_folder_separator(path);
-      if (pos == string::npos) return path;
-      else return path.substr(pos+1);
-    }
-
-    // do a locigal clean up of the path
-    // no physical check on the filesystem
-    string make_canonical_path (string path)
-    {
-
-      // declarations
-      size_t pos;
-
-      #ifdef _WIN32
-        //convert backslashes to forward slashes
-        replace(path.begin(), path.end(), '\\', '/');
-      #endif
-
-      pos = 0; // remove all self references inside the path string
-      while((pos = path.find("/./", pos)) != string::npos) path.erase(pos, 2);
-
-      pos = 0; // remove all leading and trailing self references
-      while(path.length() > 1 && path.substr(0, 2) == "./") path.erase(0, 2);
-      while((pos = path.length()) > 1 && path.substr(pos - 2) == "/.") path.erase(pos - 2);
-
-      pos = 0; // collapse multiple delimiters into a single one
-      while((pos = path.find("//", pos)) != string::npos) path.erase(pos, 1);
-
-      return path;
-
-    }
-
-    // join two path segments cleanly together
-    // but only if right side is not absolute yet
-    string join_paths(string l, string r)
-    {
-
-      #ifdef _WIN32
-        // convert Windows backslashes to URL forward slashes
-        replace(l.begin(), l.end(), '\\', '/');
-        replace(r.begin(), r.end(), '\\', '/');
-      #endif
-
-      if (l.empty()) return r;
-      if (r.empty()) return l;
-
-      if (is_absolute_path(r)) return r;
-      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);
-        l = l.substr(0, pos == string::npos ? pos : pos + 1);
-      }
-
-      return l + r;
-    }
-
-    // create an absolute path by resolving relative paths with cwd
-    string make_absolute_path(const string& path, const string& cwd)
-    {
-      return make_canonical_path((is_absolute_path(path) ? path : join_paths(cwd, path)));
-    }
-
-    // create a path that is relative to the given base directory
-    // path and base will first be resolved against cwd to make them absolute
-    string resolve_relative_path(const string& uri, const string& base, const string& cwd)
-    {
-
-      string absolute_uri = make_absolute_path(uri, cwd);
-      string absolute_base = make_absolute_path(base, cwd);
-
-      #ifdef _WIN32
-        // absolute link must have a drive letter, and we know that we
-        // can only create relative links if both are on the same drive
-        if (absolute_base[0] != absolute_uri[0]) return absolute_uri;
-      #endif
-
-      string stripped_uri = "";
-      string stripped_base = "";
-
-      size_t index = 0;
-      size_t minSize = min(absolute_uri.size(), absolute_base.size());
-      for (size_t i = 0; i < minSize; ++i) {
-        #ifdef FS_CASE_SENSITIVE
-          if (absolute_uri[i] != absolute_base[i]) break;
-        #else
-          // compare the charactes in a case insensitive manner
-          // windows fs is only case insensitive in ascii ranges
-          if (tolower(absolute_uri[i]) != tolower(absolute_base[i])) break;
-        #endif
-        if (absolute_uri[i] == '/') index = i + 1;
-      }
-      for (size_t i = index; i < absolute_uri.size(); ++i) {
-        stripped_uri += absolute_uri[i];
-      }
-      for (size_t i = index; i < absolute_base.size(); ++i) {
-        stripped_base += absolute_base[i];
-      }
-
-      size_t left = 0;
-      size_t directories = 0;
-      for (size_t right = 0; right < stripped_base.size(); ++right) {
-        if (stripped_base[right] == '/') {
-          if (stripped_base.substr(left, 2) != "..") {
-            ++directories;
-          }
-          else if (directories > 1) {
-            --directories;
-          }
-          else {
-            directories = 0;
-          }
-          left = right + 1;
-        }
-      }
-
-      string result = "";
-      for (size_t i = 0; i < directories; ++i) {
-        result += "../";
-      }
-      result += stripped_uri;
-
-      return result;
-    }
-
-    // Resolution order for ambiguous imports:
-    // (1) filename as given
-    // (2) underscore + given
-    // (3) underscore + given + extension
-    // (4) given + extension
-    string resolve_file(const string& filename)
-    {
-      // supported extensions
-      const vector<string> exts = {
-        ".scss", ".sass", ".css"
-      };
-      // split the filename
-      string base(dir_name(filename));
-      string name(base_name(filename));
-      // create full path (maybe relative)
-      string path(join_paths(base, name));
-      if (file_exists(path)) return path;
-      // next test variation with underscore
-      path = join_paths(base, "_" + name);
-      if (file_exists(path)) return path;
-      // next test exts plus underscore
-      for(auto ext : exts) {
-        path = join_paths(base, "_" + name + ext);
-        if (file_exists(path)) return path;
-      }
-      // next test plain name with exts
-      for(auto ext : exts) {
-        path = join_paths(base, name + ext);
-        if (file_exists(path)) return path;
-      }
-      // nothing found
-      return string("");
-    }
-
-    // helper function to resolve a filename
-    string find_file(const string& file, const vector<string> paths)
-    {
-      // search in every include path for a match
-      for (size_t i = 0, S = paths.size(); i < S; ++i)
-      {
-        string path(join_paths(paths[i], file));
-        string resolved(resolve_file(path));
-        if (resolved != "") return resolved;
-      }
-      // nothing found
-      return string("");
-    }
-
-    // inc paths can be directly passed from C code
-    string find_file(const string& file, const char* paths[])
-    {
-      if (paths == 0) return string("");
-      vector<string> includes(0);
-      // includes.push_back(".");
-      const char** it = paths;
-      while (it && *it) {
-        includes.push_back(*it);
-        ++it;
-      }
-      return find_file(file, includes);
-    }
-
-    // try to load the given filename
-    // returned memory must be freed
-    // will auto convert .sass files
-    char* read_file(const string& path)
-    {
-      #ifdef _WIN32
-        BYTE* pBuffer;
-        DWORD dwBytes;
-        // windows unicode filepaths are encoded in utf16
-        wstring wpath = UTF_8::convert_to_utf16(path);
-        HANDLE hFile = CreateFileW(wpath.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
-        if (hFile == INVALID_HANDLE_VALUE) return 0;
-        DWORD dwFileLength = GetFileSize(hFile, NULL);
-        if (dwFileLength == INVALID_FILE_SIZE) return 0;
-        // allocate an extra byte for the null char
-        pBuffer = (BYTE*)malloc((dwFileLength+1)*sizeof(BYTE));
-        ReadFile(hFile, pBuffer, dwFileLength, &dwBytes, NULL);
-        pBuffer[dwFileLength] = '\0';
-        CloseHandle(hFile);
-        // just convert from unsigned char*
-        char* contents = (char*) pBuffer;
-      #else
-        struct stat st;
-        if (stat(path.c_str(), &st) == -1 || S_ISDIR(st.st_mode)) return 0;
-        ifstream file(path.c_str(), ios::in | ios::binary | ios::ate);
-        char* contents = 0;
-        if (file.is_open()) {
-          size_t size = file.tellg();
-          // allocate an extra byte for the null char
-          contents = (char*) malloc((size+1)*sizeof(char));
-          file.seekg(0, ios::beg);
-          file.read(contents, size);
-          contents[size] = '\0';
-          file.close();
-        }
-      #endif
-      string extension;
-      if (path.length() > 5) {
-        extension = path.substr(path.length() - 5, 5);
-      }
-      for(size_t i=0; i<extension.size();++i)
-        extension[i] = tolower(extension[i]);
-      if (extension == ".sass" && contents != 0) {
-        char * converted = sass2scss(contents, SASS2SCSS_PRETTIFY_1 | SASS2SCSS_KEEP_COMMENT);
-        free(contents); // free the indented contents
-        return converted; // should be freed by caller
-      } else {
-        return contents;
-      }
-    }
-
-  }
-}
diff --git a/libsass/file.hpp b/libsass/file.hpp
deleted file mode 100644
--- a/libsass/file.hpp
+++ /dev/null
@@ -1,60 +0,0 @@
-#ifndef SASS_FILE_H
-#define SASS_FILE_H
-
-#include <string>
-#include <vector>
-
-namespace Sass {
-  using namespace std;
-  class Context;
-  namespace File {
-
-    // return the current directory
-    // always with forward slashes
-    string get_cwd();
-
-    // test if path exists and is a file
-    bool file_exists(const string& file);
-
-    // return if given path is absolute
-    // works with *nix and windows paths
-    bool is_absolute_path(const string& path);
-
-    // return only the directory part of path
-    string dir_name(const string& path);
-
-    // return only the filename part of path
-    string base_name(const string&);
-
-    // do a locigal clean up of the path
-    // no physical check on the filesystem
-    string make_canonical_path (string path);
-
-    // join two path segments cleanly together
-    // but only if right side is not absolute yet
-    string join_paths(string root, string name);
-
-    // create an absolute path by resolving relative paths with cwd
-    string make_absolute_path(const string& path, const string& cwd = ".");
-
-    // create a path that is relative to the given base directory
-    // path and base will first be resolved against cwd to make them absolute
-    string resolve_relative_path(const string& path, const string& base, const string& cwd = ".");
-
-    // try to find/resolve the filename
-    string resolve_file(const string& file);
-
-    // helper function to resolve a filename
-    string find_file(const string& file, const vector<string> paths);
-    // inc paths can be directly passed from C code
-    string find_file(const string& file, const char** paths);
-
-    // try to load the given filename
-    // returned memory must be freed
-    // will auto convert .sass files
-    char* read_file(const string& file);
-
-  }
-}
-
-#endif
diff --git a/libsass/functions.cpp b/libsass/functions.cpp
deleted file mode 100644
--- a/libsass/functions.cpp
+++ /dev/null
@@ -1,1592 +0,0 @@
-#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 "eval.hpp"
-#include "util.hpp"
-#include "utf8_string.hpp"
-#include "utf8.h"
-
-#include <atomic>
-#include <cstdlib>
-#include <cmath>
-#include <cctype>
-#include <sstream>
-#include <string>
-#include <iomanip>
-#include <iostream>
-#include <random>
-#include <set>
-
-#ifdef __MINGW32__
-#include "windows.h"
-#include "wincrypt.h"
-#endif
-
-#define ARG(argname, argtype) get_arg<argtype>(argname, env, sig, pstate, backtrace)
-#define ARGR(argname, argtype, lo, hi) get_arg_r(argname, env, sig, pstate, lo, hi, backtrace)
-#define ARGM(argname, argtype, ctx) get_arg_m(argname, env, sig, pstate, backtrace, ctx)
-
-namespace Sass {
-  using std::stringstream;
-  using std::endl;
-
-  Definition* 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>();
-    string name(Util::normalize_underscores(sig_parser.lexed));
-    Parameters* params = sig_parser.parse_parameters();
-    return new (ctx.mem) Definition(ParserState("[built-in function]"),
-                                    sig,
-                                    name,
-                                    params,
-                                    func,
-                                    &ctx,
-                                    false);
-  }
-
-  Definition* make_c_function(Sass_Function_Entry c_func, Context& ctx)
-  {
-    const char* sig = sass_function_get_signature(c_func);
-    Parser sig_parser = Parser::from_c_str(sig, ctx, ParserState("[c function]"));
-    // allow to overload generic callback plus @warn, @error and @debug with custom functions
-    sig_parser.lex < alternatives < identifier, exactly <'*'>,
-                                    exactly < Constants::warn_kwd >,
-                                    exactly < Constants::error_kwd >,
-                                    exactly < Constants::debug_kwd >
-                   >              >();
-    string name(Util::normalize_underscores(sig_parser.lexed));
-    Parameters* params = sig_parser.parse_parameters();
-    return new (ctx.mem) Definition(ParserState("[c function]"),
-                                    sig,
-                                    name,
-                                    params,
-                                    c_func,
-                                    &ctx,
-                                    false, true);
-  }
-
-  namespace Functions {
-
-    template <typename T>
-    T* get_arg(const 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]);
-      if (!val) {
-        string msg("argument `");
-        msg += argname;
-        msg += "` of `";
-        msg += sig;
-        msg += "` must be a ";
-        msg += T::type_name();
-        error(msg, pstate, backtrace);
-      }
-      return val;
-    }
-
-    Map* get_arg_m(const 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]);
-      if (val) return val;
-
-      List* lval = dynamic_cast<List*>(env[argname]);
-      if (lval && lval->length() == 0) return new (ctx.mem) 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 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);
-      double v = val->value();
-      if (!(lo <= v && v <= hi)) {
-        stringstream msg;
-        msg << "argument `" << argname << "` of `" << sig << "` must be between ";
-        msg << lo << " and " << hi;
-        error(msg.str(), pstate, backtrace);
-      }
-      return val;
-    }
-
-#ifdef __MINGW32__
-    uint64_t GetSeed()
-    {
-      HCRYPTPROV hp = 0;
-      BYTE rb[8];
-      CryptAcquireContext(&hp, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
-      CryptGenRandom(hp, sizeof(rb), rb);
-      CryptReleaseContext(hp, 0);
-
-      uint64_t seed;
-      memcpy(&seed, &rb[0], sizeof(seed));
-
-      return seed;
-    }
-#else
-    static random_device rd;
-    uint64_t GetSeed()
-    {
-	  return rd();
-	}
-#endif
-
-    // note: the performance of many  implementations of
-    // random_device degrades sharply once the entropy pool
-    // is exhausted. For practical use, random_device is
-    // generally only used to seed a PRNG such as mt19937.
-    static mt19937 rand(static_cast<unsigned int>(GetSeed()));
-
-    // features
-    static set<string> features {
-      "global-variable-shadowing",
-      "at-error",
-      "units-level-3"
-    };
-
-    ////////////////
-    // RGB FUNCTIONS
-    ////////////////
-
-    inline double color_num(Number* n) {
-      if (n->unit() == "%") {
-        return std::min(std::max(n->value(), 0.0), 1.0) * 255;
-      } else {
-        return std::min(std::max(n->value(), 0.0), 255.0);
-      }
-    }
-
-    Signature rgb_sig = "rgb($red, $green, $blue)";
-    BUILT_IN(rgb)
-    {
-      return new (ctx.mem) Color(pstate,
-                                 color_num(ARGR("$red",   Number, 0, 255)),
-                                 color_num(ARGR("$green", Number, 0, 255)),
-                                 color_num(ARGR("$blue",  Number, 0, 255)));
-    }
-
-    Signature rgba_4_sig = "rgba($red, $green, $blue, $alpha)";
-    BUILT_IN(rgba_4)
-    {
-      return new (ctx.mem) Color(pstate,
-                                 color_num(ARGR("$red",   Number, 0, 255)),
-                                 color_num(ARGR("$green", Number, 0, 255)),
-                                 color_num(ARGR("$blue",  Number, 0, 255)),
-                                 ARGR("$alpha", Number, 0, 1)->value());
-    }
-
-    Signature rgba_2_sig = "rgba($color, $alpha)";
-    BUILT_IN(rgba_2)
-    {
-      Color* c_arg = ARG("$color", Color);
-      Color* new_c = new (ctx.mem) Color(*c_arg);
-      new_c->a(ARGR("$alpha", Number, 0, 1)->value());
-      new_c->disp("");
-      return new_c;
-    }
-
-    Signature red_sig = "red($color)";
-    BUILT_IN(red)
-    { return new (ctx.mem) Number(pstate, ARG("$color", Color)->r()); }
-
-    Signature green_sig = "green($color)";
-    BUILT_IN(green)
-    { return new (ctx.mem) Number(pstate, ARG("$color", Color)->g()); }
-
-    Signature blue_sig = "blue($color)";
-    BUILT_IN(blue)
-    { return new (ctx.mem) 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);
-
-      double p = weight->value()/100;
-      double w = 2*p - 1;
-      double a = color1->a() - color2->a();
-
-      double w1 = (((w * a == -1) ? w : (w + a)/(1 + w*a)) + 1)/2.0;
-      double w2 = 1 - w1;
-
-      return new (ctx.mem) Color(pstate,
-                                 std::round(w1*color1->r() + w2*color2->r()),
-                                 std::round(w1*color1->g() + w2*color2->g()),
-                                 std::round(w1*color1->b() + w2*color2->b()),
-                                 color1->a()*p + color2->a()*(1-p));
-    }
-
-    ////////////////
-    // HSL FUNCTIONS
-    ////////////////
-
-    // RGB to HSL helper function
-    struct HSL { double h; double s; double l; };
-    HSL rgb_to_hsl(double r, double g, double b)
-    {
-
-      // Algorithm from http://en.wikipedia.org/wiki/wHSL_and_HSV#Conversion_from_RGB_to_HSL_or_HSV
-      r /= 255.0; g /= 255.0; b /= 255.0;
-
-      double max = std::max(r, std::max(g, b));
-      double min = std::min(r, std::min(g, b));
-      double del = max - min;
-
-      double h = 0, s = 0, l = (max + min) / 2.0;
-
-      if (max == min) {
-        h = s = 0; // achromatic
-      }
-      else {
-        if (l < 0.5) s = del / (max + min);
-        else         s = del / (2.0 - max - min);
-
-        if      (r == max) h = (g - b) / del + (g < b ? 6 : 0);
-        else if (g == max) h = (b - r) / del + 2;
-        else if (b == max) h = (r - g) / del + 4;
-      }
-
-      HSL hsl_struct;
-      hsl_struct.h = h / 6 * 360;
-      hsl_struct.s = s * 100;
-      hsl_struct.l = l * 100;
-
-      return hsl_struct;
-    }
-
-    // hue to RGB helper function
-    double h_to_rgb(double m1, double m2, double h) {
-      if (h < 0) h += 1;
-      if (h > 1) h -= 1;
-      if (h*6.0 < 1) return m1 + (m2 - m1)*h*6;
-      if (h*2.0 < 1) return m2;
-      if (h*3.0 < 2) return m1 + (m2 - m1) * (2.0/3.0 - h)*6;
-      return m1;
-    }
-
-    Color* hsla_impl(double h, double s, double l, double a, Context& ctx, ParserState pstate)
-    {
-      h /= 360.0;
-      s /= 100.0;
-      l /= 100.0;
-
-      if (l < 0) l = 0;
-      if (s < 0) s = 0;
-      if (l > 1) l = 1;
-      if (s > 1) s = 1;
-      while (h < 0) h += 1;
-      while (h > 1) h -= 1;
-
-      // Algorithm from the CSS3 spec: http://www.w3.org/TR/css3-color/#hsl-color.
-      double m2;
-      if (l <= 0.5) m2 = l*(s+1.0);
-      else m2 = (l+s)-(l*s);
-      double m1 = (l*2.0)-m2;
-      // round the results -- consider moving this into the Color constructor
-      double r = (h_to_rgb(m1, m2, h+1.0/3.0) * 255.0);
-      double g = (h_to_rgb(m1, m2, h) * 255.0);
-      double b = (h_to_rgb(m1, m2, h-1.0/3.0) * 255.0);
-
-      return new (ctx.mem) Color(pstate, r, g, b, a);
-    }
-
-    Signature hsl_sig = "hsl($hue, $saturation, $lightness)";
-    BUILT_IN(hsl)
-    {
-      return hsla_impl(ARG("$hue", Number)->value(),
-                       ARGR("$saturation", Number, 0, 100)->value(),
-                       ARGR("$lightness", Number, 0, 100)->value(),
-                       1.0,
-                       ctx,
-                       pstate);
-    }
-
-    Signature hsla_sig = "hsla($hue, $saturation, $lightness, $alpha)";
-    BUILT_IN(hsla)
-    {
-      return hsla_impl(ARG("$hue", Number)->value(),
-                       ARGR("$saturation", Number, 0, 100)->value(),
-                       ARGR("$lightness", Number, 0, 100)->value(),
-                       ARGR("$alpha", Number, 0, 1)->value(),
-                       ctx,
-                       pstate);
-    }
-
-    Signature hue_sig = "hue($color)";
-    BUILT_IN(hue)
-    {
-      Color* rgb_color = ARG("$color", Color);
-      HSL hsl_color = rgb_to_hsl(rgb_color->r(),
-                                 rgb_color->g(),
-                                 rgb_color->b());
-      return new (ctx.mem) Number(pstate, hsl_color.h, "deg");
-    }
-
-    Signature saturation_sig = "saturation($color)";
-    BUILT_IN(saturation)
-    {
-      Color* rgb_color = ARG("$color", Color);
-      HSL hsl_color = rgb_to_hsl(rgb_color->r(),
-                                 rgb_color->g(),
-                                 rgb_color->b());
-      return new (ctx.mem) Number(pstate, hsl_color.s, "%");
-    }
-
-    Signature lightness_sig = "lightness($color)";
-    BUILT_IN(lightness)
-    {
-      Color* rgb_color = ARG("$color", Color);
-      HSL hsl_color = rgb_to_hsl(rgb_color->r(),
-                                 rgb_color->g(),
-                                 rgb_color->b());
-      return new (ctx.mem) 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);
-      HSL hsl_color = rgb_to_hsl(rgb_color->r(),
-                                 rgb_color->g(),
-                                 rgb_color->b());
-      return hsla_impl(hsl_color.h + degrees->value(),
-                       hsl_color.s,
-                       hsl_color.l,
-                       rgb_color->a(),
-                       ctx,
-                       pstate);
-    }
-
-    Signature lighten_sig = "lighten($color, $amount)";
-    BUILT_IN(lighten)
-    {
-      Color* rgb_color = ARG("$color", Color);
-      Number* amount = ARGR("$amount", Number, 0, 100);
-      HSL hsl_color = rgb_to_hsl(rgb_color->r(),
-                                 rgb_color->g(),
-                                 rgb_color->b());
-      //Check lightness is not negative before lighten it
-      double hslcolorL = hsl_color.l;
-      if (hslcolorL < 0) {
-        hslcolorL = 0;
-      }
-
-      return hsla_impl(hsl_color.h,
-                       hsl_color.s,
-                       hslcolorL + amount->value(),
-                       rgb_color->a(),
-                       ctx,
-                       pstate);
-    }
-
-    Signature darken_sig = "darken($color, $amount)";
-    BUILT_IN(darken)
-    {
-      Color* rgb_color = ARG("$color", Color);
-      Number* amount = ARGR("$amount", Number, 0, 100);
-      HSL hsl_color = rgb_to_hsl(rgb_color->r(),
-                                 rgb_color->g(),
-                                 rgb_color->b());
-
-      //Check lightness if not over 100, before darken it
-      double hslcolorL = hsl_color.l;
-      if (hslcolorL > 100) {
-        hslcolorL = 100;
-      }
-
-      return hsla_impl(hsl_color.h,
-                       hsl_color.s,
-                       hslcolorL - amount->value(),
-                       rgb_color->a(),
-                       ctx,
-                       pstate);
-    }
-
-    Signature saturate_sig = "saturate($color, $amount: false)";
-    BUILT_IN(saturate)
-    {
-      // CSS3 filter function overload: pass literal through directly
-      Number* amount = dynamic_cast<Number*>(env["$amount"]);
-      if (!amount) {
-        To_String to_string(&ctx);
-        return new (ctx.mem) String_Constant(pstate, "saturate(" + env["$color"]->perform(&to_string) + ")");
-      }
-
-      ARGR("$amount", Number, 0, 100);
-      Color* rgb_color = ARG("$color", Color);
-      HSL hsl_color = rgb_to_hsl(rgb_color->r(),
-                                 rgb_color->g(),
-                                 rgb_color->b());
-
-      double hslcolorS = hsl_color.s + amount->value();
-
-      // Saturation cannot be below 0 or above 100
-      if (hslcolorS < 0) {
-        hslcolorS = 0;
-      }
-      if (hslcolorS > 100) {
-        hslcolorS = 100;
-      }
-
-      return hsla_impl(hsl_color.h,
-                       hslcolorS,
-                       hsl_color.l,
-                       rgb_color->a(),
-                       ctx,
-                       pstate);
-    }
-
-    Signature desaturate_sig = "desaturate($color, $amount)";
-    BUILT_IN(desaturate)
-    {
-      Color* rgb_color = ARG("$color", Color);
-      Number* amount = ARGR("$amount", Number, 0, 100);
-      HSL hsl_color = rgb_to_hsl(rgb_color->r(),
-                                 rgb_color->g(),
-                                 rgb_color->b());
-
-      double hslcolorS = hsl_color.s - amount->value();
-
-      // Saturation cannot be below 0 or above 100
-      if (hslcolorS <= 0) {
-        hslcolorS = 0;
-      }
-      if (hslcolorS > 100) {
-        hslcolorS = 100;
-      }
-
-      return hsla_impl(hsl_color.h,
-                       hslcolorS,
-                       hsl_color.l,
-                       rgb_color->a(),
-                       ctx,
-                       pstate);
-    }
-
-    Signature grayscale_sig = "grayscale($color)";
-    BUILT_IN(grayscale)
-    {
-      // CSS3 filter function overload: pass literal through directly
-      Number* amount = dynamic_cast<Number*>(env["$color"]);
-      if (amount) {
-        To_String to_string(&ctx);
-        return new (ctx.mem) String_Constant(pstate, "grayscale(" + amount->perform(&to_string) + ")");
-      }
-
-      Color* rgb_color = ARG("$color", Color);
-      HSL hsl_color = rgb_to_hsl(rgb_color->r(),
-                                 rgb_color->g(),
-                                 rgb_color->b());
-      return hsla_impl(hsl_color.h,
-                       0.0,
-                       hsl_color.l,
-                       rgb_color->a(),
-                       ctx,
-                       pstate);
-    }
-
-    Signature complement_sig = "complement($color)";
-    BUILT_IN(complement)
-    {
-      Color* rgb_color = ARG("$color", Color);
-      HSL hsl_color = rgb_to_hsl(rgb_color->r(),
-                                 rgb_color->g(),
-                                 rgb_color->b());
-      return hsla_impl(hsl_color.h - 180.0,
-                       hsl_color.s,
-                       hsl_color.l,
-                       rgb_color->a(),
-                       ctx,
-                       pstate);
-    }
-
-    Signature invert_sig = "invert($color)";
-    BUILT_IN(invert)
-    {
-      // CSS3 filter function overload: pass literal through directly
-      Number* amount = dynamic_cast<Number*>(env["$color"]);
-      if (amount) {
-        To_String to_string(&ctx);
-        return new (ctx.mem) String_Constant(pstate, "invert(" + amount->perform(&to_string) + ")");
-      }
-
-      Color* rgb_color = ARG("$color", Color);
-      return new (ctx.mem) Color(pstate,
-                                 255 - rgb_color->r(),
-                                 255 - rgb_color->g(),
-                                 255 - rgb_color->b(),
-                                 rgb_color->a());
-    }
-
-    ////////////////////
-    // OPACITY FUNCTIONS
-    ////////////////////
-    Signature alpha_sig = "alpha($color)";
-    Signature opacity_sig = "opacity($color)";
-    BUILT_IN(alpha)
-    {
-      String_Constant* ie_kwd = dynamic_cast<String_Constant*>(env["$color"]);
-      if (ie_kwd) {
-        return new (ctx.mem) String_Constant(pstate, "alpha(" + ie_kwd->value() + ")");
-      }
-
-      // CSS3 filter function overload: pass literal through directly
-      Number* amount = dynamic_cast<Number*>(env["$color"]);
-      if (amount) {
-        To_String to_string(&ctx);
-        return new (ctx.mem) String_Constant(pstate, "opacity(" + amount->perform(&to_string) + ")");
-      }
-
-      return new (ctx.mem) 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);
-      double amount = ARGR("$amount", Number, 0, 1)->value();
-      double alpha = std::min(color->a() + amount, 1.0);
-      return new (ctx.mem) Color(pstate,
-                                 color->r(),
-                                 color->g(),
-                                 color->b(),
-                                 alpha);
-    }
-
-    Signature transparentize_sig = "transparentize($color, $amount)";
-    Signature fade_out_sig = "fade-out($color, $amount)";
-    BUILT_IN(transparentize)
-    {
-      Color* color = ARG("$color", Color);
-      double amount = ARGR("$amount", Number, 0, 1)->value();
-      double alpha = std::max(color->a() - amount, 0.0);
-      return new (ctx.mem) Color(pstate,
-                                 color->r(),
-                                 color->g(),
-                                 color->b(),
-                                 alpha);
-    }
-
-    ////////////////////////
-    // OTHER COLOR FUNCTIONS
-    ////////////////////////
-
-    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"]);
-
-      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);
-      }
-      if (rgb) {
-        return new (ctx.mem) Color(pstate,
-                                   color->r() + (r ? r->value() : 0),
-                                   color->g() + (g ? g->value() : 0),
-                                   color->b() + (b ? b->value() : 0),
-                                   color->a() + (a ? a->value() : 0));
-      }
-      if (hsl) {
-        HSL hsl_struct = rgb_to_hsl(color->r(), color->g(), color->b());
-        return hsla_impl(hsl_struct.h + (h ? h->value() : 0),
-                         hsl_struct.s + (s ? s->value() : 0),
-                         hsl_struct.l + (l ? l->value() : 0),
-                         color->a() + (a ? a->value() : 0),
-                         ctx,
-                         pstate);
-      }
-      if (a) {
-        return new (ctx.mem) Color(pstate,
-                                   color->r(),
-                                   color->g(),
-                                   color->b(),
-                                   color->a() + (a ? a->value() : 0));
-      }
-      error("not enough arguments for `adjust-color`", pstate);
-      // unreachable
-      return color;
-    }
-
-    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"]);
-
-      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);
-      }
-      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 new (ctx.mem) Color(pstate,
-                                   color->r() + rscale * (rscale > 0.0 ? 255 - color->r() : color->r()),
-                                   color->g() + gscale * (gscale > 0.0 ? 255 - color->g() : color->g()),
-                                   color->b() + bscale * (bscale > 0.0 ? 255 - color->b() : color->b()),
-                                   color->a() + ascale * (ascale > 0.0 ? 1.0 - color->a() : color->a()));
-      }
-      if (hsl) {
-        double hscale = (h ? ARGR("$hue",        Number, -100.0, 100.0)->value() : 0.0) / 100.0;
-        double sscale = (s ? ARGR("$saturation", Number, -100.0, 100.0)->value() : 0.0) / 100.0;
-        double lscale = (l ? ARGR("$lightness",  Number, -100.0, 100.0)->value() : 0.0) / 100.0;
-        double ascale = (a ? ARGR("$alpha",      Number, -100.0, 100.0)->value() : 0.0) / 100.0;
-        HSL hsl_struct = rgb_to_hsl(color->r(), color->g(), color->b());
-        hsl_struct.h += hscale * (hscale > 0.0 ? 360.0 - hsl_struct.h : hsl_struct.h);
-        hsl_struct.s += sscale * (sscale > 0.0 ? 100.0 - hsl_struct.s : hsl_struct.s);
-        hsl_struct.l += lscale * (lscale > 0.0 ? 100.0 - hsl_struct.l : hsl_struct.l);
-        double alpha = color->a() + ascale * (ascale > 0.0 ? 1.0 - color->a() : color->a());
-        return hsla_impl(hsl_struct.h, hsl_struct.s, hsl_struct.l, alpha, ctx, pstate);
-      }
-      if (a) {
-        double ascale = (a ? ARGR("$alpha", Number, -100.0, 100.0)->value() : 0.0) / 100.0;
-        return new (ctx.mem) 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);
-      // unreachable
-      return color;
-    }
-
-    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"]);
-
-      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);
-      }
-      if (rgb) {
-        return new (ctx.mem) Color(pstate,
-                                   r ? ARGR("$red",   Number, 0, 255)->value() : color->r(),
-                                   g ? ARGR("$green", Number, 0, 255)->value() : color->g(),
-                                   b ? ARGR("$blue",  Number, 0, 255)->value() : color->b(),
-                                   a ? ARGR("$alpha", Number, 0, 255)->value() : color->a());
-      }
-      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 (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();
-        return hsla_impl(hsl_struct.h, hsl_struct.s, hsl_struct.l, alpha, ctx, pstate);
-      }
-      if (a) {
-        double alpha = a ? ARGR("$alpha", Number, 0, 1.0)->value() : color->a();
-        return new (ctx.mem) Color(pstate,
-                                   color->r(),
-                                   color->g(),
-                                   color->b(),
-                                   alpha);
-      }
-      error("not enough arguments for `change-color`", pstate);
-      // unreachable
-      return color;
-    }
-
-    template <size_t range>
-    static double cap_channel(double c) {
-      if      (c > range) return range;
-      else if (c < 0)     return 0;
-      else                return c;
-    }
-
-    Signature ie_hex_str_sig = "ie-hex-str($color)";
-    BUILT_IN(ie_hex_str)
-    {
-      Color* 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());
-      double a = cap_channel<1>   (c->a()) * 255;
-
-      stringstream ss;
-      ss << '#' << std::setw(2) << std::setfill('0');
-      ss << std::hex << std::setw(2) << static_cast<unsigned long>(std::floor(a+0.5));
-      ss << std::hex << std::setw(2) << static_cast<unsigned long>(std::floor(r+0.5));
-      ss << std::hex << std::setw(2) << static_cast<unsigned long>(std::floor(g+0.5));
-      ss << std::hex << std::setw(2) << static_cast<unsigned long>(std::floor(b+0.5));
-
-      string result(ss.str());
-      for (size_t i = 0, L = result.length(); i < L; ++i) {
-        result[i] = std::toupper(result[i]);
-      }
-      return new (ctx.mem) String_Constant(pstate, result);
-    }
-
-    ///////////////////
-    // STRING FUNCTIONS
-    ///////////////////
-
-    Signature unquote_sig = "unquote($string)";
-    BUILT_IN(sass_unquote)
-    {
-      AST_Node* arg = env["$string"];
-      if (dynamic_cast<Null*>(arg)) {
-        return new (ctx.mem) Null(pstate);
-      }
-      else if (String_Quoted* string_quoted = dynamic_cast<String_Quoted*>(arg)) {
-        String_Constant* result = new (ctx.mem) String_Constant(pstate, string_quoted->value());
-        // remember if the string was quoted (color tokens)
-        result->sass_fix_1291(string_quoted->quote_mark() != 0);
-        return result;
-      }
-      To_String to_string(&ctx);
-      return new (ctx.mem) String_Constant(pstate, unquote(string(arg->perform(&to_string))));
-    }
-
-    Signature quote_sig = "quote($string)";
-    BUILT_IN(sass_quote)
-    {
-      To_String to_string(&ctx);
-      AST_Node* arg = env["$string"];
-      string str(quote(arg->perform(&to_string), String_Constant::double_quote()));
-      String_Constant* result = new (ctx.mem) String_Constant(pstate, str);
-      result->is_delayed(true);
-      return result;
-    }
-
-
-    Signature str_length_sig = "str-length($string)";
-    BUILT_IN(str_length)
-    {
-      size_t len = string::npos;
-      try {
-        String_Constant* s = ARG("$string", String_Constant);
-        len = UTF_8::code_point_count(s->value(), 0, s->value().size());
-
-      }
-      catch (utf8::invalid_code_point) {
-        string msg("utf8::invalid_code_point");
-        error(msg, pstate, backtrace);
-      }
-      catch (utf8::not_enough_room) {
-        string msg("utf8::not_enough_room");
-        error(msg, pstate, backtrace);
-      }
-      catch (utf8::invalid_utf8) {
-        string msg("utf8::invalid_utf8");
-        error(msg, pstate, backtrace);
-      }
-      catch (...) { throw; }
-      // return something even if we had an error (-1)
-      return new (ctx.mem) Number(pstate, len);
-    }
-
-    Signature str_insert_sig = "str-insert($string, $insert, $index)";
-    BUILT_IN(str_insert)
-    {
-      string str;
-      try {
-        String_Constant* s = ARG("$string", String_Constant);
-        str = s->value();
-        str = unquote(str);
-        String_Constant* i = ARG("$insert", String_Constant);
-        string ins = i->value();
-        ins = unquote(ins);
-        Number* ind = ARG("$index", Number);
-        double index = ind->value();
-        size_t len = UTF_8::code_point_count(str, 0, str.size());
-
-        if (index > 0 && index <= len) {
-          // positive and within string length
-          str.insert(UTF_8::offset_at_position(str, static_cast<size_t>(index) - 1), ins);
-        }
-        else if (index > len) {
-          // positive and past string length
-          str += ins;
-        }
-        else if (index == 0) {
-          str = ins + str;
-        }
-        else if (std::abs(index) <= len) {
-          // negative and within string length
-          index += len + 1;
-          str.insert(UTF_8::offset_at_position(str, static_cast<size_t>(index)), ins);
-        }
-        else {
-          // negative and past string length
-          str = ins + str;
-        }
-
-        if (String_Quoted* ss = dynamic_cast<String_Quoted*>(s)) {
-          if (ss->quote_mark()) str = quote(str);
-        }
-      }
-      catch (utf8::invalid_code_point) {
-        string msg("utf8::invalid_code_point");
-        error(msg, pstate, backtrace);
-      }
-      catch (utf8::not_enough_room) {
-        string msg("utf8::not_enough_room");
-        error(msg, pstate, backtrace);
-      }
-      catch (utf8::invalid_utf8) {
-        string msg("utf8::invalid_utf8");
-        error(msg, pstate, backtrace);
-      }
-      catch (...) { throw; }
-      return new (ctx.mem) String_Constant(pstate, str);
-    }
-
-    Signature str_index_sig = "str-index($string, $substring)";
-    BUILT_IN(str_index)
-    {
-      size_t index = string::npos;
-      try {
-        String_Constant* s = ARG("$string", String_Constant);
-        String_Constant* t = ARG("$substring", String_Constant);
-        string str = s->value();
-        str = unquote(str);
-        string substr = t->value();
-        substr = unquote(substr);
-
-        size_t c_index = str.find(substr);
-        if(c_index == string::npos) {
-          return new (ctx.mem) Null(pstate);
-        }
-        index = UTF_8::code_point_count(str, 0, c_index) + 1;
-      }
-      catch (utf8::invalid_code_point) {
-        string msg("utf8::invalid_code_point");
-        error(msg, pstate, backtrace);
-      }
-      catch (utf8::not_enough_room) {
-        string msg("utf8::not_enough_room");
-        error(msg, pstate, backtrace);
-      }
-      catch (utf8::invalid_utf8) {
-        string msg("utf8::invalid_utf8");
-        error(msg, pstate, backtrace);
-      }
-      catch (...) { throw; }
-      // return something even if we had an error (-1)
-      return new (ctx.mem) Number(pstate, index);
-    }
-
-    Signature str_slice_sig = "str-slice($string, $start-at, $end-at:-1)";
-    BUILT_IN(str_slice)
-    {
-      string newstr;
-      try {
-        String_Constant* s = ARG("$string", String_Constant);
-        double start_at = ARG("$start-at", Number)->value();
-        double end_at = ARG("$end-at", Number)->value();
-
-        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 (end_at > size) { end_at = size; }
-        if (start_at < 0) { start_at += size + 1; }
-        else if (start_at == 0) { ++ start_at; }
-
-        if (start_at <= end_at)
-        {
-          string::iterator start = str.begin();
-          utf8::advance(start, start_at - 1, str.end());
-          string::iterator end = start;
-          utf8::advance(end, end_at - start_at + 1, str.end());
-          newstr = string(start, end);
-        }
-        if (String_Quoted* ss = dynamic_cast<String_Quoted*>(s)) {
-          if(ss->quote_mark()) newstr = quote(newstr);
-        }
-      }
-      catch (utf8::invalid_code_point) {
-        string msg("utf8::invalid_code_point");
-        error(msg, pstate, backtrace);
-      }
-      catch (utf8::not_enough_room) {
-        string msg("utf8::not_enough_room");
-        error(msg, pstate, backtrace);
-      }
-      catch (utf8::invalid_utf8) {
-        string msg("utf8::invalid_utf8");
-        error(msg, pstate, backtrace);
-      }
-      catch (...) { throw; }
-      return new (ctx.mem) 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 str = s->value();
-
-      for (size_t i = 0, L = str.length(); i < L; ++i) {
-        if (Sass::Util::isAscii(str[i])) {
-          str[i] = std::toupper(str[i]);
-        }
-      }
-
-      if (String_Quoted* ss = dynamic_cast<String_Quoted*>(s)) {
-        str = ss->quote_mark() ? quote(str) : str;
-      }
-      return new (ctx.mem) String_Constant(pstate, str);
-    }
-
-    Signature to_lower_case_sig = "to-lower-case($string)";
-    BUILT_IN(to_lower_case)
-    {
-      String_Constant* s = ARG("$string", String_Constant);
-      string str = s->value();
-
-      for (size_t i = 0, L = str.length(); i < L; ++i) {
-        if (Sass::Util::isAscii(str[i])) {
-          str[i] = std::tolower(str[i]);
-        }
-      }
-
-      if (String_Quoted* ss = dynamic_cast<String_Quoted*>(s)) {
-        str = ss->quote_mark() ? quote(str, '"') : str;
-      }
-      return new (ctx.mem) String_Constant(pstate, str);
-    }
-
-    ///////////////////
-    // NUMBER FUNCTIONS
-    ///////////////////
-
-    Signature percentage_sig = "percentage($number)";
-    BUILT_IN(percentage)
-    {
-      Number* n = ARG("$number", Number);
-      if (!n->is_unitless()) error("argument $number of `" + string(sig) + "` must be unitless", pstate);
-      return new (ctx.mem) Number(pstate, n->value() * 100, "%");
-    }
-
-    Signature round_sig = "round($number)";
-    BUILT_IN(round)
-    {
-      Number* n = ARG("$number", Number);
-      Number* r = new (ctx.mem) Number(*n);
-      r->pstate(pstate);
-      r->value(std::floor(r->value() + 0.5));
-      return r;
-    }
-
-    Signature ceil_sig = "ceil($number)";
-    BUILT_IN(ceil)
-    {
-      Number* n = ARG("$number", Number);
-      Number* r = new (ctx.mem) Number(*n);
-      r->pstate(pstate);
-      r->value(std::ceil(r->value()));
-      return r;
-    }
-
-    Signature floor_sig = "floor($number)";
-    BUILT_IN(floor)
-    {
-      Number* n = ARG("$number", Number);
-      Number* r = new (ctx.mem) Number(*n);
-      r->pstate(pstate);
-      r->value(std::floor(r->value()));
-      return r;
-    }
-
-    Signature abs_sig = "abs($number)";
-    BUILT_IN(abs)
-    {
-      Number* n = ARG("$number", Number);
-      Number* r = new (ctx.mem) Number(*n);
-      r->pstate(pstate);
-      r->value(std::abs(r->value()));
-      return r;
-    }
-
-    Signature min_sig = "min($numbers...)";
-    BUILT_IN(min)
-    {
-      List* arglist = ARG("$numbers", List);
-      Number* least = 0;
-      for (size_t i = 0, L = arglist->length(); i < L; ++i) {
-        Number* xi = dynamic_cast<Number*>(arglist->value_at_index(i));
-        if (least) {
-          if (!xi) error("`" + string(sig) + "` only takes numeric arguments", pstate);
-          if (lt(xi, least, ctx)) least = xi;
-        } else least = xi;
-      }
-      return least;
-    }
-
-    Signature max_sig = "max($numbers...)";
-    BUILT_IN(max)
-    {
-      List* arglist = ARG("$numbers", List);
-      Number* greatest = 0;
-      for (size_t i = 0, L = arglist->length(); i < L; ++i) {
-        Number* xi = dynamic_cast<Number*>(arglist->value_at_index(i));
-        if (greatest) {
-          if (!xi) error("`" + string(sig) + "` only takes numeric arguments", pstate);
-          if (lt(greatest, xi, ctx)) greatest = xi;
-        } else greatest = xi;
-      }
-      return greatest;
-    }
-
-    Signature random_sig = "random($limit:false)";
-    BUILT_IN(random)
-    {
-      Number* l = dynamic_cast<Number*>(env["$limit"]);
-      if (l) {
-        if (trunc(l->value()) != l->value() || l->value() == 0) error("argument $limit of `" + string(sig) + "` must be a positive integer", pstate);
-        uniform_real_distribution<> distributor(1, l->value() + 1);
-        uint_fast32_t distributed = static_cast<uint_fast32_t>(distributor(rand));
-        return new (ctx.mem) Number(pstate, (double)distributed);
-      }
-      else {
-        uniform_real_distribution<> distributor(0, 1);
-        double distributed = static_cast<double>(distributor(rand));
-        return new (ctx.mem) Number(pstate, distributed);
-     }
-    }
-
-    /////////////////
-    // LIST FUNCTIONS
-    /////////////////
-
-    Signature length_sig = "length($list)";
-    BUILT_IN(length)
-    {
-      Expression* v = ARG("$list", Expression);
-      if (v->concrete_type() == Expression::MAP) {
-        Map* map = dynamic_cast<Map*>(env["$list"]);
-        return new (ctx.mem) Number(pstate,
-                                    map ? map->length() : 1);
-      }
-
-      List* list = dynamic_cast<List*>(env["$list"]);
-      return new (ctx.mem) Number(pstate,
-                                  list ? list->size() : 1);
-    }
-
-    Signature nth_sig = "nth($list, $n)";
-    BUILT_IN(nth)
-    {
-      Map* m = dynamic_cast<Map*>(env["$list"]);
-      List* l = dynamic_cast<List*>(env["$list"]);
-      Number* n = ARG("$n", Number);
-      if (n->value() == 0) error("argument `$n` of `" + 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 = new (ctx.mem) List(pstate, 1);
-        *l << ARG("$list", Expression);
-      }
-      size_t len = m ? m->length() : l->length();
-      bool empty = m ? m->empty() : l->empty();
-      if (empty) error("argument `$list` of `" + 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 `" + string(sig) + "`", pstate);
-
-      if (m) {
-        l = 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;
-      }
-      else {
-        return l->value_at_index(static_cast<int>(index));
-      }
-    }
-
-    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);
-      if (!l) {
-        l = new (ctx.mem) List(pstate, 1);
-        *l << ARG("$list", Expression);
-      }
-      if (l->empty()) error("argument `$list` of `" + 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 `" + string(sig) + "`", pstate);
-      List* result = new (ctx.mem) List(pstate, l->length(), l->separator());
-      for (size_t i = 0, L = l->length(); i < L; ++i) {
-        *result << ((i == index) ? v : (*l)[i]);
-      }
-      return result;
-    }
-
-    Signature index_sig = "index($list, $value)";
-    BUILT_IN(index)
-    {
-      List* l = dynamic_cast<List*>(env["$list"]);
-      Expression* v = ARG("$value", Expression);
-      if (!l) {
-        l = new (ctx.mem) List(pstate, 1);
-        *l << ARG("$list", Expression);
-      }
-      for (size_t i = 0, L = l->length(); i < L; ++i) {
-        if (eq(l->value_at_index(i), v, ctx)) return new (ctx.mem) Number(pstate, i+1);
-      }
-      return new (ctx.mem) 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);
-      List::Separator sep_val = (l1 ? l1->separator() : List::SPACE);
-      if (!l1) {
-        l1 = new (ctx.mem) List(pstate, 1);
-        *l1 << ARG("$list1", Expression);
-        sep_val = (l2 ? l2->separator() : List::SPACE);
-      }
-      if (!l2) {
-        l2 = new (ctx.mem) List(pstate, 1);
-        *l2 << ARG("$list2", Expression);
-      }
-      size_t len = l1->length() + l2->length();
-      string sep_str = unquote(sep->value());
-      if (sep_str == "space") sep_val = List::SPACE;
-      else if (sep_str == "comma") sep_val = List::COMMA;
-      else if (sep_str != "auto") error("argument `$separator` of `" + string(sig) + "` must be `space`, `comma`, or `auto`", pstate);
-      List* result = new (ctx.mem) List(pstate, len, sep_val);
-      *result += l1;
-      *result += l2;
-      return result;
-    }
-
-    Signature append_sig = "append($list, $val, $separator: auto)";
-    BUILT_IN(append)
-    {
-      List* l = dynamic_cast<List*>(env["$list"]);
-      Expression* v = ARG("$val", Expression);
-      String_Constant* sep = ARG("$separator", String_Constant);
-      if (!l) {
-        l = new (ctx.mem) List(pstate, 1);
-        *l << ARG("$list", Expression);
-      }
-      List* result = new (ctx.mem) List(pstate, l->length() + 1, l->separator());
-      string sep_str(unquote(sep->value()));
-      if (sep_str == "space") result->separator(List::SPACE);
-      else if (sep_str == "comma") result->separator(List::COMMA);
-      else if (sep_str != "auto") error("argument `$separator` of `" + string(sig) + "` must be `space`, `comma`, or `auto`", pstate);
-      *result += l;
-      bool is_arglist = l->is_arglist();
-      result->is_arglist(is_arglist);
-      if (is_arglist) {
-        *result << new (ctx.mem) Argument(v->pstate(),
-                                          v,
-                                          "",
-                                          false,
-                                          false);
-
-      } else {
-        *result << v;
-      }
-      return result;
-    }
-
-    Signature zip_sig = "zip($lists...)";
-    BUILT_IN(zip)
-    {
-      List* arglist = new (ctx.mem) List(*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));
-        if (!ith) {
-          ith = new (ctx.mem) List(pstate, 1);
-          *ith << arglist->value_at_index(i);
-          if (arglist->is_arglist()) {
-            ((Argument*)(*arglist)[i])->value(ith);
-          } else {
-            (*arglist)[i] = ith;
-          }
-        }
-        shortest = (i ? std::min(shortest, ith->length()) : ith->length());
-      }
-      List* zippers = new (ctx.mem) List(pstate, shortest, List::COMMA);
-      size_t L = arglist->length();
-      for (size_t i = 0; i < shortest; ++i) {
-        List* zipper = new (ctx.mem) List(pstate, L);
-        for (size_t j = 0; j < L; ++j) {
-          *zipper << (*static_cast<List*>(arglist->value_at_index(j)))[i];
-        }
-        *zippers << zipper;
-      }
-      return zippers;
-    }
-
-    Signature list_separator_sig = "list_separator($list)";
-    BUILT_IN(list_separator)
-    {
-      List* l = dynamic_cast<List*>(env["$list"]);
-      if (!l) {
-        l = new (ctx.mem) List(pstate, 1);
-        *l << ARG("$list", Expression);
-      }
-      return new (ctx.mem) String_Constant(pstate,
-                                           l->separator() == List::COMMA ? "comma" : "space");
-    }
-
-    /////////////////
-    // MAP FUNCTIONS
-    /////////////////
-
-    Signature map_get_sig = "map-get($map, $key)";
-    BUILT_IN(map_get)
-    {
-      Map* m = ARGM("$map", Map, ctx);
-      Expression* v = ARG("$key", Expression);
-      try {
-        return m->at(v);
-      } catch (const std::out_of_range&) {
-        return new (ctx.mem) Null(pstate);
-      }
-      catch (...) { throw; }
-    }
-
-    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 new (ctx.mem) Boolean(pstate, m->has(v));
-    }
-
-    Signature map_keys_sig = "map-keys($map)";
-    BUILT_IN(map_keys)
-    {
-      Map* m = ARGM("$map", Map, ctx);
-      List* result = new (ctx.mem) List(pstate, m->length(), List::COMMA);
-      for ( auto key : m->keys()) {
-        *result << key;
-      }
-      return result;
-    }
-
-    Signature map_values_sig = "map-values($map)";
-    BUILT_IN(map_values)
-    {
-      Map* m = ARGM("$map", Map, ctx);
-      List* result = new (ctx.mem) List(pstate, m->length(), List::COMMA);
-      for ( auto key : m->keys()) {
-        *result << m->at(key);
-      }
-      return result;
-    }
-
-    Signature map_merge_sig = "map-merge($map1, $map2)";
-    BUILT_IN(map_merge)
-    {
-      Map* m1 = ARGM("$map1", Map, ctx);
-      Map* m2 = ARGM("$map2", Map, ctx);
-
-      size_t len = m1->length() + m2->length();
-      Map* result = new (ctx.mem) Map(pstate, len);
-      *result += m1;
-      *result += m2;
-      return result;
-    }
-
-    Signature map_remove_sig = "map-remove($map, $keys...)";
-    BUILT_IN(map_remove)
-    {
-      bool remove;
-      Map* m = ARGM("$map", Map, ctx);
-      List* arglist = ARG("$keys", List);
-      Map* result = new (ctx.mem) Map(pstate, 1);
-      for (auto key : m->keys()) {
-        remove = false;
-        for (size_t j = 0, K = arglist->length(); j < K && !remove; ++j) {
-          remove = eq(key, arglist->value_at_index(j), ctx);
-        }
-        if (!remove) *result << make_pair(key, m->at(key));
-      }
-      return result;
-    }
-
-    Signature keywords_sig = "keywords($args)";
-    BUILT_IN(keywords)
-    {
-      List* arglist = new (ctx.mem) List(*ARG("$args", List));
-      Map* result = new (ctx.mem) Map(pstate, 1);
-      for (size_t i = arglist->size(), L = arglist->length(); i < L; ++i) {
-        string name = string(((Argument*)(*arglist)[i])->name());
-        name = name.erase(0, 1); // sanitize name (remove dollar sign)
-        *result << make_pair(new (ctx.mem) String_Constant(pstate, name),
-                             ((Argument*)(*arglist)[i])->value());
-      }
-      return result;
-    }
-
-    //////////////////////////
-    // INTROSPECTION FUNCTIONS
-    //////////////////////////
-
-    Signature type_of_sig = "type-of($value)";
-    BUILT_IN(type_of)
-    {
-      Expression* v = ARG("$value", Expression);
-      if (v->concrete_type() == Expression::STRING) {
-        To_String to_string(&ctx);
-        string str(v->perform(&to_string));
-        if (ctx.names_to_colors.count(str)) {
-          return new (ctx.mem) String_Constant(pstate, "color");
-        }
-      }
-      return new (ctx.mem) String_Constant(pstate, ARG("$value", Expression)->type());
-    }
-
-    Signature unit_sig = "unit($number)";
-    BUILT_IN(unit)
-    { return new (ctx.mem) String_Quoted(pstate, quote(ARG("$number", Number)->unit(), '"')); }
-
-    Signature unitless_sig = "unitless($number)";
-    BUILT_IN(unitless)
-    { return new (ctx.mem) 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);
-      if (n1->is_unitless() || n2->is_unitless()) {
-        return new (ctx.mem) Boolean(pstate, true);
-      }
-      Number tmp_n2(*n2);
-      tmp_n2.normalize(n1->find_convertible_unit());
-      return new (ctx.mem) Boolean(pstate, n1->unit() == tmp_n2.unit());
-    }
-
-    Signature variable_exists_sig = "variable-exists($name)";
-    BUILT_IN(variable_exists)
-    {
-      string s = Util::normalize_underscores(unquote(ARG("$name", String_Constant)->value()));
-
-      if(d_env.has("$"+s)) {
-        return new (ctx.mem) Boolean(pstate, true);
-      }
-      else {
-        return new (ctx.mem) Boolean(pstate, false);
-      }
-    }
-
-    Signature global_variable_exists_sig = "global-variable-exists($name)";
-    BUILT_IN(global_variable_exists)
-    {
-      string s = Util::normalize_underscores(unquote(ARG("$name", String_Constant)->value()));
-
-      if(d_env.has_global("$"+s)) {
-        return new (ctx.mem) Boolean(pstate, true);
-      }
-      else {
-        return new (ctx.mem) Boolean(pstate, false);
-      }
-    }
-
-    Signature function_exists_sig = "function-exists($name)";
-    BUILT_IN(function_exists)
-    {
-      string s = Util::normalize_underscores(unquote(ARG("$name", String_Constant)->value()));
-
-      if(d_env.has_global(s+"[f]")) {
-        return new (ctx.mem) Boolean(pstate, true);
-      }
-      else {
-        return new (ctx.mem) Boolean(pstate, false);
-      }
-    }
-
-    Signature mixin_exists_sig = "mixin-exists($name)";
-    BUILT_IN(mixin_exists)
-    {
-      string s = Util::normalize_underscores(unquote(ARG("$name", String_Constant)->value()));
-
-      if(d_env.has_global(s+"[m]")) {
-        return new (ctx.mem) Boolean(pstate, true);
-      }
-      else {
-        return new (ctx.mem) Boolean(pstate, false);
-      }
-    }
-
-    Signature feature_exists_sig = "feature-exists($name)";
-    BUILT_IN(feature_exists)
-    {
-      string s = unquote(ARG("$name", String_Constant)->value());
-
-      if(features.find(s) == features.end()) {
-        return new (ctx.mem) Boolean(pstate, false);
-      }
-      else {
-        return new (ctx.mem) Boolean(pstate, true);
-      }
-    }
-
-    Signature call_sig = "call($name, $args...)";
-    BUILT_IN(call)
-    {
-      string name = Util::normalize_underscores(unquote(ARG("$name", String_Constant)->value()));
-      List* arglist = new (ctx.mem) List(*ARG("$args", List));
-
-      Arguments* args = new (ctx.mem) Arguments(pstate);
-      for (size_t i = 0, L = arglist->length(); i < L; ++i) {
-        Expression* expr = arglist->value_at_index(i);
-        if (arglist->is_arglist()) {
-          Argument* arg = static_cast<Argument*>((*arglist)[i]);
-          *args << new (ctx.mem) Argument(pstate,
-                                          expr,
-                                          "",
-                                          arg->is_rest_argument(),
-                                          arg->is_keyword_argument());
-        } else {
-          *args << new (ctx.mem) Argument(pstate, expr);
-        }
-      }
-      Function_Call* func = new (ctx.mem) Function_Call(pstate, name, args);
-      Contextualize contextualize(ctx, &d_env, backtrace);
-      Listize listize(ctx);
-      Eval eval(ctx, &contextualize, &listize, &d_env, backtrace);
-      return func->perform(&eval);
-
-    }
-
-    ////////////////////
-    // BOOLEAN FUNCTIONS
-    ////////////////////
-
-    Signature not_sig = "not($value)";
-    BUILT_IN(sass_not)
-    { return new (ctx.mem) 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)
-    {
-      Contextualize contextualize(ctx, &d_env, backtrace);
-      Listize listize(ctx);
-      Eval eval(ctx, &contextualize, &listize, &d_env, backtrace);
-      bool is_true = !ARG("$condition", Expression)->perform(&eval)->is_false();
-      if (is_true) {
-        return ARG("$if-true", Expression)->perform(&eval);
-      }
-      else {
-        return ARG("$if-false", Expression)->perform(&eval);
-      }
-    }
-
-    ////////////////
-    // URL FUNCTIONS
-    ////////////////
-
-    Signature image_url_sig = "image-url($path, $only-path: false, $cache-buster: false)";
-    BUILT_IN(image_url)
-    {
-      error("`image_url` has been removed from libsass because it's not part of the Sass spec", pstate);
-      return 0; // suppress warning, error will exit anyway
-    }
-
-    //////////////////////////
-    // MISCELLANEOUS FUNCTIONS
-    //////////////////////////
-
-    Signature inspect_sig = "inspect($value)";
-    BUILT_IN(inspect)
-    {
-      Expression* v = ARG("$value", Expression);
-      if (v->concrete_type() == Expression::NULL_VAL) {
-        return new (ctx.mem) String_Constant(pstate, "null");
-      } else if (v->concrete_type() == Expression::BOOLEAN && *v == 0) {
-        return new (ctx.mem) String_Constant(pstate, "false");
-      } else if (v->concrete_type() == Expression::STRING) {
-        return v;
-      } else {
-        bool parentheses = v->concrete_type() == Expression::MAP ||
-                           v->concrete_type() == Expression::LIST;
-        Output_Style old_style;
-        old_style = ctx.output_style;
-        ctx.output_style = NESTED;
-        To_String to_string(&ctx, false);
-        string inspect = v->perform(&to_string);
-        if (inspect.empty() && parentheses) inspect = "()";
-        ctx.output_style = old_style;
-        return new (ctx.mem) String_Constant(pstate, inspect);
-
-
-      }
-      // return v;
-    }
-
-    Signature is_superselector_sig = "is-superselector($super, $sub)";
-    BUILT_IN(is_superselector)
-    {
-      To_String to_string(&ctx, false);
-      Expression*  ex_sup = ARG("$super", Expression);
-      Expression*  ex_sub = ARG("$sub", Expression);
-      string sup_src = ex_sup->perform(&to_string) + "{";
-      string sub_src = ex_sub->perform(&to_string) + "{";
-      Selector_List* sel_sup = Parser::parse_selector(sup_src.c_str(), ctx);
-      Selector_List* sel_sub = Parser::parse_selector(sub_src.c_str(), ctx);
-      bool result = sel_sup->is_superselector_of(sel_sub);
-      return new (ctx.mem) Boolean(pstate, result);
-    }
-
-    Signature unique_id_sig = "unique-id()";
-    BUILT_IN(unique_id)
-    {
-      std::stringstream ss;
-      uniform_real_distribution<> distributor(0, 4294967296); // 16^8
-      uint_fast32_t distributed = static_cast<uint_fast32_t>(distributor(rand));
-      ss << "u" << setfill('0') << setw(8) << std::hex << distributed;
-      return new (ctx.mem) String_Constant(pstate, ss.str());
-    }
-
-  }
-}
diff --git a/libsass/functions.hpp b/libsass/functions.hpp
deleted file mode 100644
--- a/libsass/functions.hpp
+++ /dev/null
@@ -1,184 +0,0 @@
-#ifndef SASS_FUNCTIONS_H
-#define SASS_FUNCTIONS_H
-
-#include <string>
-
-#include "position.hpp"
-#include "environment.hpp"
-#include "sass_functions.h"
-
-#define BUILT_IN(name) Expression*\
-name(Env& env, Env& d_env, Context& ctx, Signature sig, ParserState pstate, Backtrace* backtrace)
-
-namespace Sass {
-  class Context;
-  struct Backtrace;
-  class AST_Node;
-  class Expression;
-  class Definition;
-  typedef Environment<AST_Node*> Env;
-  typedef const char* Signature;
-  typedef Expression* (*Native_Function)(Env&, Env&, Context&, Signature, ParserState, Backtrace*);
-
-  Definition* make_native_function(Signature, Native_Function, Context& ctx);
-  Definition* make_c_function(Sass_Function_Entry c_func, Context& ctx);
-
-  namespace Functions {
-
-    extern Signature rgb_sig;
-    extern Signature rgba_4_sig;
-    extern Signature rgba_2_sig;
-    extern Signature red_sig;
-    extern Signature green_sig;
-    extern Signature blue_sig;
-    extern Signature mix_sig;
-    extern Signature hsl_sig;
-    extern Signature hsla_sig;
-    extern Signature hue_sig;
-    extern Signature saturation_sig;
-    extern Signature lightness_sig;
-    extern Signature adjust_hue_sig;
-    extern Signature lighten_sig;
-    extern Signature darken_sig;
-    extern Signature saturate_sig;
-    extern Signature desaturate_sig;
-    extern Signature grayscale_sig;
-    extern Signature complement_sig;
-    extern Signature invert_sig;
-    extern Signature alpha_sig;
-    extern Signature opacity_sig;
-    extern Signature opacify_sig;
-    extern Signature fade_in_sig;
-    extern Signature transparentize_sig;
-    extern Signature fade_out_sig;
-    extern Signature adjust_color_sig;
-    extern Signature scale_color_sig;
-    extern Signature change_color_sig;
-    extern Signature ie_hex_str_sig;
-    extern Signature unquote_sig;
-    extern Signature quote_sig;
-    extern Signature str_length_sig;
-    extern Signature str_insert_sig;
-    extern Signature str_index_sig;
-    extern Signature str_slice_sig;
-    extern Signature to_upper_case_sig;
-    extern Signature to_lower_case_sig;
-    extern Signature percentage_sig;
-    extern Signature round_sig;
-    extern Signature ceil_sig;
-    extern Signature floor_sig;
-    extern Signature abs_sig;
-    extern Signature min_sig;
-    extern Signature max_sig;
-    extern Signature inspect_sig;
-    extern Signature random_sig;
-    extern Signature length_sig;
-    extern Signature nth_sig;
-    extern Signature index_sig;
-    extern Signature join_sig;
-    extern Signature append_sig;
-    extern Signature zip_sig;
-    extern Signature list_separator_sig;
-    extern Signature type_of_sig;
-    extern Signature unit_sig;
-    extern Signature unitless_sig;
-    extern Signature comparable_sig;
-    extern Signature variable_exists_sig;
-    extern Signature global_variable_exists_sig;
-    extern Signature function_exists_sig;
-    extern Signature mixin_exists_sig;
-    extern Signature feature_exists_sig;
-    extern Signature call_sig;
-    extern Signature not_sig;
-    extern Signature if_sig;
-    extern Signature image_url_sig;
-    extern Signature map_get_sig;
-    extern Signature map_merge_sig;
-    extern Signature map_remove_sig;
-    extern Signature map_keys_sig;
-    extern Signature map_values_sig;
-    extern Signature map_has_key_sig;
-    extern Signature keywords_sig;
-    extern Signature set_nth_sig;
-    extern Signature unique_id_sig;
-    extern Signature is_superselector_sig;
-
-    BUILT_IN(rgb);
-    BUILT_IN(rgba_4);
-    BUILT_IN(rgba_2);
-    BUILT_IN(red);
-    BUILT_IN(green);
-    BUILT_IN(blue);
-    BUILT_IN(mix);
-    BUILT_IN(hsl);
-    BUILT_IN(hsla);
-    BUILT_IN(hue);
-    BUILT_IN(saturation);
-    BUILT_IN(lightness);
-    BUILT_IN(adjust_hue);
-    BUILT_IN(lighten);
-    BUILT_IN(darken);
-    BUILT_IN(saturate);
-    BUILT_IN(desaturate);
-    BUILT_IN(grayscale);
-    BUILT_IN(complement);
-    BUILT_IN(invert);
-    BUILT_IN(alpha);
-    BUILT_IN(opacify);
-    BUILT_IN(transparentize);
-    BUILT_IN(adjust_color);
-    BUILT_IN(scale_color);
-    BUILT_IN(change_color);
-    BUILT_IN(ie_hex_str);
-    BUILT_IN(sass_unquote);
-    BUILT_IN(sass_quote);
-    BUILT_IN(str_length);
-    BUILT_IN(str_insert);
-    BUILT_IN(str_index);
-    BUILT_IN(str_slice);
-    BUILT_IN(to_upper_case);
-    BUILT_IN(to_lower_case);
-    BUILT_IN(percentage);
-    BUILT_IN(round);
-    BUILT_IN(ceil);
-    BUILT_IN(floor);
-    BUILT_IN(abs);
-    BUILT_IN(min);
-    BUILT_IN(max);
-    BUILT_IN(inspect);
-    BUILT_IN(random);
-    BUILT_IN(length);
-    BUILT_IN(nth);
-    BUILT_IN(index);
-    BUILT_IN(join);
-    BUILT_IN(append);
-    BUILT_IN(zip);
-    BUILT_IN(list_separator);
-    BUILT_IN(type_of);
-    BUILT_IN(unit);
-    BUILT_IN(unitless);
-    BUILT_IN(comparable);
-    BUILT_IN(variable_exists);
-    BUILT_IN(global_variable_exists);
-    BUILT_IN(function_exists);
-    BUILT_IN(mixin_exists);
-    BUILT_IN(feature_exists);
-    BUILT_IN(call);
-    BUILT_IN(sass_not);
-    BUILT_IN(sass_if);
-    BUILT_IN(image_url);
-    BUILT_IN(map_get);
-    BUILT_IN(map_merge);
-    BUILT_IN(map_remove);
-    BUILT_IN(map_keys);
-    BUILT_IN(map_values);
-    BUILT_IN(map_has_key);
-    BUILT_IN(keywords);
-    BUILT_IN(set_nth);
-    BUILT_IN(unique_id);
-    BUILT_IN(is_superselector);
-
-  }
-}
-
-#endif
diff --git a/libsass/include/sass.h b/libsass/include/sass.h
new file mode 100644
--- /dev/null
+++ b/libsass/include/sass.h
@@ -0,0 +1,15 @@
+#ifndef SASS_H
+#define SASS_H
+
+// #define DEBUG 1
+
+// include API headers
+#include <sass/base.h>
+#include <sass/version.h>
+#include <sass/values.h>
+#include <sass/functions.h>
+#include <sass/context.h>
+#include <sass2scss.h>
+
+#endif
+
diff --git a/libsass/include/sass/base.h b/libsass/include/sass/base.h
new file mode 100644
--- /dev/null
+++ b/libsass/include/sass/base.h
@@ -0,0 +1,76 @@
+#ifndef SASS_BASE_H
+#define SASS_BASE_H
+
+#ifdef _MSC_VER
+  #pragma warning(disable : 4503)
+  #ifndef _SCL_SECURE_NO_WARNINGS
+    #define _SCL_SECURE_NO_WARNINGS
+  #endif
+  #ifndef _CRT_SECURE_NO_WARNINGS
+    #define _CRT_SECURE_NO_WARNINGS
+  #endif
+  #ifndef _CRT_NONSTDC_NO_DEPRECATE
+    #define _CRT_NONSTDC_NO_DEPRECATE
+  #endif
+#endif
+
+#include <stddef.h>
+#include <stdbool.h>
+
+#ifdef __GNUC__
+  #define DEPRECATED(func) func __attribute__ ((deprecated))
+#elif defined(_MSC_VER)
+  #define DEPRECATED(func) __declspec(deprecated) func
+#else
+  #pragma message("WARNING: You need to implement DEPRECATED for this compiler")
+  #define DEPRECATED(func) func
+#endif
+
+#ifdef _WIN32
+
+  /* You should define ADD_EXPORTS *only* when building the DLL. */
+  #ifdef ADD_EXPORTS
+    #define ADDAPI __declspec(dllexport)
+    #define ADDCALL __cdecl
+  #else
+    #define ADDAPI
+    #define ADDCALL
+  #endif
+
+#else /* _WIN32 not defined. */
+
+  /* Define with no value on non-Windows OSes. */
+  #define ADDAPI
+  #define ADDCALL
+
+#endif
+
+/* Make sure functions are exported with C linkage under C++ compilers. */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+// Different render styles
+enum Sass_Output_Style {
+  SASS_STYLE_NESTED,
+  SASS_STYLE_EXPANDED,
+  SASS_STYLE_COMPACT,
+  SASS_STYLE_COMPRESSED
+};
+
+// 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);
+
+// 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
+ADDAPI const char* ADDCALL libsass_version(void);
+
+#ifdef __cplusplus
+} // __cplusplus defined.
+#endif
+
+#endif
diff --git a/libsass/include/sass/context.h b/libsass/include/sass/context.h
new file mode 100644
--- /dev/null
+++ b/libsass/include/sass/context.h
@@ -0,0 +1,152 @@
+#ifndef SASS_C_CONTEXT_H
+#define SASS_C_CONTEXT_H
+
+#include <stddef.h>
+#include <stdbool.h>
+#include <sass/base.h>
+#include <sass/values.h>
+#include <sass/functions.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+// Forward declaration
+struct Sass_Compiler;
+
+// Forward declaration
+struct Sass_Options; // base struct
+struct Sass_Context; // : Sass_Options
+struct Sass_File_Context; // : Sass_Context
+struct Sass_Data_Context; // : Sass_Context
+
+// Compiler states
+enum Sass_Compiler_State {
+  SASS_COMPILER_CREATED,
+  SASS_COMPILER_PARSED,
+  SASS_COMPILER_EXECUTED
+};
+
+// Create and initialize an option struct
+ADDAPI struct Sass_Options* ADDCALL sass_make_options (void);
+// Create and initialize a specific context
+ADDAPI struct Sass_File_Context* ADDCALL sass_make_file_context (const char* input_path);
+ADDAPI struct Sass_Data_Context* ADDCALL sass_make_data_context (char* source_string);
+
+// Call the compilation step for the specific context
+ADDAPI int ADDCALL sass_compile_file_context (struct Sass_File_Context* ctx);
+ADDAPI int ADDCALL sass_compile_data_context (struct Sass_Data_Context* ctx);
+
+// Create a sass compiler instance for more control
+ADDAPI struct Sass_Compiler* ADDCALL sass_make_file_compiler (struct Sass_File_Context* file_ctx);
+ADDAPI struct Sass_Compiler* ADDCALL sass_make_data_compiler (struct Sass_Data_Context* data_ctx);
+
+// Execute the different compilation steps individually
+// Usefull if you only want to query the included files
+ADDAPI int ADDCALL sass_compiler_parse(struct Sass_Compiler* compiler);
+ADDAPI int ADDCALL sass_compiler_execute(struct Sass_Compiler* compiler);
+
+// 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);
+
+// Release all memory allocated and also ourself
+ADDAPI void ADDCALL sass_delete_file_context (struct Sass_File_Context* ctx);
+ADDAPI void ADDCALL sass_delete_data_context (struct Sass_Data_Context* ctx);
+
+// Getters for context from specific implementation
+ADDAPI struct Sass_Context* ADDCALL sass_file_context_get_context (struct Sass_File_Context* file_ctx);
+ADDAPI struct Sass_Context* ADDCALL sass_data_context_get_context (struct Sass_Data_Context* data_ctx);
+
+// Getters for Context_Options from Sass_Context
+ADDAPI struct Sass_Options* ADDCALL sass_context_get_options (struct Sass_Context* ctx);
+ADDAPI struct Sass_Options* ADDCALL sass_file_context_get_options (struct Sass_File_Context* file_ctx);
+ADDAPI struct Sass_Options* ADDCALL sass_data_context_get_options (struct Sass_Data_Context* data_ctx);
+ADDAPI void ADDCALL sass_file_context_set_options (struct Sass_File_Context* file_ctx, struct Sass_Options* opt);
+ADDAPI void ADDCALL sass_data_context_set_options (struct Sass_Data_Context* data_ctx, struct Sass_Options* opt);
+
+
+// Getters for Context_Option values
+ADDAPI int ADDCALL sass_option_get_precision (struct Sass_Options* options);
+ADDAPI enum Sass_Output_Style ADDCALL sass_option_get_output_style (struct Sass_Options* options);
+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_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);
+ADDAPI const char* ADDCALL sass_option_get_linefeed (struct Sass_Options* options);
+ADDAPI const char* ADDCALL sass_option_get_input_path (struct Sass_Options* options);
+ADDAPI const char* ADDCALL sass_option_get_output_path (struct Sass_Options* options);
+ADDAPI const char* ADDCALL sass_option_get_plugin_path (struct Sass_Options* options);
+ADDAPI const char* ADDCALL sass_option_get_include_path (struct Sass_Options* options);
+ADDAPI const char* ADDCALL sass_option_get_source_map_file (struct Sass_Options* options);
+ADDAPI const char* ADDCALL sass_option_get_source_map_root (struct Sass_Options* options);
+ADDAPI Sass_Importer_List ADDCALL sass_option_get_c_headers (struct Sass_Options* options);
+ADDAPI Sass_Importer_List ADDCALL sass_option_get_c_importers (struct Sass_Options* options);
+ADDAPI Sass_Function_List ADDCALL sass_option_get_c_functions (struct Sass_Options* options);
+
+// Setters for Context_Option values
+ADDAPI void ADDCALL sass_option_set_precision (struct Sass_Options* options, int precision);
+ADDAPI void ADDCALL sass_option_set_output_style (struct Sass_Options* options, enum Sass_Output_Style output_style);
+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_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);
+ADDAPI void ADDCALL sass_option_set_linefeed (struct Sass_Options* options, const char* linefeed);
+ADDAPI void ADDCALL sass_option_set_input_path (struct Sass_Options* options, const char* input_path);
+ADDAPI void ADDCALL sass_option_set_output_path (struct Sass_Options* options, const char* output_path);
+ADDAPI void ADDCALL sass_option_set_plugin_path (struct Sass_Options* options, const char* plugin_path);
+ADDAPI void ADDCALL sass_option_set_include_path (struct Sass_Options* options, const char* include_path);
+ADDAPI void ADDCALL sass_option_set_source_map_file (struct Sass_Options* options, const char* source_map_file);
+ADDAPI void ADDCALL sass_option_set_source_map_root (struct Sass_Options* options, const char* source_map_root);
+ADDAPI void ADDCALL sass_option_set_c_headers (struct Sass_Options* options, Sass_Importer_List c_headers);
+ADDAPI void ADDCALL sass_option_set_c_importers (struct Sass_Options* options, Sass_Importer_List c_importers);
+ADDAPI void ADDCALL sass_option_set_c_functions (struct Sass_Options* options, Sass_Function_List c_functions);
+
+
+// Getters for Sass_Context values
+ADDAPI const char* ADDCALL sass_context_get_output_string (struct Sass_Context* ctx);
+ADDAPI int ADDCALL sass_context_get_error_status (struct Sass_Context* ctx);
+ADDAPI const char* ADDCALL sass_context_get_error_json (struct Sass_Context* ctx);
+ADDAPI const char* ADDCALL sass_context_get_error_text (struct Sass_Context* ctx);
+ADDAPI const char* ADDCALL sass_context_get_error_message (struct Sass_Context* ctx);
+ADDAPI const char* ADDCALL sass_context_get_error_file (struct Sass_Context* ctx);
+ADDAPI const char* ADDCALL sass_context_get_error_src (struct Sass_Context* ctx);
+ADDAPI size_t ADDCALL sass_context_get_error_line (struct Sass_Context* ctx);
+ADDAPI size_t ADDCALL sass_context_get_error_column (struct Sass_Context* ctx);
+ADDAPI const char* ADDCALL sass_context_get_source_map_string (struct Sass_Context* ctx);
+ADDAPI char** ADDCALL sass_context_get_included_files (struct Sass_Context* ctx);
+
+// Calculate the size of the stored null terminated array
+ADDAPI size_t ADDCALL sass_context_get_included_files_size (struct Sass_Context* ctx);
+
+// Take ownership of memory (value on context is set to 0)
+ADDAPI char* ADDCALL sass_context_take_error_json (struct Sass_Context* ctx);
+ADDAPI char* ADDCALL sass_context_take_error_text (struct Sass_Context* ctx);
+ADDAPI char* ADDCALL sass_context_take_error_message (struct Sass_Context* ctx);
+ADDAPI char* ADDCALL sass_context_take_error_file (struct Sass_Context* ctx);
+ADDAPI char* ADDCALL sass_context_take_output_string (struct Sass_Context* ctx);
+ADDAPI char* ADDCALL sass_context_take_source_map_string (struct Sass_Context* ctx);
+ADDAPI char** ADDCALL sass_context_take_included_files (struct Sass_Context* ctx);
+
+// Getters for Sass_Compiler options
+ADDAPI enum Sass_Compiler_State ADDCALL sass_compiler_get_state(struct Sass_Compiler* compiler);
+ADDAPI struct Sass_Context* ADDCALL sass_compiler_get_context(struct Sass_Compiler* compiler);
+ADDAPI struct Sass_Options* ADDCALL sass_compiler_get_options(struct Sass_Compiler* compiler);
+ADDAPI size_t ADDCALL sass_compiler_get_import_stack_size(struct Sass_Compiler* compiler);
+ADDAPI Sass_Import_Entry ADDCALL sass_compiler_get_last_import(struct Sass_Compiler* compiler);
+ADDAPI Sass_Import_Entry ADDCALL sass_compiler_get_import_entry(struct Sass_Compiler* compiler, size_t idx);
+
+// Push function for paths (no manipulation support for now)
+ADDAPI void ADDCALL sass_option_push_plugin_path (struct Sass_Options* options, const char* path);
+ADDAPI void ADDCALL sass_option_push_include_path (struct Sass_Options* options, const char* path);
+
+#ifdef __cplusplus
+} // __cplusplus defined.
+#endif
+
+#endif
diff --git a/libsass/include/sass/functions.h b/libsass/include/sass/functions.h
new file mode 100644
--- /dev/null
+++ b/libsass/include/sass/functions.h
@@ -0,0 +1,108 @@
+#ifndef SASS_C_FUNCTIONS_H
+#define SASS_C_FUNCTIONS_H
+
+#include <stddef.h>
+#include <stdbool.h>
+#include <sass/base.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+// Forward declaration
+struct Sass_Import;
+struct Sass_Options;
+struct Sass_Compiler;
+struct Sass_Importer;
+struct Sass_Function;
+
+// Typedef helpers for import lists
+typedef struct Sass_Import (*Sass_Import_Entry);
+typedef struct Sass_Import* (*Sass_Import_List);
+// Typedef helpers for custom importer lists
+typedef struct Sass_Importer (*Sass_Importer_Entry);
+typedef struct Sass_Importer* (*Sass_Importer_List);
+// Typedef defining importer signature and return type
+typedef Sass_Import_List (*Sass_Importer_Fn)
+  (const char* url, Sass_Importer_Entry cb, struct Sass_Compiler* compiler);
+
+// Typedef helpers for custom functions lists
+typedef struct Sass_Function (*Sass_Function_Entry);
+typedef struct Sass_Function* (*Sass_Function_List);
+// Typedef defining function signature and return type
+typedef union Sass_Value* (*Sass_Function_Fn)
+  (const union Sass_Value*, Sass_Function_Entry cb, struct Sass_Compiler* compiler);
+
+
+// Creator for sass custom importer return argument list
+ADDAPI Sass_Importer_List ADDCALL sass_make_importer_list (size_t length);
+ADDAPI Sass_Importer_Entry ADDCALL sass_importer_get_list_entry (Sass_Importer_List list, size_t idx);
+ADDAPI void ADDCALL sass_importer_set_list_entry (Sass_Importer_List list, size_t idx, Sass_Importer_Entry entry);
+
+
+// Creators for custom importer callback (with some additional pointer)
+// The pointer is mostly used to store the callback into the actual binding
+ADDAPI Sass_Importer_Entry ADDCALL sass_make_importer (Sass_Importer_Fn importer, double priority, void* cookie);
+
+// Getters for import function descriptors
+ADDAPI Sass_Importer_Fn ADDCALL sass_importer_get_function (Sass_Importer_Entry cb);
+ADDAPI double ADDCALL sass_importer_get_priority (Sass_Importer_Entry cb);
+ADDAPI void* ADDCALL sass_importer_get_cookie (Sass_Importer_Entry cb);
+
+// Deallocator for associated memory
+ADDAPI void ADDCALL sass_delete_importer (Sass_Importer_Entry cb);
+
+// Creator for sass custom importer return argument list
+ADDAPI Sass_Import_List ADDCALL sass_make_import_list (size_t length);
+// Creator for a single import entry returned by the custom importer inside the list
+ADDAPI Sass_Import_Entry ADDCALL sass_make_import_entry (const char* path, char* source, char* srcmap);
+ADDAPI Sass_Import_Entry ADDCALL sass_make_import (const char* imp_path, const char* abs_base, char* source, char* srcmap);
+// set error message to abort import and to print out a message (path from existing object is used in output)
+ADDAPI Sass_Import_Entry ADDCALL sass_import_set_error(Sass_Import_Entry import, const char* message, size_t line, size_t col);
+
+// Setters to insert an entry into the import list (you may also use [] access directly)
+// Since we are dealing with pointers they should have a guaranteed and fixed size
+ADDAPI void ADDCALL sass_import_set_list_entry (Sass_Import_List list, size_t idx, Sass_Import_Entry entry);
+ADDAPI Sass_Import_Entry ADDCALL sass_import_get_list_entry (Sass_Import_List list, size_t idx);
+
+// Getters for import entry
+ADDAPI const char* ADDCALL sass_import_get_imp_path (Sass_Import_Entry);
+ADDAPI const char* ADDCALL sass_import_get_abs_path (Sass_Import_Entry);
+ADDAPI const char* ADDCALL sass_import_get_source (Sass_Import_Entry);
+ADDAPI const char* ADDCALL sass_import_get_srcmap (Sass_Import_Entry);
+// Explicit functions to take ownership of these items
+// The property on our struct will be reset to NULL
+ADDAPI char* ADDCALL sass_import_take_source (Sass_Import_Entry);
+ADDAPI char* ADDCALL sass_import_take_srcmap (Sass_Import_Entry);
+// Getters from import error entry
+ADDAPI size_t ADDCALL sass_import_get_error_line (Sass_Import_Entry);
+ADDAPI size_t ADDCALL sass_import_get_error_column (Sass_Import_Entry);
+ADDAPI const char* ADDCALL sass_import_get_error_message (Sass_Import_Entry);
+
+// Deallocator for associated memory (incl. entries)
+ADDAPI void ADDCALL sass_delete_import_list (Sass_Import_List);
+// Just in case we have some stray import structs
+ADDAPI void ADDCALL sass_delete_import (Sass_Import_Entry);
+
+
+
+// Creators for sass function list and function descriptors
+ADDAPI Sass_Function_List ADDCALL sass_make_function_list (size_t length);
+ADDAPI Sass_Function_Entry ADDCALL sass_make_function (const char* signature, Sass_Function_Fn cb, void* cookie);
+
+// Setters and getters for callbacks on function lists
+ADDAPI Sass_Function_Entry ADDCALL sass_function_get_list_entry(Sass_Function_List list, size_t pos);
+ADDAPI void ADDCALL sass_function_set_list_entry(Sass_Function_List list, size_t pos, Sass_Function_Entry cb);
+
+// Getters for custom function descriptors
+ADDAPI const char* ADDCALL sass_function_get_signature (Sass_Function_Entry cb);
+ADDAPI Sass_Function_Fn ADDCALL sass_function_get_function (Sass_Function_Entry cb);
+ADDAPI void* ADDCALL sass_function_get_cookie (Sass_Function_Entry cb);
+
+
+#ifdef __cplusplus
+} // __cplusplus defined.
+#endif
+
+#endif
diff --git a/libsass/include/sass/interface.h b/libsass/include/sass/interface.h
new file mode 100644
--- /dev/null
+++ b/libsass/include/sass/interface.h
@@ -0,0 +1,105 @@
+#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
new file mode 100644
--- /dev/null
+++ b/libsass/include/sass/values.h
@@ -0,0 +1,141 @@
+#ifndef SASS_C_VALUES_H
+#define SASS_C_VALUES_H
+
+#include <stddef.h>
+#include <stdbool.h>
+#include <sass/base.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+// Forward declaration
+union Sass_Value;
+
+// Type for Sass values
+enum Sass_Tag {
+  SASS_BOOLEAN,
+  SASS_NUMBER,
+  SASS_COLOR,
+  SASS_STRING,
+  SASS_LIST,
+  SASS_MAP,
+  SASS_NULL,
+  SASS_ERROR,
+  SASS_WARNING
+};
+
+// Tags for denoting Sass list separators
+enum Sass_Separator {
+  SASS_COMMA,
+  SASS_SPACE
+};
+
+// Value Operators
+enum Sass_OP {
+  AND, OR,                   // logical connectives
+  EQ, NEQ, GT, GTE, LT, LTE, // arithmetic relations
+  ADD, SUB, MUL, DIV, MOD,   // arithmetic functions
+  NUM_OPS                    // so we know how big to make the op table
+};
+
+// 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);
+
+// Check value to be of a specific type
+// Can also be used before accessing properties!
+ADDAPI bool ADDCALL sass_value_is_null (const union Sass_Value* v);
+ADDAPI bool ADDCALL sass_value_is_number (const union Sass_Value* v);
+ADDAPI bool ADDCALL sass_value_is_string (const union Sass_Value* v);
+ADDAPI bool ADDCALL sass_value_is_boolean (const union Sass_Value* v);
+ADDAPI bool ADDCALL sass_value_is_color (const union Sass_Value* v);
+ADDAPI bool ADDCALL sass_value_is_list (const union Sass_Value* v);
+ADDAPI bool ADDCALL sass_value_is_map (const union Sass_Value* v);
+ADDAPI bool ADDCALL sass_value_is_error (const union Sass_Value* v);
+ADDAPI bool ADDCALL sass_value_is_warning (const union Sass_Value* v);
+
+// Getters and setters for Sass_Number
+ADDAPI double ADDCALL sass_number_get_value (const union Sass_Value* v);
+ADDAPI void ADDCALL sass_number_set_value (union Sass_Value* v, double value);
+ADDAPI const char* ADDCALL sass_number_get_unit (const union Sass_Value* v);
+ADDAPI void ADDCALL sass_number_set_unit (union Sass_Value* v, char* unit);
+
+// Getters and setters for Sass_String
+ADDAPI const char* ADDCALL sass_string_get_value (const union Sass_Value* v);
+ADDAPI void ADDCALL sass_string_set_value (union Sass_Value* v, char* value);
+ADDAPI bool ADDCALL sass_string_is_quoted(const union Sass_Value* v);
+ADDAPI void ADDCALL sass_string_set_quoted(union Sass_Value* v, bool quoted);
+
+// Getters and setters for Sass_Boolean
+ADDAPI bool ADDCALL sass_boolean_get_value (const union Sass_Value* v);
+ADDAPI void ADDCALL sass_boolean_set_value (union Sass_Value* v, bool value);
+
+// Getters and setters for Sass_Color
+ADDAPI double ADDCALL sass_color_get_r (const union Sass_Value* v);
+ADDAPI void ADDCALL sass_color_set_r (union Sass_Value* v, double r);
+ADDAPI double ADDCALL sass_color_get_g (const union Sass_Value* v);
+ADDAPI void ADDCALL sass_color_set_g (union Sass_Value* v, double g);
+ADDAPI double ADDCALL sass_color_get_b (const union Sass_Value* v);
+ADDAPI void ADDCALL sass_color_set_b (union Sass_Value* v, double b);
+ADDAPI double ADDCALL sass_color_get_a (const union Sass_Value* v);
+ADDAPI void ADDCALL sass_color_set_a (union Sass_Value* v, double a);
+
+// Getter for the number of items in list
+ADDAPI size_t ADDCALL sass_list_get_length (const union Sass_Value* v);
+// Getters and setters for Sass_List
+ADDAPI enum Sass_Separator ADDCALL sass_list_get_separator (const union Sass_Value* v);
+ADDAPI void ADDCALL sass_list_set_separator (union Sass_Value* v, enum Sass_Separator value);
+// Getters and setters for Sass_List values
+ADDAPI union Sass_Value* ADDCALL sass_list_get_value (const union Sass_Value* v, size_t i);
+ADDAPI void ADDCALL sass_list_set_value (union Sass_Value* v, size_t i, union Sass_Value* value);
+
+// Getter for the number of items in map
+ADDAPI size_t ADDCALL sass_map_get_length (const union Sass_Value* v);
+// Getters and setters for Sass_Map keys and values
+ADDAPI union Sass_Value* ADDCALL sass_map_get_key (const union Sass_Value* v, size_t i);
+ADDAPI void ADDCALL sass_map_set_key (union Sass_Value* v, size_t i, union Sass_Value*);
+ADDAPI union Sass_Value* ADDCALL sass_map_get_value (const union Sass_Value* v, size_t i);
+ADDAPI void ADDCALL sass_map_set_value (union Sass_Value* v, size_t i, union Sass_Value*);
+
+// Getters and setters for Sass_Error
+ADDAPI char* ADDCALL sass_error_get_message (const union Sass_Value* v);
+ADDAPI void ADDCALL sass_error_set_message (union Sass_Value* v, char* msg);
+
+// 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.
+#endif
+
+#endif
diff --git a/libsass/include/sass/version.h b/libsass/include/sass/version.h
new file mode 100644
--- /dev/null
+++ b/libsass/include/sass/version.h
@@ -0,0 +1,8 @@
+#ifndef SASS_VERSION_H
+#define SASS_VERSION_H
+
+#ifndef LIBSASS_VERSION
+#define LIBSASS_VERSION "[NA]"
+#endif
+
+#endif
diff --git a/libsass/include/sass/version.h.in b/libsass/include/sass/version.h.in
new file mode 100644
--- /dev/null
+++ b/libsass/include/sass/version.h.in
@@ -0,0 +1,8 @@
+#ifndef SASS_VERSION_H
+#define SASS_VERSION_H
+
+#ifndef LIBSASS_VERSION
+#define LIBSASS_VERSION "@PACKAGE_VERSION@"
+#endif
+
+#endif
diff --git a/libsass/include/sass2scss.h b/libsass/include/sass2scss.h
new file mode 100644
--- /dev/null
+++ b/libsass/include/sass2scss.h
@@ -0,0 +1,120 @@
+/**
+ * sass2scss
+ * Licensed under the MIT License
+ * Copyright (c) Marcel Greter
+ */
+
+#ifndef SASS2SCSS_H
+#define SASS2SCSS_H
+
+#ifdef _WIN32
+
+  /* You should define ADD_EXPORTS *only* when building the DLL. */
+  #ifdef ADD_EXPORTS
+    #define ADDAPI __declspec(dllexport)
+	#define ADDCALL __cdecl
+  #else
+    #define ADDAPI
+	#define ADDCALL
+  #endif
+
+#else /* _WIN32 not defined. */
+
+  /* Define with no value on non-Windows OSes. */
+  #define ADDAPI
+  #define ADDCALL
+
+#endif
+
+#ifdef __cplusplus
+
+#include <stack>
+#include <string>
+#include <cstring>
+#include <sstream>
+#include <iostream>
+
+#ifndef SASS2SCSS_VERSION
+// Hardcode once the file is copied from
+// https://github.com/mgreter/sass2scss
+#define SASS2SCSS_VERSION "1.0.5"
+#endif
+
+// add namespace for c++
+namespace Sass
+{
+
+	// pretty print options
+	const int SASS2SCSS_PRETTIFY_0 = 0;
+	const int SASS2SCSS_PRETTIFY_1 = 1;
+	const int SASS2SCSS_PRETTIFY_2 = 2;
+	const int SASS2SCSS_PRETTIFY_3 = 3;
+
+	// remove one-line comment
+	const int SASS2SCSS_KEEP_COMMENT    =  32;
+	// remove multi-line comments
+	const int SASS2SCSS_STRIP_COMMENT   =  64;
+	// convert one-line to multi-line
+	const int SASS2SCSS_CONVERT_COMMENT = 128;
+
+	// String for finding something interesting
+	const std::string SASS2SCSS_FIND_WHITESPACE = " \t\n\v\f\r";
+
+	// converter struct
+	// holding all states
+	struct converter
+	{
+		// bit options
+		int options;
+		// is selector
+		bool selector;
+		// concat lists
+		bool comma;
+		// has property
+		bool property;
+		// has semicolon
+		bool semicolon;
+		// comment context
+		std::string comment;
+		// flag end of file
+		bool end_of_file;
+		// whitespace buffer
+		std::string whitespace;
+		// context/block stack
+		std::stack<std::string> indents;
+	};
+
+	// function only available in c++ code
+	char* sass2scss (const std::string& sass, const int options);
+
+}
+// EO namespace
+
+// declare for c
+extern "C" {
+#endif
+
+	// prettyfy print options
+	#define SASS2SCSS_PRETTIFY_0   0
+	#define SASS2SCSS_PRETTIFY_1   1
+	#define SASS2SCSS_PRETTIFY_2   2
+	#define SASS2SCSS_PRETTIFY_3   3
+
+	// keep one-line comments
+	#define SASS2SCSS_KEEP_COMMENT     32
+	// remove multi-line comments
+	#define SASS2SCSS_STRIP_COMMENT    64
+	// convert one-line to multi-line
+	#define SASS2SCSS_CONVERT_COMMENT  128
+
+	// available to c and c++ code
+	ADDAPI char* ADDCALL sass2scss (const char* sass, const int options);
+
+	// Get compiled sass2scss version
+	ADDAPI const char* ADDCALL sass2scss_version(void);
+
+#ifdef __cplusplus
+} // __cplusplus defined.
+#endif
+
+#endif
diff --git a/libsass/inspect.cpp b/libsass/inspect.cpp
deleted file mode 100644
--- a/libsass/inspect.cpp
+++ /dev/null
@@ -1,945 +0,0 @@
-#include <cmath>
-#include <string>
-#include <iostream>
-#include <iomanip>
-#include <stdint.h>
-#include <stdint.h>
-
-#include "ast.hpp"
-#include "inspect.hpp"
-#include "context.hpp"
-#include "utf8/checked.h"
-
-namespace Sass {
-  using namespace std;
-
-  Inspect::Inspect(Emitter emi)
-  : Emitter(emi)
-  { }
-  Inspect::~Inspect() { }
-
-  // statements
-  void Inspect::operator()(Block* block)
-  {
-    if (!block->is_root()) {
-      add_open_mapping(block);
-      append_scope_opener();
-    }
-    if (output_style() == NESTED) indentation += block->tabs();
-    for (size_t i = 0, L = block->length(); i < L; ++i) {
-      (*block)[i]->perform(this);
-    }
-    if (output_style() == NESTED) indentation -= block->tabs();
-    if (!block->is_root()) {
-      append_scope_closer();
-      add_close_mapping(block);
-    }
-
-  }
-
-  void Inspect::operator()(Ruleset* ruleset)
-  {
-    ruleset->selector()->perform(this);
-    ruleset->block()->perform(this);
-  }
-
-  void Inspect::operator()(Keyframe_Rule* rule)
-  {
-    if (rule->selector()) rule->selector()->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)
-  {
-    append_indentation();
-    append_token("::BUBBLE", bubble);
-    append_scope_opener();
-    bubble->node()->perform(this);
-    append_scope_closer();
-  }
-
-  void Inspect::operator()(Media_Block* media_block)
-  {
-    append_indentation();
-    append_token("@media", media_block);
-    append_mandatory_space();
-    in_media_block = true;
-    media_block->media_queries()->perform(this);
-    in_media_block = false;
-    media_block->block()->perform(this);
-  }
-
-  void Inspect::operator()(Feature_Block* feature_block)
-  {
-    append_indentation();
-    append_token("@supports", feature_block);
-    append_mandatory_space();
-    feature_block->feature_queries()->perform(this);
-    feature_block->block()->perform(this);
-  }
-
-  void Inspect::operator()(At_Root_Block* at_root_block)
-  {
-    append_indentation();
-    append_token("@at-root ", at_root_block);
-    append_mandatory_space();
-    if(at_root_block->expression()) at_root_block->expression()->perform(this);
-    at_root_block->block()->perform(this);
-  }
-
-  void Inspect::operator()(At_Rule* at_rule)
-  {
-    append_indentation();
-    append_token(at_rule->keyword(), at_rule);
-    if (at_rule->selector()) {
-      append_mandatory_space();
-      bool was_wrapped = in_wrapped;
-      in_wrapped = true;
-      at_rule->selector()->perform(this);
-      in_wrapped = was_wrapped;
-    }
-    if (at_rule->block()) {
-      at_rule->block()->perform(this);
-    }
-    else {
-      append_delimiter();
-    }
-  }
-
-  void Inspect::operator()(Declaration* dec)
-  {
-    if (dec->value()->concrete_type() == Expression::NULL_VAL) return;
-    bool was_decl = in_declaration;
-    in_declaration = true;
-    if (output_style() == NESTED)
-      indentation += dec->tabs();
-    append_indentation();
-    dec->property()->perform(this);
-    append_colon_separator();
-    dec->value()->perform(this);
-    if (dec->is_important()) {
-      append_optional_space();
-      append_string("!important");
-    }
-    append_delimiter();
-    if (output_style() == NESTED)
-      indentation -= dec->tabs();
-    in_declaration = was_decl;
-  }
-
-  void Inspect::operator()(Assignment* assn)
-  {
-    append_token(assn->variable(), assn);
-    append_colon_separator();
-    assn->value()->perform(this);
-    if (assn->is_default()) {
-      append_optional_space();
-      append_string("!default");
-    }
-    append_delimiter();
-  }
-
-  void Inspect::operator()(Import* 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);
-      append_delimiter();
-      for (size_t i = 1, S = import->urls().size(); i < S; ++i) {
-        append_mandatory_linefeed();
-        append_token("@import", import);
-        append_mandatory_space();
-
-        if (String_Quoted* strq = dynamic_cast<String_Quoted*>(import->urls()[i])) {
-          strq->is_delayed(false);
-        }
-
-        import->urls()[i]->perform(this);
-        append_delimiter();
-      }
-    }
-  }
-
-  void Inspect::operator()(Import_Stub* import)
-  {
-    append_indentation();
-    append_token("@import", import);
-    append_mandatory_space();
-    append_string(import->file_name());
-    append_delimiter();
-  }
-
-  void Inspect::operator()(Warning* warning)
-  {
-    append_indentation();
-    append_token("@warn", warning);
-    append_mandatory_space();
-    warning->message()->perform(this);
-    append_delimiter();
-  }
-
-  void Inspect::operator()(Error* error)
-  {
-    append_indentation();
-    append_token("@error", error);
-    append_mandatory_space();
-    error->message()->perform(this);
-    append_delimiter();
-  }
-
-  void Inspect::operator()(Debug* debug)
-  {
-    append_indentation();
-    append_token("@debug", debug);
-    append_mandatory_space();
-    debug->value()->perform(this);
-    append_delimiter();
-  }
-
-  void Inspect::operator()(Comment* comment)
-  {
-    in_comment = true;
-    comment->text()->perform(this);
-    in_comment = false;
-  }
-
-  void Inspect::operator()(If* cond)
-  {
-    append_indentation();
-    append_token("@if", cond);
-    append_mandatory_space();
-    cond->predicate()->perform(this);
-    cond->consequent()->perform(this);
-    if (cond->alternative()) {
-      append_optional_linefeed();
-      append_indentation();
-      append_string("else");
-      cond->alternative()->perform(this);
-    }
-  }
-
-  void Inspect::operator()(For* loop)
-  {
-    append_indentation();
-    append_token("@for", loop);
-    append_mandatory_space();
-    append_string(loop->variable());
-    append_string(" from ");
-    loop->lower_bound()->perform(this);
-    append_string(loop->is_inclusive() ? " through " : " to ");
-    loop->upper_bound()->perform(this);
-    loop->block()->perform(this);
-  }
-
-  void Inspect::operator()(Each* loop)
-  {
-    append_indentation();
-    append_token("@each", loop);
-    append_mandatory_space();
-    append_string(loop->variables()[0]);
-    for (size_t i = 1, L = loop->variables().size(); i < L; ++i) {
-      append_comma_separator();
-      append_string(loop->variables()[i]);
-    }
-    append_string(" in ");
-    loop->list()->perform(this);
-    loop->block()->perform(this);
-  }
-
-  void Inspect::operator()(While* loop)
-  {
-    append_indentation();
-    append_token("@while", loop);
-    append_mandatory_space();
-    loop->predicate()->perform(this);
-    loop->block()->perform(this);
-  }
-
-  void Inspect::operator()(Return* ret)
-  {
-    append_indentation();
-    append_token("@return", ret);
-    append_mandatory_space();
-    ret->value()->perform(this);
-    append_delimiter();
-  }
-
-  void Inspect::operator()(Extension* extend)
-  {
-    append_indentation();
-    append_token("@extend", extend);
-    append_mandatory_space();
-    extend->selector()->perform(this);
-    append_delimiter();
-  }
-
-  void Inspect::operator()(Definition* def)
-  {
-    append_indentation();
-    if (def->type() == Definition::MIXIN) {
-      append_token("@mixin", def);
-      append_mandatory_space();
-    } else {
-      append_token("@function", def);
-      append_mandatory_space();
-    }
-    append_string(def->name());
-    def->parameters()->perform(this);
-    def->block()->perform(this);
-  }
-
-  void Inspect::operator()(Mixin_Call* call)
-  {
-    append_indentation();
-    append_token("@include", call);
-    append_mandatory_space();
-    append_string(call->name());
-    if (call->arguments()) {
-      call->arguments()->perform(this);
-    }
-    if (call->block()) {
-      append_optional_space();
-      call->block()->perform(this);
-    }
-    if (!call->block()) append_delimiter();
-  }
-
-  void Inspect::operator()(Content* content)
-  {
-    append_indentation();
-    append_token("@content", content);
-    append_delimiter();
-  }
-
-  void Inspect::operator()(Map* map)
-  {
-    if (map->empty()) return;
-    if (map->is_invisible()) return;
-    bool items_output = false;
-    append_string("(");
-    for (auto key : map->keys()) {
-      if (key->is_invisible()) continue;
-      if (map->at(key)->is_invisible()) continue;
-      if (items_output) append_comma_separator();
-      key->perform(this);
-      append_colon_separator();
-      map->at(key)->perform(this);
-      items_output = true;
-    }
-    append_string(")");
-  }
-
-  void Inspect::operator()(List* list)
-  {
-    string sep(list->separator() == List::SPACE ? " " : ",");
-    if (output_style() != COMPRESSED && sep == ",") sep += " ";
-    else if (in_media_block && sep != " ") sep += " "; // verified
-    if (list->empty()) return;
-    bool items_output = false;
-
-    bool was_space_array = in_space_array;
-    bool was_comma_array = in_comma_array;
-    if (!in_declaration && (
-        (list->separator() == List::SPACE && in_space_array) ||
-        (list->separator() == List::COMMA && in_comma_array)
-    )) {
-      append_string("(");
-    }
-
-    if (list->separator() == List::SPACE) in_space_array = true;
-    else if (list->separator() == List::COMMA) in_comma_array = true;
-
-    for (size_t i = 0, L = list->size(); i < L; ++i) {
-      Expression* list_item = (*list)[i];
-      if (list_item->is_invisible()) {
-        continue;
-      }
-      if (items_output) {
-        append_string(sep);
-      }
-      if (items_output && sep != " ")
-        append_optional_space();
-      list_item->perform(this);
-      items_output = true;
-    }
-
-    in_comma_array = was_comma_array;
-    in_space_array = was_space_array;
-    if (!in_declaration && (
-        (list->separator() == List::SPACE && in_space_array) ||
-        (list->separator() == List::COMMA && in_comma_array)
-    )) {
-      append_string(")");
-    }
-
-  }
-
-  void Inspect::operator()(Binary_Expression* expr)
-  {
-    expr->left()->perform(this);
-    switch (expr->type()) {
-      case Binary_Expression::AND: append_string(" and "); break;
-      case Binary_Expression::OR:  append_string(" or ");  break;
-      case Binary_Expression::EQ:  append_string(" == ");  break;
-      case Binary_Expression::NEQ: append_string(" != ");  break;
-      case Binary_Expression::GT:  append_string(" > ");   break;
-      case Binary_Expression::GTE: append_string(" >= ");  break;
-      case Binary_Expression::LT:  append_string(" < ");   break;
-      case Binary_Expression::LTE: append_string(" <= ");  break;
-      case Binary_Expression::ADD: append_string(" + ");   break;
-      case Binary_Expression::SUB: append_string(" - ");   break;
-      case Binary_Expression::MUL: append_string(" * ");   break;
-      case Binary_Expression::DIV: append_string("/");     break;
-      case Binary_Expression::MOD: append_string(" % ");   break;
-      default: break; // shouldn't get here
-    }
-    expr->right()->perform(this);
-  }
-
-  void Inspect::operator()(Unary_Expression* expr)
-  {
-    if (expr->type() == Unary_Expression::PLUS) append_string("+");
-    else                                        append_string("-");
-    expr->operand()->perform(this);
-  }
-
-  void Inspect::operator()(Function_Call* call)
-  {
-    append_token(call->name(), call);
-    call->arguments()->perform(this);
-  }
-
-  void Inspect::operator()(Function_Call_Schema* call)
-  {
-    call->name()->perform(this);
-    call->arguments()->perform(this);
-  }
-
-  void Inspect::operator()(Variable* var)
-  {
-    append_token(var->name(), var);
-  }
-
-  void Inspect::operator()(Textual* txt)
-  {
-    append_token(txt->value(), txt);
-  }
-
-  void Inspect::operator()(Number* n)
-  {
-
-    string res;
-
-    // init stuff
-    n->normalize();
-    int precision = 5;
-    double value = n->value();
-    // get option from optional context
-    if (ctx) precision = ctx->precision;
-
-    // check if the fractional part of the value equals to zero
-    // neat trick from http://stackoverflow.com/a/1521682/1550314
-    // double int_part; bool is_int = modf(value, &int_part) == 0.0;
-
-    // this all cannot be done with one run only, since fixed
-    // output differs from normal output and regular output
-    // can contain scientific notation which we do not want!
-
-    // first sample
-    stringstream ss;
-    ss.precision(12);
-    ss << value;
-
-    // check if we got scientific notation in result
-    if (ss.str().find_first_of("e") != string::npos) {
-      ss.clear(); ss.str(string());
-      ss.precision(max(12, precision));
-      ss << fixed << value;
-    }
-
-    string tmp = ss.str();
-    size_t pos_point = tmp.find_first_of(".,");
-    size_t pos_fract = tmp.find_last_not_of("0");
-    bool is_int = pos_point == pos_fract ||
-                  pos_point == string::npos;
-
-    // reset stream for another run
-    ss.clear(); ss.str(string());
-
-    // take a shortcut for integers
-    if (is_int)
-    {
-      ss.precision(0);
-      ss << fixed << value;
-      res = string(ss.str());
-    }
-    // process floats
-    else
-    {
-      // do we have have too much precision?
-      if (pos_fract < precision + pos_point)
-      { precision = pos_fract - pos_point; }
-      // round value again
-      ss.precision(precision);
-      ss << fixed << value;
-      res = string(ss.str());
-      // maybe we truncated up to decimal point
-      size_t pos = res.find_last_not_of("0");
-      bool at_dec_point = res[pos] == '.' ||
-                          res[pos] == ',';
-      // don't leave a blank point
-      if (at_dec_point) ++ pos;
-      res.resize (pos + 1);
-    }
-
-    // some final cosmetics
-    if (res == "-0.0") res.erase(0, 1);
-    else if (res == "-0") res.erase(0, 1);
-
-    // add unit now
-    res += n->unit();
-
-    // check for a valid unit here
-    // includes result for reporting
-    if (n->numerator_units().size() > 1 ||
-        n->denominator_units().size() > 0 ||
-        (n->numerator_units().size() && n->numerator_units()[0].find_first_of('/') != string::npos) ||
-        (n->numerator_units().size() && n->numerator_units()[0].find_first_of('*') != string::npos)
-    ) {
-      error(res + " isn't a valid CSS value.", n->pstate());
-    }
-
-    // output the final token
-    append_token(res, n);
-
-  }
-
-  // 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* c)
-  {
-    stringstream ss;
-
-    // check if we prefer short hex colors
-    bool want_short = output_style() == COMPRESSED;
-
-    // original color name
-    // maybe an unknown token
-    string name = c->disp();
-
-    // resolved color
-    string res_name = name;
-
-    double r = round(cap_channel<0xff>(c->r()));
-    double g = round(cap_channel<0xff>(c->g()));
-    double b = round(cap_channel<0xff>(c->b()));
-    double a = cap_channel<1>   (c->a());
-
-    // get color from given name (if one was given at all)
-    if (name != "" && ctx && ctx->names_to_colors.count(name)) {
-      Color* n = ctx->names_to_colors[name];
-      r = round(cap_channel<0xff>(n->r()));
-      g = round(cap_channel<0xff>(n->g()));
-      b = round(cap_channel<0xff>(n->b()));
-      a = cap_channel<1>   (n->a());
-    }
-    // otherwise get the possible resolved color name
-    else {
-      int numval = static_cast<int>(r) * 0x10000 + static_cast<int>(g) * 0x100 + static_cast<int>(b);
-      if (ctx && ctx->colors_to_names.count(numval))
-        res_name = ctx->colors_to_names[numval];
-    }
-
-    stringstream hexlet;
-    hexlet << '#' << setw(1) << setfill('0');
-    // create a short color hexlet if there is any need for it
-    if (want_short && is_color_doublet(r, g, b) && a == 1) {
-      hexlet << hex << setw(1) << (static_cast<unsigned long>(r) >> 4);
-      hexlet << hex << setw(1) << (static_cast<unsigned long>(g) >> 4);
-      hexlet << hex << setw(1) << (static_cast<unsigned long>(b) >> 4);
-    } else {
-      hexlet << hex << setw(2) << static_cast<unsigned long>(r);
-      hexlet << hex << setw(2) << static_cast<unsigned long>(g);
-      hexlet << hex << setw(2) << static_cast<unsigned long>(b);
-    }
-
-    // retain the originally specified color definition if unchanged
-    if (name != "") {
-      ss << name;
-    }
-    else if (r == 0 && g == 0 && b == 0 && a == 0) {
-        ss << "transparent";
-    }
-    else if (a >= 1) {
-      if (res_name != "") {
-        if (want_short && 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 (output_style() != COMPRESSED) ss << " ";
-      ss << static_cast<unsigned long>(g) << ",";
-      if (output_style() != COMPRESSED) ss << " ";
-      ss << static_cast<unsigned long>(b) << ",";
-      if (output_style() != COMPRESSED) ss << " ";
-      ss << a << ')';
-    }
-    append_token(ss.str(), c);
-  }
-
-  void Inspect::operator()(Boolean* b)
-  {
-    append_token(b->value() ? "true" : "false", b);
-  }
-
-  void Inspect::operator()(String_Schema* ss)
-  {
-    // Evaluation should turn these into String_Constants, so this method is
-    // only for inspection purposes.
-    for (size_t i = 0, L = ss->length(); i < L; ++i) {
-      if ((*ss)[i]->is_interpolant()) append_string("#{");
-      (*ss)[i]->perform(this);
-      if ((*ss)[i]->is_interpolant()) append_string("}");
-    }
-  }
-
-  void Inspect::operator()(String_Constant* s)
-  {
-    if (String_Quoted* quoted = dynamic_cast<String_Quoted*>(s)) {
-      return Inspect::operator()(quoted);
-    }
-    append_token(s->value(), s);
-  }
-
-  void Inspect::operator()(String_Quoted* s)
-  {
-    if (s->quote_mark()) {
-      append_token(quote(s->value(), s->quote_mark(), true), s);
-    } else {
-      append_token(s->value(), s);
-    }
-  }
-
-  void Inspect::operator()(Feature_Query* fq)
-  {
-    size_t i = 0;
-    (*fq)[i++]->perform(this);
-    for (size_t L = fq->length(); i < L; ++i) {
-      (*fq)[i]->perform(this);
-    }
-  }
-
-  void Inspect::operator()(Feature_Query_Condition* fqc)
-  {
-    if (fqc->operand() == Feature_Query_Condition::AND) {
-      append_mandatory_space();
-      append_token("and", fqc);
-      append_mandatory_space();
-    } else if (fqc->operand() == Feature_Query_Condition::OR) {
-      append_mandatory_space();
-      append_token("or", fqc);
-      append_mandatory_space();
-    } else if (fqc->operand() == Feature_Query_Condition::NOT) {
-      append_mandatory_space();
-      append_token("not", fqc);
-      append_mandatory_space();
-    }
-
-    if (!fqc->is_root()) append_string("(");
-
-    if (!fqc->length()) {
-      fqc->feature()->perform(this);
-      append_string(": "); // verified
-      fqc->value()->perform(this);
-    }
-    for (size_t i = 0, L = fqc->length(); i < L; ++i)
-      (*fqc)[i]->perform(this);
-
-    if (!fqc->is_root()) append_string(")");
-  }
-
-  void Inspect::operator()(Media_Query* mq)
-  {
-    size_t i = 0;
-    if (mq->media_type()) {
-      if      (mq->is_negated())    append_string("not ");
-      else if (mq->is_restricted()) append_string("only ");
-      mq->media_type()->perform(this);
-    }
-    else {
-      (*mq)[i++]->perform(this);
-    }
-    for (size_t L = mq->length(); i < L; ++i) {
-      append_string(" and ");
-      (*mq)[i]->perform(this);
-    }
-  }
-
-  void Inspect::operator()(Media_Query_Expression* mqe)
-  {
-    if (mqe->is_interpolated()) {
-      mqe->feature()->perform(this);
-    }
-    else {
-      append_string("(");
-      mqe->feature()->perform(this);
-      if (mqe->value()) {
-        append_string(": "); // verified
-        mqe->value()->perform(this);
-      }
-      append_string(")");
-    }
-  }
-
-  void Inspect::operator()(At_Root_Expression* 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(")");
-    }
-  }
-
-  void Inspect::operator()(Null* n)
-  {
-    append_token("null", n);
-  }
-
-  void Inspect::operator()(Parent_Selector* p)
-  {
-    if (p->selector()) {
-      p->selector()->perform(this);
-      append_delimiter();
-    }
-    else {
-      append_string("&");
-    }
-  }
-
-  // parameters and arguments
-  void Inspect::operator()(Parameter* p)
-  {
-    append_token(p->name(), p);
-    if (p->default_value()) {
-      append_colon_separator();
-      p->default_value()->perform(this);
-    }
-    else if (p->is_rest_parameter()) {
-      append_string("...");
-    }
-  }
-
-  void Inspect::operator()(Parameters* p)
-  {
-    append_string("(");
-    if (!p->empty()) {
-      (*p)[0]->perform(this);
-      for (size_t i = 1, L = p->length(); i < L; ++i) {
-        append_comma_separator();
-        (*p)[i]->perform(this);
-      }
-    }
-    append_string(")");
-  }
-
-  void Inspect::operator()(Argument* a)
-  {
-    if (!a->name().empty()) {
-      append_token(a->name(), a);
-      append_colon_separator();
-    }
-    // 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);
-    if (a->is_rest_argument()) {
-      append_string("...");
-    }
-  }
-
-  void Inspect::operator()(Arguments* a)
-  {
-    append_string("(");
-    if (!a->empty()) {
-      (*a)[0]->perform(this);
-      for (size_t i = 1, L = a->length(); i < L; ++i) {
-        append_string(", "); // verified
-        // Sass Bug? append_comma_separator();
-        (*a)[i]->perform(this);
-      }
-    }
-    append_string(")");
-  }
-
-  void Inspect::operator()(Selector_Schema* s)
-  {
-    s->contents()->perform(this);
-  }
-
-  void Inspect::operator()(Selector_Reference* ref)
-  {
-    if (ref->selector()) ref->selector()->perform(this);
-    else                 append_string("&");
-  }
-
-  void Inspect::operator()(Selector_Placeholder* s)
-  {
-    append_token(s->name(), s);
-    if (s->has_line_break()) append_optional_linefeed();
-    if (s->has_line_break()) append_indentation();
-
-  }
-
-  void Inspect::operator()(Type_Selector* s)
-  {
-    append_token(s->name(), s);
-  }
-
-  void Inspect::operator()(Selector_Qualifier* s)
-  {
-    append_token(s->name(), s);
-    if (s->has_line_break()) append_optional_linefeed();
-    if (s->has_line_break()) append_indentation();
-  }
-
-  void Inspect::operator()(Attribute_Selector* s)
-  {
-    append_string("[");
-    add_open_mapping(s);
-    append_token(s->name(), s);
-    if (!s->matcher().empty()) {
-      append_string(s->matcher());
-      if (s->value()) {
-        s->value()->perform(this);
-      }
-    }
-    add_close_mapping(s);
-    append_string("]");
-  }
-
-  void Inspect::operator()(Pseudo_Selector* s)
-  {
-    append_token(s->name(), s);
-    if (s->expression()) {
-      s->expression()->perform(this);
-      append_string(")");
-    }
-  }
-
-  void Inspect::operator()(Wrapped_Selector* s)
-  {
-    bool was = in_wrapped;
-    in_wrapped = true;
-    append_token(s->name(), s);
-    s->selector()->perform(this);
-    append_string(")");
-    in_wrapped = was;
-  }
-
-  void Inspect::operator()(Compound_Selector* s)
-  {
-    for (size_t i = 0, L = s->length(); i < L; ++i) {
-      (*s)[i]->perform(this);
-    }
-    if (s->has_line_break()) {
-      append_optional_linefeed();
-    }
-  }
-
-  void Inspect::operator()(Complex_Selector* c)
-  {
-    Compound_Selector*           head = c->head();
-    Complex_Selector*            tail = c->tail();
-    Complex_Selector::Combinator comb = c->combinator();
-    if (head && !head->is_empty_reference()) head->perform(this);
-    bool is_empty = head && head->is_empty_reference();
-    bool is_tail = head && !head->is_empty_reference() && tail;
-    if (output_style() == COMPRESSED && comb != Complex_Selector::ANCESTOR_OF) scheduled_space = 0;
-
-    switch (comb) {
-      case Complex_Selector::ANCESTOR_OF:
-        if (is_tail) append_mandatory_space();
-      break;
-      case Complex_Selector::PARENT_OF:
-        append_optional_space();
-        append_string(">");
-        append_optional_space();
-      break;
-      case Complex_Selector::ADJACENT_TO:
-        append_optional_space();
-        append_string("+");
-        append_optional_space();
-      break;
-      case Complex_Selector::PRECEDES:
-        if (is_empty) append_optional_space();
-        else append_mandatory_space();
-        append_string("~");
-        if (tail) append_mandatory_space();
-        else append_optional_space();
-      break;
-    }
-    if (tail && comb != Complex_Selector::ANCESTOR_OF) {
-      if (c->has_line_break()) append_optional_linefeed();
-    }
-    if (tail) tail->perform(this);
-  }
-
-  void Inspect::operator()(Selector_List* g)
-  {
-    if (g->empty()) return;
-    for (size_t i = 0, L = g->length(); i < L; ++i) {
-      if (!in_wrapped && i == 0) append_indentation();
-      (*g)[i]->perform(this);
-      if (i < L - 1) {
-        append_comma_separator();
-        if ((*g)[i]->has_line_feed()) {
-          append_optional_linefeed();
-          append_indentation();
-        }
-      }
-    }
-  }
-
-  void Inspect::fallback_impl(AST_Node* n)
-  {
-  }
-
-}
diff --git a/libsass/inspect.hpp b/libsass/inspect.hpp
deleted file mode 100644
--- a/libsass/inspect.hpp
+++ /dev/null
@@ -1,98 +0,0 @@
-#ifndef SASS_INSPECT_H
-#define SASS_INSPECT_H
-
-#include <string>
-
-#include "position.hpp"
-#include "operation.hpp"
-#include "emitter.hpp"
-
-namespace Sass {
-  class Context;
-  using namespace std;
-
-  class Inspect : public Operation_CRTP<void, Inspect>, public Emitter {
-  protected:
-    // import all the class-specific methods and override as desired
-    using Operation_CRTP<void, Inspect>::operator();
-
-    void fallback_impl(AST_Node* n);
-
-  public:
-
-    Inspect(Emitter emi);
-    virtual ~Inspect();
-
-    // statements
-    virtual void operator()(Block*);
-    virtual void operator()(Ruleset*);
-    virtual void operator()(Propset*);
-    virtual void operator()(Bubble*);
-    virtual void operator()(Feature_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*);
-    // 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()(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()(Feature_Query*);
-    virtual void operator()(Feature_Query_Condition*);
-    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);
-    // parameters and arguments
-    virtual void operator()(Parameter*);
-    virtual void operator()(Parameters*);
-    virtual void operator()(Argument*);
-    virtual void operator()(Arguments*);
-    // selectors
-    virtual void operator()(Selector_Schema*);
-    virtual void operator()(Selector_Reference*);
-    virtual void operator()(Selector_Placeholder*);
-    virtual void operator()(Type_Selector*);
-    virtual void operator()(Selector_Qualifier*);
-    virtual void operator()(Attribute_Selector*);
-    virtual void operator()(Pseudo_Selector*);
-    virtual void operator()(Wrapped_Selector*);
-    virtual void operator()(Compound_Selector*);
-    virtual void operator()(Complex_Selector*);
-    virtual void operator()(Selector_List*);
-
-    // template <typename U>
-    // void fallback(U x) { fallback_impl(reinterpret_cast<AST_Node*>(x)); }
-  };
-
-}
-#endif
diff --git a/libsass/json.cpp b/libsass/json.cpp
deleted file mode 100644
--- a/libsass/json.cpp
+++ /dev/null
@@ -1,1408 +0,0 @@
-/*
-  Copyright (C) 2011 Joseph A. Adams (joeyadams3.14159@gmail.com)
-  All rights reserved.
-
-  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 the Software without restriction, including without limitation the rights
-  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-  copies of the Software, and to permit persons to whom the Software is
-  furnished to do so, subject to the following conditions:
-
-  The above copyright notice and this permission notice shall be included in
-  all copies or substantial portions of the Software.
-
-  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-  THE SOFTWARE.
-*/
-
-#include "json.hpp"
-
-#include <assert.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#ifdef _MSC_VER
-
-#include <stdarg.h>
-#define snprintf c99_snprintf
-
-inline int c99_vsnprintf(char* str, size_t size, const char* format, va_list ap)
-{
-    int count = -1;
-
-    if (size != 0)
-        count = _vsnprintf_s(str, size, _TRUNCATE, format, ap);
-    if (count == -1)
-        count = _vscprintf(format, ap);
-
-    return count;
-}
-
-inline int c99_snprintf(char* str, size_t size, const char* format, ...)
-{
-    int count;
-    va_list ap;
-
-    va_start(ap, format);
-    count = c99_vsnprintf(str, size, format, ap);
-    va_end(ap);
-
-    return count;
-}
-#endif // _MSC_VER
-
-#define out_of_memory() do {                    \
-    fprintf(stderr, "Out of memory.\n");    \
-    exit(EXIT_FAILURE);                     \
-  } while (0)
-
-/* Sadly, strdup is not portable. */
-static char *json_strdup(const char *str)
-{
-  char *ret = (char*) malloc(strlen(str) + 1);
-  if (ret == NULL)
-    out_of_memory();
-  strcpy(ret, str);
-  return ret;
-}
-
-/* String buffer */
-
-typedef struct
-{
-  char *cur;
-  char *end;
-  char *start;
-} SB;
-
-static void sb_init(SB *sb)
-{
-  sb->start = (char*) malloc(17);
-  if (sb->start == NULL)
-    out_of_memory();
-  sb->cur = sb->start;
-  sb->end = sb->start + 16;
-}
-
-/* sb and need may be evaluated multiple times. */
-#define sb_need(sb, need) do {                  \
-    if ((sb)->end - (sb)->cur < (need))     \
-      sb_grow(sb, need);                  \
-  } while (0)
-
-static void sb_grow(SB *sb, int need)
-{
-  size_t length = sb->cur - sb->start;
-  size_t alloc = sb->end - sb->start;
-
-  do {
-    alloc *= 2;
-  } while (alloc < length + need);
-
-  sb->start = (char*) realloc(sb->start, alloc + 1);
-  if (sb->start == NULL)
-    out_of_memory();
-  sb->cur = sb->start + length;
-  sb->end = sb->start + alloc;
-}
-
-static void sb_put(SB *sb, const char *bytes, int count)
-{
-  sb_need(sb, count);
-  memcpy(sb->cur, bytes, count);
-  sb->cur += count;
-}
-
-#define sb_putc(sb, c) do {         \
-    if ((sb)->cur >= (sb)->end) \
-      sb_grow(sb, 1);         \
-    *(sb)->cur++ = (c);         \
-  } while (0)
-
-static void sb_puts(SB *sb, const char *str)
-{
-  sb_put(sb, str, strlen(str));
-}
-
-static char *sb_finish(SB *sb)
-{
-  *sb->cur = 0;
-  assert(sb->start <= sb->cur && strlen(sb->start) == (size_t)(sb->cur - sb->start));
-  return sb->start;
-}
-
-static void sb_free(SB *sb)
-{
-  free(sb->start);
-}
-
-/*
- * Unicode helper functions
- *
- * These are taken from the ccan/charset module and customized a bit.
- * Putting them here means the compiler can (choose to) inline them,
- * and it keeps ccan/json from having a dependency.
- *
- * We use uint32_t Type for Unicode codepoints.
- * We need our own because wchar_t might be 16 bits.
- */
-
-/*
- * Validate a single UTF-8 character starting at @s.
- * The string must be null-terminated.
- *
- * If it's valid, return its length (1 thru 4).
- * If it's invalid or clipped, return 0.
- *
- * This function implements the syntax given in RFC3629, which is
- * the same as that given in The Unicode Standard, Version 6.0.
- *
- * It has the following properties:
- *
- *  * All codepoints U+0000..U+10FFFF may be encoded,
- *    except for U+D800..U+DFFF, which are reserved
- *    for UTF-16 surrogate pair encoding.
- *  * UTF-8 byte sequences longer than 4 bytes are not permitted,
- *    as they exceed the range of Unicode.
- *  * The sixty-six Unicode "non-characters" are permitted
- *    (namely, U+FDD0..U+FDEF, U+xxFFFE, and U+xxFFFF).
- */
-static int utf8_validate_cz(const char *s)
-{
-  unsigned char c = *s++;
-
-  if (c <= 0x7F) {        /* 00..7F */
-    return 1;
-  } else if (c <= 0xC1) { /* 80..C1 */
-    /* Disallow overlong 2-byte sequence. */
-    return 0;
-  } else if (c <= 0xDF) { /* C2..DF */
-    /* Make sure subsequent byte is in the range 0x80..0xBF. */
-    if (((unsigned char)*s++ & 0xC0) != 0x80)
-      return 0;
-
-    return 2;
-  } else if (c <= 0xEF) { /* E0..EF */
-    /* Disallow overlong 3-byte sequence. */
-    if (c == 0xE0 && (unsigned char)*s < 0xA0)
-      return 0;
-
-    /* Disallow U+D800..U+DFFF. */
-    if (c == 0xED && (unsigned char)*s > 0x9F)
-      return 0;
-
-    /* Make sure subsequent bytes are in the range 0x80..0xBF. */
-    if (((unsigned char)*s++ & 0xC0) != 0x80)
-      return 0;
-    if (((unsigned char)*s++ & 0xC0) != 0x80)
-      return 0;
-
-    return 3;
-  } else if (c <= 0xF4) { /* F0..F4 */
-    /* Disallow overlong 4-byte sequence. */
-    if (c == 0xF0 && (unsigned char)*s < 0x90)
-      return 0;
-
-    /* Disallow codepoints beyond U+10FFFF. */
-    if (c == 0xF4 && (unsigned char)*s > 0x8F)
-      return 0;
-
-    /* Make sure subsequent bytes are in the range 0x80..0xBF. */
-    if (((unsigned char)*s++ & 0xC0) != 0x80)
-      return 0;
-    if (((unsigned char)*s++ & 0xC0) != 0x80)
-      return 0;
-    if (((unsigned char)*s++ & 0xC0) != 0x80)
-      return 0;
-
-    return 4;
-  } else {                /* F5..FF */
-    return 0;
-  }
-}
-
-/* Validate a null-terminated UTF-8 string. */
-static bool utf8_validate(const char *s)
-{
-  int len;
-
-  for (; *s != 0; s += len) {
-    len = utf8_validate_cz(s);
-    if (len == 0)
-      return false;
-  }
-
-  return true;
-}
-
-/*
- * Read a single UTF-8 character starting at @s,
- * returning the length, in bytes, of the character read.
- *
- * This function assumes input is valid UTF-8,
- * and that there are enough characters in front of @s.
- */
-static int utf8_read_char(const char *s, uint32_t *out)
-{
-  const unsigned char *c = (const unsigned char*) s;
-
-  assert(utf8_validate_cz(s));
-
-  if (c[0] <= 0x7F) {
-    /* 00..7F */
-    *out = c[0];
-    return 1;
-  } else if (c[0] <= 0xDF) {
-    /* C2..DF (unless input is invalid) */
-    *out = ((uint32_t)c[0] & 0x1F) << 6 |
-           ((uint32_t)c[1] & 0x3F);
-    return 2;
-  } else if (c[0] <= 0xEF) {
-    /* E0..EF */
-    *out = ((uint32_t)c[0] &  0xF) << 12 |
-           ((uint32_t)c[1] & 0x3F) << 6  |
-           ((uint32_t)c[2] & 0x3F);
-    return 3;
-  } else {
-    /* F0..F4 (unless input is invalid) */
-    *out = ((uint32_t)c[0] &  0x7) << 18 |
-           ((uint32_t)c[1] & 0x3F) << 12 |
-           ((uint32_t)c[2] & 0x3F) << 6  |
-           ((uint32_t)c[3] & 0x3F);
-    return 4;
-  }
-}
-
-/*
- * Write a single UTF-8 character to @s,
- * returning the length, in bytes, of the character written.
- *
- * @unicode must be U+0000..U+10FFFF, but not U+D800..U+DFFF.
- *
- * This function will write up to 4 bytes to @out.
- */
-static int utf8_write_char(uint32_t unicode, char *out)
-{
-  unsigned char *o = (unsigned char*) out;
-
-  assert(unicode <= 0x10FFFF && !(unicode >= 0xD800 && unicode <= 0xDFFF));
-
-  if (unicode <= 0x7F) {
-    /* U+0000..U+007F */
-    *o++ = unicode;
-    return 1;
-  } else if (unicode <= 0x7FF) {
-    /* U+0080..U+07FF */
-    *o++ = 0xC0 | unicode >> 6;
-    *o++ = 0x80 | (unicode & 0x3F);
-    return 2;
-  } else if (unicode <= 0xFFFF) {
-    /* U+0800..U+FFFF */
-    *o++ = 0xE0 | unicode >> 12;
-    *o++ = 0x80 | (unicode >> 6 & 0x3F);
-    *o++ = 0x80 | (unicode & 0x3F);
-    return 3;
-  } else {
-    /* U+10000..U+10FFFF */
-    *o++ = 0xF0 | unicode >> 18;
-    *o++ = 0x80 | (unicode >> 12 & 0x3F);
-    *o++ = 0x80 | (unicode >> 6 & 0x3F);
-    *o++ = 0x80 | (unicode & 0x3F);
-    return 4;
-  }
-}
-
-/*
- * Compute the Unicode codepoint of a UTF-16 surrogate pair.
- *
- * @uc should be 0xD800..0xDBFF, and @lc should be 0xDC00..0xDFFF.
- * If they aren't, this function returns false.
- */
-static bool from_surrogate_pair(uint16_t uc, uint16_t lc, uint32_t *unicode)
-{
-  if (uc >= 0xD800 && uc <= 0xDBFF && lc >= 0xDC00 && lc <= 0xDFFF) {
-    *unicode = 0x10000 + ((((uint32_t)uc & 0x3FF) << 10) | (lc & 0x3FF));
-    return true;
-  } else {
-    return false;
-  }
-}
-
-/*
- * Construct a UTF-16 surrogate pair given a Unicode codepoint.
- *
- * @unicode must be U+10000..U+10FFFF.
- */
-static void to_surrogate_pair(uint32_t unicode, uint16_t *uc, uint16_t *lc)
-{
-  uint32_t n;
-
-  assert(unicode >= 0x10000 && unicode <= 0x10FFFF);
-
-  n = unicode - 0x10000;
-  *uc = ((n >> 10) & 0x3FF) | 0xD800;
-  *lc = (n & 0x3FF) | 0xDC00;
-}
-
-#define is_space(c) ((c) == '\t' || (c) == '\n' || (c) == '\r' || (c) == ' ')
-#define is_digit(c) ((c) >= '0' && (c) <= '9')
-
-static bool parse_value     (const char **sp, JsonNode        **out);
-static bool parse_string    (const char **sp, char            **out);
-static bool parse_number    (const char **sp, double           *out);
-static bool parse_array     (const char **sp, JsonNode        **out);
-static bool parse_object    (const char **sp, JsonNode        **out);
-static bool parse_hex16     (const char **sp, uint16_t         *out);
-
-static bool expect_literal  (const char **sp, const char *str);
-static void skip_space      (const char **sp);
-
-static void emit_value              (SB *out, const JsonNode *node);
-static void emit_value_indented     (SB *out, const JsonNode *node, const char *space, int indent_level);
-static void emit_string             (SB *out, const char *str);
-static void emit_number             (SB *out, double num);
-static void emit_array              (SB *out, const JsonNode *array);
-static void emit_array_indented     (SB *out, const JsonNode *array, const char *space, int indent_level);
-static void emit_object             (SB *out, const JsonNode *object);
-static void emit_object_indented    (SB *out, const JsonNode *object, const char *space, int indent_level);
-
-static int write_hex16(char *out, uint16_t val);
-
-static JsonNode *mknode(JsonTag tag);
-static void append_node(JsonNode *parent, JsonNode *child);
-static void prepend_node(JsonNode *parent, JsonNode *child);
-static void append_member(JsonNode *object, char *key, JsonNode *value);
-
-/* Assertion-friendly validity checks */
-static bool tag_is_valid(unsigned int tag);
-static bool number_is_valid(const char *num);
-
-JsonNode *json_decode(const char *json)
-{
-  const char *s = json;
-  JsonNode *ret;
-
-  skip_space(&s);
-  if (!parse_value(&s, &ret))
-    return NULL;
-
-  skip_space(&s);
-  if (*s != 0) {
-    json_delete(ret);
-    return NULL;
-  }
-
-  return ret;
-}
-
-char *json_encode(const JsonNode *node)
-{
-  return json_stringify(node, NULL);
-}
-
-char *json_encode_string(const char *str)
-{
-  SB sb;
-  sb_init(&sb);
-
-  emit_string(&sb, str);
-
-  return sb_finish(&sb);
-}
-
-char *json_stringify(const JsonNode *node, const char *space)
-{
-  SB sb;
-  sb_init(&sb);
-
-  if (space != NULL)
-    emit_value_indented(&sb, node, space, 0);
-  else
-    emit_value(&sb, node);
-
-  return sb_finish(&sb);
-}
-
-void json_delete(JsonNode *node)
-{
-  if (node != NULL) {
-    json_remove_from_parent(node);
-
-    switch (node->tag) {
-      case JSON_STRING:
-        free(node->string_);
-        break;
-      case JSON_ARRAY:
-      case JSON_OBJECT:
-      {
-        JsonNode *child, *next;
-        for (child = node->children.head; child != NULL; child = next) {
-          next = child->next;
-          json_delete(child);
-        }
-        break;
-      }
-      default:;
-    }
-
-    free(node);
-  }
-}
-
-bool json_validate(const char *json)
-{
-  const char *s = json;
-
-  skip_space(&s);
-  if (!parse_value(&s, NULL))
-    return false;
-
-  skip_space(&s);
-  if (*s != 0)
-    return false;
-
-  return true;
-}
-
-JsonNode *json_find_element(JsonNode *array, int index)
-{
-  JsonNode *element;
-  int i = 0;
-
-  if (array == NULL || array->tag != JSON_ARRAY)
-    return NULL;
-
-  json_foreach(element, array) {
-    if (i == index)
-      return element;
-    i++;
-  }
-
-  return NULL;
-}
-
-JsonNode *json_find_member(JsonNode *object, const char *name)
-{
-  JsonNode *member;
-
-  if (object == NULL || object->tag != JSON_OBJECT)
-    return NULL;
-
-  json_foreach(member, object)
-    if (strcmp(member->key, name) == 0)
-      return member;
-
-  return NULL;
-}
-
-JsonNode *json_first_child(const JsonNode *node)
-{
-  if (node != NULL && (node->tag == JSON_ARRAY || node->tag == JSON_OBJECT))
-    return node->children.head;
-  return NULL;
-}
-
-static JsonNode *mknode(JsonTag tag)
-{
-  JsonNode *ret = (JsonNode*) calloc(1, sizeof(JsonNode));
-  if (ret == NULL)
-    out_of_memory();
-  ret->tag = tag;
-  return ret;
-}
-
-JsonNode *json_mknull(void)
-{
-  return mknode(JSON_NULL);
-}
-
-JsonNode *json_mkbool(bool b)
-{
-  JsonNode *ret = mknode(JSON_BOOL);
-  ret->bool_ = b;
-  return ret;
-}
-
-static JsonNode *mkstring(char *s)
-{
-  JsonNode *ret = mknode(JSON_STRING);
-  ret->string_ = s;
-  return ret;
-}
-
-JsonNode *json_mkstring(const char *s)
-{
-  return mkstring(json_strdup(s));
-}
-
-JsonNode *json_mknumber(double n)
-{
-  JsonNode *node = mknode(JSON_NUMBER);
-  node->number_ = n;
-  return node;
-}
-
-JsonNode *json_mkarray(void)
-{
-  return mknode(JSON_ARRAY);
-}
-
-JsonNode *json_mkobject(void)
-{
-  return mknode(JSON_OBJECT);
-}
-
-static void append_node(JsonNode *parent, JsonNode *child)
-{
-  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;
-}
-
-static void prepend_node(JsonNode *parent, JsonNode *child)
-{
-  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;
-}
-
-static void append_member(JsonNode *object, char *key, JsonNode *value)
-{
-  value->key = key;
-  append_node(object, value);
-}
-
-void json_append_element(JsonNode *array, JsonNode *element)
-{
-  assert(array->tag == JSON_ARRAY);
-  assert(element->parent == NULL);
-
-  append_node(array, element);
-}
-
-void json_prepend_element(JsonNode *array, JsonNode *element)
-{
-  assert(array->tag == JSON_ARRAY);
-  assert(element->parent == NULL);
-
-  prepend_node(array, element);
-}
-
-void json_append_member(JsonNode *object, const char *key, JsonNode *value)
-{
-  assert(object->tag == JSON_OBJECT);
-  assert(value->parent == NULL);
-
-  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);
-
-  value->key = json_strdup(key);
-  prepend_node(object, value);
-}
-
-void json_remove_from_parent(JsonNode *node)
-{
-  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;
-
-    free(node->key);
-
-    node->parent = NULL;
-    node->prev = node->next = NULL;
-    node->key = NULL;
-  }
-}
-
-static bool parse_value(const char **sp, JsonNode **out)
-{
-  const char *s = *sp;
-
-  switch (*s) {
-    case 'n':
-      if (expect_literal(&s, "null")) {
-        if (out)
-          *out = json_mknull();
-        *sp = s;
-        return true;
-      }
-      return false;
-
-    case 'f':
-      if (expect_literal(&s, "false")) {
-        if (out)
-          *out = json_mkbool(false);
-        *sp = s;
-        return true;
-      }
-      return false;
-
-    case 't':
-      if (expect_literal(&s, "true")) {
-        if (out)
-          *out = json_mkbool(true);
-        *sp = s;
-        return true;
-      }
-      return false;
-
-    case '"': {
-      char *str;
-      if (parse_string(&s, out ? &str : NULL)) {
-        if (out)
-          *out = mkstring(str);
-        *sp = s;
-        return true;
-      }
-      return false;
-    }
-
-    case '[':
-      if (parse_array(&s, out)) {
-        *sp = s;
-        return true;
-      }
-      return false;
-
-    case '{':
-      if (parse_object(&s, out)) {
-        *sp = s;
-        return true;
-      }
-      return false;
-
-    default: {
-      double num;
-      if (parse_number(&s, out ? &num : NULL)) {
-        if (out)
-          *out = json_mknumber(num);
-        *sp = s;
-        return true;
-      }
-      return false;
-    }
-  }
-}
-
-static bool parse_array(const char **sp, JsonNode **out)
-{
-  const char *s = *sp;
-  JsonNode *ret = out ? json_mkarray() : NULL;
-  JsonNode *element;
-
-  if (*s++ != '[')
-    goto failure;
-  skip_space(&s);
-
-  if (*s == ']') {
-    s++;
-    goto success;
-  }
-
-  for (;;) {
-    if (!parse_value(&s, out ? &element : NULL))
-      goto failure;
-    skip_space(&s);
-
-    if (out)
-      json_append_element(ret, element);
-
-    if (*s == ']') {
-      s++;
-      goto success;
-    }
-
-    if (*s++ != ',')
-      goto failure;
-    skip_space(&s);
-  }
-
-success:
-  *sp = s;
-  if (out)
-    *out = ret;
-  return true;
-
-failure:
-  json_delete(ret);
-  return false;
-}
-
-static bool parse_object(const char **sp, JsonNode **out)
-{
-  const char *s = *sp;
-  JsonNode *ret = out ? json_mkobject() : NULL;
-  char *key;
-  JsonNode *value;
-
-  if (*s++ != '{')
-    goto failure;
-  skip_space(&s);
-
-  if (*s == '}') {
-    s++;
-    goto success;
-  }
-
-  for (;;) {
-    if (!parse_string(&s, out ? &key : NULL))
-      goto failure;
-    skip_space(&s);
-
-    if (*s++ != ':')
-      goto failure_free_key;
-    skip_space(&s);
-
-    if (!parse_value(&s, out ? &value : NULL))
-      goto failure_free_key;
-    skip_space(&s);
-
-    if (out)
-      append_member(ret, key, value);
-
-    if (*s == '}') {
-      s++;
-      goto success;
-    }
-
-    if (*s++ != ',')
-      goto failure;
-    skip_space(&s);
-  }
-
-success:
-  *sp = s;
-  if (out)
-    *out = ret;
-  return true;
-
-failure_free_key:
-  if (out)
-    free(key);
-failure:
-  json_delete(ret);
-  return false;
-}
-
-bool parse_string(const char **sp, char **out)
-{
-  const char *s = *sp;
-  SB sb;
-  char throwaway_buffer[4];
-    /* enough space for a UTF-8 character */
-  char *b;
-
-  if (*s++ != '"')
-    return false;
-
-  if (out) {
-    sb_init(&sb);
-    sb_need(&sb, 4);
-    b = sb.cur;
-  } else {
-    b = throwaway_buffer;
-  }
-
-  while (*s != '"') {
-    unsigned char c = *s++;
-
-    /* Parse next character, and write it to b. */
-    if (c == '\\') {
-      c = *s++;
-      switch (c) {
-        case '"':
-        case '\\':
-        case '/':
-          *b++ = c;
-          break;
-        case 'b':
-          *b++ = '\b';
-          break;
-        case 'f':
-          *b++ = '\f';
-          break;
-        case 'n':
-          *b++ = '\n';
-          break;
-        case 'r':
-          *b++ = '\r';
-          break;
-        case 't':
-          *b++ = '\t';
-          break;
-        case 'u':
-        {
-          uint16_t uc, lc;
-          uint32_t unicode;
-
-          if (!parse_hex16(&s, &uc))
-            goto failed;
-
-          if (uc >= 0xD800 && uc <= 0xDFFF) {
-            /* Handle UTF-16 surrogate pair. */
-            if (*s++ != '\\' || *s++ != 'u' || !parse_hex16(&s, &lc))
-              goto failed; /* Incomplete surrogate pair. */
-            if (!from_surrogate_pair(uc, lc, &unicode))
-              goto failed; /* Invalid surrogate pair. */
-          } else if (uc == 0) {
-            /* Disallow "\u0000". */
-            goto failed;
-          } else {
-            unicode = uc;
-          }
-
-          b += utf8_write_char(unicode, b);
-          break;
-        }
-        default:
-          /* Invalid escape */
-          goto failed;
-      }
-    } else if (c <= 0x1F) {
-      /* Control characters are not allowed in string literals. */
-      goto failed;
-    } else {
-      /* Validate and echo a UTF-8 character. */
-      int len;
-
-      s--;
-      len = utf8_validate_cz(s);
-      if (len == 0)
-        goto failed; /* Invalid UTF-8 character. */
-
-      while (len--)
-        *b++ = *s++;
-    }
-
-    /*
-     * Update sb to know about the new bytes,
-     * and set up b to write another character.
-     */
-    if (out) {
-      sb.cur = b;
-      sb_need(&sb, 4);
-      b = sb.cur;
-    } else {
-      b = throwaway_buffer;
-    }
-  }
-  s++;
-
-  if (out)
-    *out = sb_finish(&sb);
-  *sp = s;
-  return true;
-
-failed:
-  if (out)
-    sb_free(&sb);
-  return false;
-}
-
-/*
- * The JSON spec says that a number shall follow this precise pattern
- * (spaces and quotes added for readability):
- *   '-'? (0 | [1-9][0-9]*) ('.' [0-9]+)? ([Ee] [+-]? [0-9]+)?
- *
- * However, some JSON parsers are more liberal.  For instance, PHP accepts
- * '.5' and '1.'.  JSON.parse accepts '+3'.
- *
- * This function takes the strict approach.
- */
-bool parse_number(const char **sp, double *out)
-{
-  const char *s = *sp;
-
-  /* '-'? */
-  if (*s == '-')
-    s++;
-
-  /* (0 | [1-9][0-9]*) */
-  if (*s == '0') {
-    s++;
-  } else {
-    if (!is_digit(*s))
-      return false;
-    do {
-      s++;
-    } while (is_digit(*s));
-  }
-
-  /* ('.' [0-9]+)? */
-  if (*s == '.') {
-    s++;
-    if (!is_digit(*s))
-      return false;
-    do {
-      s++;
-    } while (is_digit(*s));
-  }
-
-  /* ([Ee] [+-]? [0-9]+)? */
-  if (*s == 'E' || *s == 'e') {
-    s++;
-    if (*s == '+' || *s == '-')
-      s++;
-    if (!is_digit(*s))
-      return false;
-    do {
-      s++;
-    } while (is_digit(*s));
-  }
-
-  if (out)
-    *out = strtod(*sp, NULL);
-
-  *sp = s;
-  return true;
-}
-
-static void skip_space(const char **sp)
-{
-  const char *s = *sp;
-  while (is_space(*s))
-    s++;
-  *sp = s;
-}
-
-static void emit_value(SB *out, const JsonNode *node)
-{
-  assert(tag_is_valid(node->tag));
-  switch (node->tag) {
-    case JSON_NULL:
-      sb_puts(out, "null");
-      break;
-    case JSON_BOOL:
-      sb_puts(out, node->bool_ ? "true" : "false");
-      break;
-    case JSON_STRING:
-      emit_string(out, node->string_);
-      break;
-    case JSON_NUMBER:
-      emit_number(out, node->number_);
-      break;
-    case JSON_ARRAY:
-      emit_array(out, node);
-      break;
-    case JSON_OBJECT:
-      emit_object(out, node);
-      break;
-    default:
-      assert(false);
-  }
-}
-
-void emit_value_indented(SB *out, const JsonNode *node, const char *space, int indent_level)
-{
-  assert(tag_is_valid(node->tag));
-  switch (node->tag) {
-    case JSON_NULL:
-      sb_puts(out, "null");
-      break;
-    case JSON_BOOL:
-      sb_puts(out, node->bool_ ? "true" : "false");
-      break;
-    case JSON_STRING:
-      emit_string(out, node->string_);
-      break;
-    case JSON_NUMBER:
-      emit_number(out, node->number_);
-      break;
-    case JSON_ARRAY:
-      emit_array_indented(out, node, space, indent_level);
-      break;
-    case JSON_OBJECT:
-      emit_object_indented(out, node, space, indent_level);
-      break;
-    default:
-      assert(false);
-  }
-}
-
-static void emit_array(SB *out, const JsonNode *array)
-{
-  const JsonNode *element;
-
-  sb_putc(out, '[');
-  json_foreach(element, array) {
-    emit_value(out, element);
-    if (element->next != NULL)
-      sb_putc(out, ',');
-  }
-  sb_putc(out, ']');
-}
-
-static void emit_array_indented(SB *out, const JsonNode *array, const char *space, int indent_level)
-{
-  const JsonNode *element = array->children.head;
-  int i;
-
-  if (element == NULL) {
-    sb_puts(out, "[]");
-    return;
-  }
-
-  sb_puts(out, "[\n");
-  while (element != NULL) {
-    for (i = 0; i < indent_level + 1; i++)
-      sb_puts(out, space);
-    emit_value_indented(out, element, space, indent_level + 1);
-
-    element = element->next;
-    sb_puts(out, element != NULL ? ",\n" : "\n");
-  }
-  for (i = 0; i < indent_level; i++)
-    sb_puts(out, space);
-  sb_putc(out, ']');
-}
-
-static void emit_object(SB *out, const JsonNode *object)
-{
-  const JsonNode *member;
-
-  sb_putc(out, '{');
-  json_foreach(member, object) {
-    emit_string(out, member->key);
-    sb_putc(out, ':');
-    emit_value(out, member);
-    if (member->next != NULL)
-      sb_putc(out, ',');
-  }
-  sb_putc(out, '}');
-}
-
-static void emit_object_indented(SB *out, const JsonNode *object, const char *space, int indent_level)
-{
-  const JsonNode *member = object->children.head;
-  int i;
-
-  if (member == NULL) {
-    sb_puts(out, "{}");
-    return;
-  }
-
-  sb_puts(out, "{\n");
-  while (member != NULL) {
-    for (i = 0; i < indent_level + 1; i++)
-      sb_puts(out, space);
-    emit_string(out, member->key);
-    sb_puts(out, ": ");
-    emit_value_indented(out, member, space, indent_level + 1);
-
-    member = member->next;
-    sb_puts(out, member != NULL ? ",\n" : "\n");
-  }
-  for (i = 0; i < indent_level; i++)
-    sb_puts(out, space);
-  sb_putc(out, '}');
-}
-
-void emit_string(SB *out, const char *str)
-{
-  bool escape_unicode = false;
-  const char *s = str;
-  char *b;
-
-  assert(utf8_validate(str));
-
-  /*
-   * 14 bytes is enough space to write up to two
-   * \uXXXX escapes and two quotation marks.
-   */
-  sb_need(out, 14);
-  b = out->cur;
-
-  *b++ = '"';
-  while (*s != 0) {
-    unsigned char c = *s++;
-
-    /* Encode the next character, and write it to b. */
-    switch (c) {
-      case '"':
-        *b++ = '\\';
-        *b++ = '"';
-        break;
-      case '\\':
-        *b++ = '\\';
-        *b++ = '\\';
-        break;
-      case '\b':
-        *b++ = '\\';
-        *b++ = 'b';
-        break;
-      case '\f':
-        *b++ = '\\';
-        *b++ = 'f';
-        break;
-      case '\n':
-        *b++ = '\\';
-        *b++ = 'n';
-        break;
-      case '\r':
-        *b++ = '\\';
-        *b++ = 'r';
-        break;
-      case '\t':
-        *b++ = '\\';
-        *b++ = 't';
-        break;
-      default: {
-        int len;
-
-        s--;
-        len = utf8_validate_cz(s);
-
-        if (len == 0) {
-          /*
-           * Handle invalid UTF-8 character gracefully in production
-           * by writing a replacement character (U+FFFD)
-           * and skipping a single byte.
-           *
-           * This should never happen when assertions are enabled
-           * due to the assertion at the beginning of this function.
-           */
-          assert(false);
-          if (escape_unicode) {
-            strcpy(b, "\\uFFFD");
-            b += 6;
-          } else {
-            *b++ = 0xEFu;
-            *b++ = 0xBFu;
-            *b++ = 0xBDu;
-          }
-          s++;
-        } else if (c < 0x1F || (c >= 0x80 && escape_unicode)) {
-          /* Encode using \u.... */
-          uint32_t unicode;
-
-          s += utf8_read_char(s, &unicode);
-
-          if (unicode <= 0xFFFF) {
-            *b++ = '\\';
-            *b++ = 'u';
-            b += write_hex16(b, unicode);
-          } else {
-            /* Produce a surrogate pair. */
-            uint16_t uc, lc;
-            assert(unicode <= 0x10FFFF);
-            to_surrogate_pair(unicode, &uc, &lc);
-            *b++ = '\\';
-            *b++ = 'u';
-            b += write_hex16(b, uc);
-            *b++ = '\\';
-            *b++ = 'u';
-            b += write_hex16(b, lc);
-          }
-        } else {
-          /* Write the character directly. */
-          while (len--)
-            *b++ = *s++;
-        }
-
-        break;
-      }
-    }
-
-    /*
-     * Update *out to know about the new bytes,
-     * and set up b to write another encoded character.
-     */
-    out->cur = b;
-    sb_need(out, 14);
-    b = out->cur;
-  }
-  *b++ = '"';
-
-  out->cur = b;
-}
-
-static void emit_number(SB *out, double num)
-{
-  /*
-   * This isn't exactly how JavaScript renders numbers,
-   * but it should produce valid JSON for reasonable numbers
-   * preserve precision well enough, and avoid some oddities
-   * like 0.3 -> 0.299999999999999988898 .
-   */
-  char buf[64];
-  sprintf(buf, "%.16g", num);
-
-  if (number_is_valid(buf))
-    sb_puts(out, buf);
-  else
-    sb_puts(out, "null");
-}
-
-static bool tag_is_valid(unsigned int tag)
-{
-  return (/* tag >= JSON_NULL && */ tag <= JSON_OBJECT);
-}
-
-static bool number_is_valid(const char *num)
-{
-  return (parse_number(&num, NULL) && *num == '\0');
-}
-
-static bool expect_literal(const char **sp, const char *str)
-{
-  const char *s = *sp;
-
-  while (*str != '\0')
-    if (*s++ != *str++)
-      return false;
-
-  *sp = s;
-  return true;
-}
-
-/*
- * Parses exactly 4 hex characters (capital or lowercase).
- * Fails if any input chars are not [0-9A-Fa-f].
- */
-static bool parse_hex16(const char **sp, uint16_t *out)
-{
-  const char *s = *sp;
-  uint16_t ret = 0;
-  uint16_t i;
-  uint16_t tmp;
-  char c;
-
-  for (i = 0; i < 4; i++) {
-    c = *s++;
-    if (c >= '0' && c <= '9')
-      tmp = c - '0';
-    else if (c >= 'A' && c <= 'F')
-      tmp = c - 'A' + 10;
-    else if (c >= 'a' && c <= 'f')
-      tmp = c - 'a' + 10;
-    else
-      return false;
-
-    ret <<= 4;
-    ret += tmp;
-  }
-
-  if (out)
-    *out = ret;
-  *sp = s;
-  return true;
-}
-
-/*
- * Encodes a 16-bit number into hexadecimal,
- * writing exactly 4 hex chars.
- */
-static int write_hex16(char *out, uint16_t val)
-{
-  const char *hex = "0123456789ABCDEF";
-
-  *out++ = hex[(val >> 12) & 0xF];
-  *out++ = hex[(val >> 8)  & 0xF];
-  *out++ = hex[(val >> 4)  & 0xF];
-  *out++ = hex[ val        & 0xF];
-
-  return 4;
-}
-
-bool json_check(const JsonNode *node, char errmsg[256])
-{
-  #define problem(...) do { \
-      if (errmsg != NULL) \
-        snprintf(errmsg, 256, __VA_ARGS__); \
-      return false; \
-    } while (0)
-
-  if (node->key != NULL && !utf8_validate(node->key))
-    problem("key contains invalid UTF-8");
-
-  if (!tag_is_valid(node->tag))
-    problem("tag is invalid (%u)", node->tag);
-
-  if (node->tag == JSON_BOOL) {
-    if (node->bool_ != false && node->bool_ != true)
-      problem("bool_ is neither false (%d) nor true (%d)", (int)false, (int)true);
-  } else if (node->tag == JSON_STRING) {
-    if (node->string_ == NULL)
-      problem("string_ is NULL");
-    if (!utf8_validate(node->string_))
-      problem("string_ contains invalid UTF-8");
-  } else if (node->tag == JSON_ARRAY || node->tag == JSON_OBJECT) {
-    JsonNode *head = node->children.head;
-    JsonNode *tail = node->children.tail;
-
-    if (head == NULL || tail == NULL) {
-      if (head != NULL)
-        problem("tail is NULL, but head is not");
-      if (tail != NULL)
-        problem("head is NULL, but tail is not");
-    } else {
-      JsonNode *child;
-      JsonNode *last = NULL;
-
-      if (head->prev != NULL)
-        problem("First child's prev pointer is not NULL");
-
-      for (child = head; child != NULL; last = child, child = child->next) {
-        if (child == node)
-          problem("node is its own child");
-        if (child->next == child)
-          problem("child->next == child (cycle)");
-        if (child->next == head)
-          problem("child->next == head (cycle)");
-
-        if (child->parent != node)
-          problem("child does not point back to parent");
-        if (child->next != NULL && child->next->prev != child)
-          problem("child->next does not point back to child");
-
-        if (node->tag == JSON_ARRAY && child->key != NULL)
-          problem("Array element's key is not NULL");
-        if (node->tag == JSON_OBJECT && child->key == NULL)
-          problem("Object member's key is NULL");
-
-        if (!json_check(child, errmsg))
-          return false;
-      }
-
-      if (last != tail)
-        problem("tail does not match pointer found by starting at head and following next links");
-    }
-  }
-
-  return true;
-
-  #undef problem
-}
diff --git a/libsass/json.hpp b/libsass/json.hpp
deleted file mode 100644
--- a/libsass/json.hpp
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
-  Copyright (C) 2011 Joseph A. Adams (joeyadams3.14159@gmail.com)
-  All rights reserved.
-
-  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 the Software without restriction, including without limitation the rights
-  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-  copies of the Software, and to permit persons to whom the Software is
-  furnished to do so, subject to the following conditions:
-
-  The above copyright notice and this permission notice shall be included in
-  all copies or substantial portions of the Software.
-
-  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-  THE SOFTWARE.
-*/
-
-#ifndef CCAN_JSON_H
-#define CCAN_JSON_H
-
-#include <stdbool.h>
-#include <stddef.h>
-
-typedef enum {
-  JSON_NULL,
-  JSON_BOOL,
-  JSON_STRING,
-  JSON_NUMBER,
-  JSON_ARRAY,
-  JSON_OBJECT,
-} JsonTag;
-
-typedef struct JsonNode JsonNode;
-
-struct JsonNode
-{
-  /* 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 {
-      JsonNode *head, *tail;
-    } children;
-  };
-};
-
-/*** Encoding, decoding, and validation ***/
-
-JsonNode   *json_decode         (const char *json);
-char       *json_encode         (const JsonNode *node);
-char       *json_encode_string  (const char *str);
-char       *json_stringify      (const JsonNode *node, const char *space);
-void        json_delete         (JsonNode *node);
-
-bool        json_validate       (const char *json);
-
-/*** Lookup and traversal ***/
-
-JsonNode   *json_find_element   (JsonNode *array, int index);
-JsonNode   *json_find_member    (JsonNode *object, const char *key);
-
-JsonNode   *json_first_child    (const JsonNode *node);
-
-#define json_foreach(i, object_or_array)            \
-  for ((i) = json_first_child(object_or_array);   \
-     (i) != NULL;                               \
-     (i) = (i)->next)
-
-/*** Construction and manipulation ***/
-
-JsonNode *json_mknull(void);
-JsonNode *json_mkbool(bool b);
-JsonNode *json_mkstring(const char *s);
-JsonNode *json_mknumber(double n);
-JsonNode *json_mkarray(void);
-JsonNode *json_mkobject(void);
-
-void json_append_element(JsonNode *array, JsonNode *element);
-void json_prepend_element(JsonNode *array, JsonNode *element);
-void json_append_member(JsonNode *object, const char *key, JsonNode *value);
-void json_prepend_member(JsonNode *object, const char *key, JsonNode *value);
-
-void json_remove_from_parent(JsonNode *node);
-
-/*** Debugging ***/
-
-/*
- * Look for structure and encoding problems in a JsonNode or its descendents.
- *
- * If a problem is detected, return false, writing a description of the problem
- * to errmsg (unless errmsg is NULL).
- */
-bool json_check(const JsonNode *node, char errmsg[256]);
-
-#endif
diff --git a/libsass/kwd_arg_macros.hpp b/libsass/kwd_arg_macros.hpp
deleted file mode 100644
--- a/libsass/kwd_arg_macros.hpp
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef SASS_KWD_ARG_MACROS_H
-#define SASS_KWD_ARG_MACROS_H
-
-// Example usage:
-// KWD_ARG_SET(Args) {
-//   KWD_ARG(Args, string, foo);
-//   KWD_ARG(Args, int, bar);
-//   ...
-// };
-//
-// ... and later ...
-//
-// something(Args().foo("hey").bar(3));
-
-#define KWD_ARG_SET(set_name) class set_name
-
-#define KWD_ARG(set_name, type, name) \
-private: \
-  type name##_; \
-public: \
-  set_name& name(type name##__) { \
-    name##_ = name##__; \
-    return *this; \
-  } \
-  type name() { return name##_; } \
-private:
-
-#endif
diff --git a/libsass/lexer.cpp b/libsass/lexer.cpp
deleted file mode 100644
--- a/libsass/lexer.cpp
+++ /dev/null
@@ -1,133 +0,0 @@
-#include <cctype>
-#include <cstddef>
-#include <iostream>
-#include <iomanip>
-#include "lexer.hpp"
-#include "constants.hpp"
-
-
-namespace Sass {
-  using namespace Constants;
-
-  namespace Prelexer {
-
-    //####################################
-    // BASIC CHARACTER MATCHERS
-    //####################################
-
-    // Match standard control chars
-    const char* kwd_at(const char* src) { return exactly<'@'>(src); }
-    const char* kwd_dot(const char* src) { return exactly<'.'>(src); }
-    const char* kwd_comma(const char* src) { return exactly<','>(src); };
-    const char* kwd_colon(const char* src) { return exactly<':'>(src); };
-    const char* kwd_star(const char* src) { return exactly<'*'>(src); };
-    const char* kwd_plus(const char* src) { return exactly<'+'>(src); };
-    const char* kwd_minus(const char* src) { return exactly<'-'>(src); };
-    const char* kwd_slash(const char* src) { return exactly<'/'>(src); };
-
-    //####################################
-    // implement some function that do exist in the standard
-    // but those are locale aware which brought some trouble
-    // this even seems to improve performance by quite a bit
-    //####################################
-
-    bool is_alpha(const char& chr)
-    {
-      return unsigned(chr - 'A') <= 'Z' - 'A' ||
-             unsigned(chr - 'a') <= 'z' - 'a';
-    }
-
-    bool is_space(const char& chr)
-    {
-      // adapted the technique from is_alpha
-      return chr == ' ' || unsigned(chr - '\t') <= '\r' - '\t';
-    }
-
-    bool is_digit(const char& chr)
-    {
-      // adapted the technique from is_alpha
-      return unsigned(chr - '0') <= '9' - '0';
-    }
-
-    bool is_xdigit(const char& chr)
-    {
-      // adapted the technique from is_alpha
-      return unsigned(chr - '0') <= '9' - '0' ||
-             unsigned(chr - 'a') <= 'f' - 'a' ||
-             unsigned(chr - 'A') <= 'F' - 'A';
-    }
-
-    bool is_punct(const char& chr)
-    {
-      // locale independent
-      return chr == '.';
-    }
-
-    bool is_alnum(const char& chr)
-    {
-      return is_alpha(chr) || is_digit(chr);
-    }
-
-    // check if char is outside ascii range
-    bool is_unicode(const char& chr)
-    {
-      // check for unicode range
-      return unsigned(chr) > 127;
-    }
-
-    // Match word character (look ahead)
-    bool is_character(const char& chr)
-    {
-      // valid alpha, numeric or unicode char (plus hyphen)
-      return is_alnum(chr) || is_unicode(chr) || chr == '-';
-    }
-
-    //####################################
-    // BASIC CLASS MATCHERS
-    //####################################
-
-    // create matchers that advance the position
-    const char* space(const char* src) { return is_space(*src) ? src + 1 : 0; }
-    const char* alpha(const char* src) { return is_alpha(*src) ? src + 1 : 0; }
-    const char* unicode(const char* src) { return is_unicode(*src) ? src + 1 : 0; }
-    const char* digit(const char* src) { return is_digit(*src) ? src + 1 : 0; }
-    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* character(const char* src) { return is_character(*src) ? src + 1 : 0; }
-
-    // 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); }
-
-    // Whitespace handling.
-    const char* no_spaces(const char* src) { return negate< space >(src); }
-    const char* optional_spaces(const char* src) { return zero_plus< space >(src); }
-
-    // Match any single character.
-    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; }
-
-    // Match linefeed /(?:\n|\r\n?)/
-    const char* re_linebreak(const char* src)
-    {
-      // end of file or unix linefeed return here
-      if (*src == 0 || *src == '\n') return src + 1;
-      // a carriage return may optionally be followed by a linefeed
-      if (*src == '\r') return *(src + 1) == '\n' ? src + 2 : src + 1;
-      // no linefeed
-      return 0;
-    }
-
-    // Assert string boundaries (/\Z|\z|\A/)
-    // This is a zero-width positive lookahead
-    const char* end_of_line(const char* src)
-    {
-      // end of file or unix linefeed return here
-      return *src == 0 || *src == '\n' || *src == '\r' ? src : 0;
-    }
-
-  }
-}
diff --git a/libsass/lexer.hpp b/libsass/lexer.hpp
deleted file mode 100644
--- a/libsass/lexer.hpp
+++ /dev/null
@@ -1,239 +0,0 @@
-#ifndef SASS_LEXER_H
-#define SASS_LEXER_H
-
-#include <cstring>
-
-namespace Sass {
-  namespace Prelexer {
-
-    //####################################
-    // BASIC CHARACTER MATCHERS
-    //####################################
-
-    // Match standard control chars
-    const char* kwd_at(const char* src);
-    const char* kwd_dot(const char* src);
-    const char* kwd_comma(const char* src);
-    const char* kwd_colon(const char* src);
-    const char* kwd_star(const char* src);
-    const char* kwd_plus(const char* src);
-    const char* kwd_minus(const char* src);
-    const char* kwd_slash(const char* src);
-
-    //####################################
-    // BASIC CLASS MATCHERS
-    //####################################
-
-    // These are locale independant
-    bool is_space(const char& src);
-    bool is_alpha(const char& src);
-    bool is_punct(const char& src);
-    bool is_digit(const char& src);
-    bool is_alnum(const char& src);
-    bool is_xdigit(const char& src);
-    bool is_unicode(const char& src);
-    bool is_character(const char& src);
-
-    // Match a single ctype predicate.
-    const char* space(const char* src);
-    const char* alpha(const char* src);
-    const char* digit(const char* src);
-    const char* xdigit(const char* src);
-    const char* alnum(const char* src);
-    const char* punct(const char* src);
-    const char* unicode(const char* src);
-    const char* character(const char* src);
-
-    // Match multiple ctype characters.
-    const char* spaces(const char* src);
-    const char* digits(const char* src);
-
-    // Whitespace handling.
-    const char* no_spaces(const char* src);
-    const char* optional_spaces(const char* src);
-
-    // Match any single character (/./).
-    const char* any_char(const char* src);
-
-    // Assert word boundary (/\b/)
-    // Is a zero-width positive lookaheads
-    const char* word_boundary(const char* src);
-
-    // Match a single linebreak (/(?:\n|\r\n?)/).
-    const char* re_linebreak(const char* src);
-
-    // Assert string boundaries (/\Z|\z|\A/)
-    // There are zero-width positive lookaheads
-    const char* end_of_line(const char* src);
-    // const char* end_of_string(const char* src);
-    // const char* start_of_string(const char* src);
-
-    // Type definition for prelexer functions
-    typedef const char* (*prelexer)(const char*);
-
-    //####################################
-    // BASIC "REGEX" CONSTRUCTORS
-    //####################################
-
-    // Match a single character literal.
-    // Regex equivalent: /(?:literal)/
-    template <char chr>
-    const char* exactly(const char* src) {
-      return *src == chr ? src + 1 : 0;
-    }
-
-    // Match a string constant.
-    // Regex equivalent: /[axy]/
-    template <const char* str>
-    const char* exactly(const char* src) {
-      if (str == 0) return 0;
-      const char* pre = str;
-      if (src == 0) return 0;
-      // there is a small chance that the search string
-      // is longer than the rest of the string to look at
-      while (*pre && *src == *pre) {
-        ++src, ++pre;
-      }
-      return *pre ? 0 : src;
-    }
-
-    // Match for members of char class.
-    // Regex equivalent: /[axy]/
-    template <const char* char_class>
-    const char* class_char(const char* src) {
-      const char* cc = char_class;
-      while (*cc && *src != *cc) ++cc;
-      return *cc ? src + 1 : 0;
-    }
-
-    // Match for members of char class.
-    // Regex equivalent: /[axy]/
-    template <const char* char_class>
-    const char* class_chars(const char* src) {
-      const char* p = src;
-      while (class_char<char_class>(p)) ++p;
-      return p == src ? 0 : p;
-    }
-
-    // Match all except the supplied one.
-    // Regex equivalent: /[^x]/
-    template <const char chr>
-    const char* any_char_but(const char* src) {
-      return (*src && *src != chr) ? src + 1 : 0;
-    }
-
-    // Succeeds if the matcher fails.
-    // Aka. zero-width negative lookahead.
-    // Regex equivalent: /(?!literal)/
-    template <prelexer mx>
-    const char* negate(const char* src) {
-      return mx(src) ? 0 : src;
-    }
-
-    // Succeeds if the matcher succeeds.
-    // Aka. zero-width positive lookahead.
-    // Regex equivalent: /(?=literal)/
-    // just hangs around until we need it
-    template <prelexer mx>
-    const char* lookahead(const char* src) {
-      return mx(src) ? src : 0;
-    }
-
-    // Tries supplied matchers in order.
-    // Succeeds if one of them succeeds.
-    // Regex equivalent: /(?:FOO|BAR)/
-    template <prelexer... mxs>
-    const char* alternatives(const char* src) {
-      const char* rslt;
-      for (prelexer mx : { mxs... }) {
-        if ((rslt = mx(src))) return rslt;
-      }
-      return 0;
-    }
-
-    // Tries supplied matchers in order.
-    // Succeeds if all of them succeeds.
-    // Regex equivalent: /(?:FOO)(?:BAR)/
-    template <prelexer... mxs>
-    const char* sequence(const char* src) {
-      const char* rslt = src;
-      for (prelexer mx : { mxs... }) {
-        if (!(rslt = mx(rslt))) return 0;
-      }
-      return rslt;
-    }
-
-    // Match a pattern or not. Always succeeds.
-    // Regex equivalent: /(?:literal)?/
-    template <prelexer mx>
-    const char* optional(const char* src) {
-      const char* p = mx(src);
-      return p ? p : src;
-    }
-
-    // Match zero or more of the patterns.
-    // Regex equivalent: /(?:literal)*/
-    template <prelexer mx>
-    const char* zero_plus(const char* src) {
-      const char* p = mx(src);
-      while (p) src = p, p = mx(src);
-      return src;
-    }
-
-    // Match one or more of the patterns.
-    // Regex equivalent: /(?:literal)+/
-    template <prelexer mx>
-    const char* one_plus(const char* src) {
-      const char* p = mx(src);
-      if (!p) return 0;
-      while (p) src = p, p = mx(src);
-      return src;
-    }
-
-    // Match mx non-greedy until delimiter.
-    // Other prelexers are greedy by default.
-    // Regex equivalent: /(?:$mx)*?(?=$delim)\b/
-    template <prelexer mx, prelexer delim>
-    const char* non_greedy(const char* src) {
-      while (!delim(src)) {
-        const char* p = mx(src);
-        if (p == src) return 0;
-        if (p == 0) return 0;
-        src = p;
-      }
-      return src;
-    }
-
-    //####################################
-    // ADVANCED "REGEX" CONSTRUCTORS
-    //####################################
-
-    // Match with word boundary rule.
-    // Regex equivalent: /(?:$mx)\b/
-    template <const char* str>
-    const char* word(const char* src) {
-      return sequence <
-               exactly < str >,
-               word_boundary
-             >(src);
-    }
-
-    template <char chr>
-    const char* loosely(const char* src) {
-      return sequence <
-               optional_spaces,
-               exactly < chr >
-             >(src);
-    }
-    template <const char* str>
-    const char* loosely(const char* src) {
-      return sequence <
-               optional_spaces,
-               exactly < str >
-             >(src);
-    }
-
-  }
-}
-
-#endif
diff --git a/libsass/listize.cpp b/libsass/listize.cpp
deleted file mode 100644
--- a/libsass/listize.cpp
+++ /dev/null
@@ -1,83 +0,0 @@
-#include <iostream>
-#include <typeinfo>
-
-#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)
-  {  }
-
-  Expression* Listize::operator()(Selector_List* sel)
-  {
-    List* l = new (ctx.mem) List(sel->pstate(), sel->length(), List::COMMA);
-    for (size_t i = 0, L = sel->length(); i < L; ++i) {
-      *l << (*sel)[i]->perform(this);
-    }
-    return l;
-  }
-
-  Expression* Listize::operator()(Compound_Selector* sel)
-  {
-    To_String to_string;
-    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);
-    }
-    return new (ctx.mem) String_Constant(sel->pstate(), str);
-  }
-
-  Expression* Listize::operator()(Complex_Selector* sel)
-  {
-    List* l = new (ctx.mem) List(sel->pstate(), 2);
-
-    Compound_Selector* head = sel->head();
-    if (head && !head->is_empty_reference())
-    {
-      Expression* hh = head->perform(this);
-      if (hh) *l << hh;
-    }
-
-    switch(sel->combinator())
-    {
-      case Complex_Selector::PARENT_OF:
-        *l << new (ctx.mem) String_Constant(sel->pstate(), ">");
-      break;
-      case Complex_Selector::ADJACENT_TO:
-        *l << new (ctx.mem) String_Constant(sel->pstate(), "+");
-      break;
-      case Complex_Selector::PRECEDES:
-        *l << new (ctx.mem) String_Constant(sel->pstate(), "~");
-      break;
-      case Complex_Selector::ANCESTOR_OF:
-      break;
-    }
-
-    Complex_Selector* 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);
-    }
-    if (l->length() == 0) return 0;
-    return l;
-  }
-
-  Expression* Listize::operator()(Selector_Reference* sel)
-  {
-    return 0;
-  }
-
-  Expression* Listize::fallback_impl(AST_Node* n)
-  {
-    return static_cast<Expression*>(n);
-  }
-}
diff --git a/libsass/listize.hpp b/libsass/listize.hpp
deleted file mode 100644
--- a/libsass/listize.hpp
+++ /dev/null
@@ -1,41 +0,0 @@
-#ifndef SASS_LISTIZE_H
-#define SASS_LISTIZE_H
-
-#include <vector>
-#include <iostream>
-
-#include "ast.hpp"
-#include "context.hpp"
-#include "operation.hpp"
-#include "environment.hpp"
-
-namespace Sass {
-  using namespace std;
-
-  typedef Environment<AST_Node*> Env;
-  struct Backtrace;
-
-  class Listize : public Operation_CRTP<Expression*, Listize> {
-
-    Context&            ctx;
-
-    Expression* fallback_impl(AST_Node* n);
-
-  public:
-    Listize(Context&);
-    virtual ~Listize() { }
-
-    using Operation<Expression*>::operator();
-
-    Expression* operator()(Selector_List*);
-    Expression* operator()(Complex_Selector*);
-    Expression* operator()(Compound_Selector*);
-    Expression* operator()(Selector_Reference*);
-
-    template <typename U>
-    Expression* fallback(U x) { return fallback_impl(x); }
-  };
-
-}
-
-#endif
diff --git a/libsass/mapping.hpp b/libsass/mapping.hpp
deleted file mode 100644
--- a/libsass/mapping.hpp
+++ /dev/null
@@ -1,18 +0,0 @@
-#ifndef SASS_MAPPING_H
-#define SASS_MAPPING_H
-
-#include "position.hpp"
-
-namespace Sass {
-
-  struct Mapping {
-    Position original_position;
-    Position generated_position;
-
-    Mapping(const Position& original_position, const Position& generated_position)
-    : original_position(original_position), generated_position(generated_position) { }
-  };
-
-}
-
-#endif
diff --git a/libsass/memory_manager.hpp b/libsass/memory_manager.hpp
deleted file mode 100644
--- a/libsass/memory_manager.hpp
+++ /dev/null
@@ -1,57 +0,0 @@
-#ifndef SASS_MEMORY_MANAGER_H
-#define SASS_MEMORY_MANAGER_H
-
-#include <vector>
-#include <iostream>
-
-namespace Sass {
-  using namespace std;
-  /////////////////////////////////////////////////////////////////////////////
-  // 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.
-  /////////////////////////////////////////////////////////////////////////////
-  template <typename T>
-  class Memory_Manager {
-    vector<T*> nodes;
-
-  public:
-    Memory_Manager(size_t size = 0) : nodes(vector<T*>())
-    { nodes.reserve(size); }
-
-    ~Memory_Manager()
-    {
-      for (size_t i = 0, S = nodes.size(); i < S; ++i) {
-        // cout << "deleting " << typeid(*nodes[i]).name() << endl;
-        delete nodes[i];
-      }
-    }
-
-    T* operator()(T* np)
-    {
-      nodes.push_back(np);
-      // cout << "registering " << typeid(*np).name() << endl;
-      return np;
-    }
-
-    void remove(T* np)
-    {
-      nodes.erase(find(nodes.begin(), nodes.end(), np));
-    }
-  };
-}
-
-template <typename T>
-inline void* operator new(size_t size, Sass::Memory_Manager<T>& mem_mgr)
-{ return mem_mgr(static_cast<T*>(operator new(size))); }
-
-template <typename T>
-inline void operator delete(void *np, Sass::Memory_Manager<T>& mem_mgr)
-{
-  mem_mgr.remove(reinterpret_cast<T*>(np));
-  operator delete(np);
-}
-
-#endif
diff --git a/libsass/node.cpp b/libsass/node.cpp
deleted file mode 100644
--- a/libsass/node.cpp
+++ /dev/null
@@ -1,251 +0,0 @@
-#include "node.hpp"
-#include "to_string.hpp"
-#include "context.hpp"
-#include "parser.hpp"
-
-namespace Sass {
-
-
-  Node Node::createCombinator(const Complex_Selector::Combinator& combinator) {
-    NodeDequePtr null;
-    return Node(COMBINATOR, combinator, NULL /*pSelector*/, null /*pCollection*/);
-  }
-
-
-  Node Node::createSelector(Complex_Selector* pSelector, Context& ctx) {
-    NodeDequePtr null;
-
-    Complex_Selector* pStripped = pSelector->clone(ctx);
-    pStripped->tail(NULL);
-    pStripped->combinator(Complex_Selector::ANCESTOR_OF);
-
-    return Node(SELECTOR, Complex_Selector::ANCESTOR_OF, pStripped, null /*pCollection*/);
-  }
-
-
-  Node Node::createCollection() {
-    NodeDequePtr pEmptyCollection = make_shared<NodeDeque>();
-    return Node(COLLECTION, Complex_Selector::ANCESTOR_OF, NULL /*pSelector*/, pEmptyCollection);
-  }
-
-
-  Node Node::createCollection(const NodeDeque& values) {
-    NodeDequePtr pShallowCopiedCollection = make_shared<NodeDeque>(values);
-    return Node(COLLECTION, Complex_Selector::ANCESTOR_OF, NULL /*pSelector*/, pShallowCopiedCollection);
-  }
-
-
-  Node Node::createNil() {
-    NodeDequePtr null;
-    return Node(NIL, Complex_Selector::ANCESTOR_OF, NULL /*pSelector*/, null /*pCollection*/);
-  }
-
-
-  Node::Node(const TYPE& type, Complex_Selector::Combinator combinator, Complex_Selector* pSelector, NodeDequePtr& pCollection)
-  : got_line_feed(false), mType(type), mCombinator(combinator), mpSelector(pSelector), mpCollection(pCollection)
-  { /* if (pSelector) got_line_feed = pSelector->has_line_feed(); */ }
-
-
-  Node Node::clone(Context& ctx) const {
-    NodeDequePtr pNewCollection = 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));
-      }
-    }
-
-    return Node(mType, mCombinator, mpSelector ? mpSelector->clone(ctx) : NULL, pNewCollection);
-  }
-
-
-  bool Node::contains(const Node& potentialChild, bool simpleSelectorOrderDependent) const {
-  	bool found = false;
-
-    for (NodeDeque::iterator iter = mpCollection->begin(), iterEnd = mpCollection->end(); iter != iterEnd; iter++) {
-      Node& toTest = *iter;
-
-      if (nodesEqual(toTest, potentialChild, simpleSelectorOrderDependent)) {
-        found = true;
-        break;
-      }
-    }
-
-    return found;
-  }
-
-
-  bool Node::operator==(const Node& rhs) const {
-  	return nodesEqual(*this, rhs, true /*simpleSelectorOrderDependent*/);
-  }
-
-
-  bool nodesEqual(const Node& lhs, const Node& rhs, bool simpleSelectorOrderDependent) {
-    if (lhs.type() != rhs.type()) {
-      return false;
-    }
-
-    if (lhs.isCombinator()) {
-
-    	return lhs.combinator() == rhs.combinator();
-
-    } else if (lhs.isNil()) {
-
-      return true; // no state to check
-
-    } else if (lhs.isSelector()){
-
-      return selectors_equal(*lhs.selector(), *rhs.selector(), simpleSelectorOrderDependent);
-
-    } else if (lhs.isCollection()) {
-
-      if (lhs.collection()->size() != rhs.collection()->size()) {
-        return false;
-      }
-
-      for (NodeDeque::iterator lhsIter = lhs.collection()->begin(), lhsIterEnd = lhs.collection()->end(),
-           rhsIter = rhs.collection()->begin(); lhsIter != lhsIterEnd; lhsIter++, rhsIter++) {
-
-        if (!nodesEqual(*lhsIter, *rhsIter, simpleSelectorOrderDependent)) {
-          return false;
-        }
-
-      }
-
-      return true;
-
-    }
-
-    // We shouldn't get here.
-    throw "Comparing unknown node types. A new type was probably added and this method wasn't implemented for it.";
-  }
-
-
-  void Node::plus(Node& rhs) {
-  	if (!this->isCollection() || !rhs.isCollection()) {
-    	throw "Both the current node and rhs must be collections.";
-    }
-  	this->collection()->insert(this->collection()->end(), rhs.collection()->begin(), rhs.collection()->end());
-  }
-
-#ifdef DEBUG
-  ostream& operator<<(ostream& os, const Node& node) {
-
-    if (node.isCombinator()) {
-
-      switch (node.combinator()) {
-        case Complex_Selector::ANCESTOR_OF: os << "\" \""; break;
-        case Complex_Selector::PARENT_OF:   os << "\">\""; break;
-        case Complex_Selector::PRECEDES:    os << "\"~\""; break;
-        case Complex_Selector::ADJACENT_TO: os << "\"+\""; break;
-      }
-
-    } else if (node.isNil()) {
-
-      os << "nil";
-
-    } else if (node.isSelector()){
-
-      To_String to_string;
-      os << node.selector()->head()->perform(&to_string);
-
-    } else if (node.isCollection()) {
-
-			os << "[";
-
-      for (NodeDeque::iterator iter = node.collection()->begin(), iterBegin = node.collection()->begin(), iterEnd = node.collection()->end(); iter != iterEnd; iter++) {
-        if (iter != iterBegin) {
-          os << ", ";
-        }
-
-				os << (*iter);
-      }
-
-      os << "]";
-
-    }
-
-    return os;
-
-  }
-#endif
-
-
-  Node complexSelectorToNode(Complex_Selector* pToConvert, Context& ctx) {
-    if (pToConvert == NULL) {
-      return Node::createNil();
-    }
-
-    Node node = Node::createCollection();
-
-    while (pToConvert) {
-
-      // the first Complex_Selector may contain a dummy head pointer, skip it.
-      if (pToConvert->head() != NULL && !pToConvert->head()->is_empty_reference()) {
-        node.collection()->push_back(Node::createSelector(pToConvert, ctx));
-      }
-
-      if (pToConvert->combinator() != Complex_Selector::ANCESTOR_OF) {
-        node.collection()->push_back(Node::createCombinator(pToConvert->combinator()));
-      }
-
-      pToConvert = pToConvert->tail();
-    }
-
-    return node;
-  }
-
-
-  Complex_Selector* 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.";
-    }
-
-
-    NodeDeque& childNodes = *toConvert.collection();
-
-    string noPath("");
-    Position noPosition(-1, -1, -1);
-    Complex_Selector* pFirst = new (ctx.mem) Complex_Selector(ParserState("[NODE]"), Complex_Selector::ANCESTOR_OF, NULL, NULL);
-    Complex_Selector* pCurrent = pFirst;
-
-    for (NodeDeque::iterator childIter = childNodes.begin(), childIterEnd = childNodes.end(); childIter != childIterEnd; childIter++) {
-
-      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()
-        pCurrent = pCurrent->tail();
-      } else if (child.isCombinator()) {
-        pCurrent->combinator(child.combinator());
-
-        // if the next node is also a combinator, create another Complex_Selector to hold it so it doesn't replace the current combinator
-        if (childIter+1 != childIterEnd) {
-          Node& nextNode = *(childIter+1);
-          if (nextNode.isCombinator()) {
-            pCurrent->tail(new (ctx.mem) Complex_Selector(ParserState("[NODE]"), Complex_Selector::ANCESTOR_OF, NULL, NULL));
-            pCurrent = pCurrent->tail();
-          }
-        }
-      } else {
-        throw "The node to convert's children must be only combinators or selectors.";
-      }
-    }
-
-    // Put the dummy Compound_Selector in the first position, for consistency with the rest of libsass
-    Compound_Selector* fakeHead = new (ctx.mem) Compound_Selector(ParserState("[NODE]"), 1);
-    Selector_Reference* selectorRef = new (ctx.mem) Selector_Reference(ParserState("[NODE]"), NULL);
-    fakeHead->elements().push_back(selectorRef);
-    pFirst->head(fakeHead);
-    pFirst->has_line_feed(pFirst->has_line_feed() || pFirst->tail()->has_line_feed() || toConvert.got_line_feed);
-
-    return pFirst;
-  }
-
-
-}
diff --git a/libsass/node.hpp b/libsass/node.hpp
deleted file mode 100644
--- a/libsass/node.hpp
+++ /dev/null
@@ -1,121 +0,0 @@
-#ifndef SASS_NODE_H
-#define SASS_NODE_H
-
-#include <deque>
-#include <iostream>
-#include <memory>
-
-#include "ast.hpp"
-
-
-namespace Sass {
-
-
-  using namespace std;
-
-
-  class Context;
-
-  /*
-   There are a lot of stumbling blocks when trying to port the ruby extend code to C++. The biggest is the choice of
-   data type. The ruby code will pretty seamlessly switch types between an Array<SimpleSequence or Op> (libsass'
-   equivalent is the Complex_Selector) to a Sequence, which contains more metadata about the sequence than just the
-   selector info. They also have the ability to have arbitrary nestings of arrays like [1, [2]], which is hard to
-   implement using Array equivalents in C++ (like the deque or vector). They also have the ability to include nil
-   in the arrays, like [1, nil, 3], which has potential semantic differences than an empty array [1, [], 3]. To be
-   able to represent all of these as unique cases, we need to create a tree of variant objects. The tree nature allows
-   the inconsistent nesting levels. The variant nature (while making some of the C++ code uglier) allows the code to
-   more closely match the ruby code, which is a huge benefit when attempting to implement an complex algorithm like
-   the Extend operator.
-
-   Note that the current libsass data model also pairs the combinator with the Complex_Selector that follows it, but
-   ruby sass has no such restriction, so we attempt to create a data structure that can handle them split apart.
-   */
-
-  class Node;
-  typedef deque<Node> NodeDeque;
-  typedef shared_ptr<NodeDeque> NodeDequePtr;
-
-  class Node {
-  public:
-    enum TYPE {
-      SELECTOR,
-      COMBINATOR,
-      COLLECTION,
-      NIL
-    };
-
-		TYPE type() const { return mType; }
-    bool isCombinator() const { return mType == COMBINATOR; }
-    bool isSelector() const { return mType == SELECTOR; }
-    bool isCollection() const { return mType == COLLECTION; }
-    bool isNil() const { return mType == NIL; }
-    bool got_line_feed;
-
-    Complex_Selector::Combinator combinator() const { return mCombinator; }
-
-    Complex_Selector* selector() { return mpSelector; }
-    const Complex_Selector* 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);
-
-    static Node createCollection();
-    static Node createCollection(const NodeDeque& values);
-
-    static Node createNil();
-
-    Node clone(Context& ctx) const;
-
-    bool operator==(const Node& rhs) const;
-    inline bool operator!=(const Node& rhs) const { return !(*this == rhs); }
-
-
-    /*
-    COLLECTION FUNCTIONS
-
-    Most types don't need any helper methods (nil and combinator due to their simplicity and
-    selector due to the fact that we leverage the non-node selector code on the Complex_Selector
-    whereever possible). The following methods are intended to be called on Node objects whose
-    type is COLLECTION only.
-    */
-
-    // rhs and this must be node collections. Shallow copy the nodes from rhs to the end of this.
-    // This function DOES NOT remove the nodes from rhs.
-    void plus(Node& rhs);
-
-    // potentialChild must be a node collection of selectors/combinators. this must be a collection
-    // of collections of nodes/combinators. This method checks if potentialChild is a child of this
-    // Node.
-    bool contains(const Node& potentialChild, bool simpleSelectorOrderDependent) const;
-
-  private:
-    // 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);
-
-    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
-    NodeDequePtr mpCollection;
-  };
-
-#ifdef DEBUG
-  ostream& operator<<(ostream& os, const Node& node);
-#endif
-  Node complexSelectorToNode(Complex_Selector* pToConvert, Context& ctx);
-  Complex_Selector* nodeToComplexSelector(const Node& toConvert, Context& ctx);
-
-  bool nodesEqual(const Node& one, const Node& two, bool simpleSelectorOrderDependent);
-
-}
-
-#endif
diff --git a/libsass/operation.hpp b/libsass/operation.hpp
deleted file mode 100644
--- a/libsass/operation.hpp
+++ /dev/null
@@ -1,166 +0,0 @@
-#ifndef SASS_OPERATION_H
-#define SASS_OPERATION_H
-
-#include <iostream>
-#include <typeinfo>
-
-#include "ast_fwd_decl.hpp"
-
-namespace Sass {
-  using namespace std;
-
-  template<typename T>
-  class Operation {
-  public:
-    virtual T operator()(AST_Node* 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()(Feature_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;
-    // 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()(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_Constant* x)        = 0;
-    virtual T operator()(Feature_Query* x)          = 0;
-    virtual T operator()(Feature_Query_Condition* 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;
-    // 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;
-    // selectors
-    virtual T operator()(Selector_Schema* x)        = 0;
-    virtual T operator()(Selector_Reference* 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;
-
-    template <typename U>
-    T fallback(U x) { return T(); }
-  };
-
-  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;
-    // 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()(Feature_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); }
-    // 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()(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()(Feature_Query* x)          { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Feature_Query_Condition* 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); }
-    // 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); }
-    // selectors
-    virtual T operator()(Selector_Schema* x)        { return static_cast<D*>(this)->fallback(x); }
-    virtual T operator()(Selector_Reference* 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); }
-
-    template <typename U>
-    T fallback(U x)                                 { return T(); }
-  };
-  template<typename T, typename D>
-  inline Operation_CRTP<T, D>::~Operation_CRTP()    { }
-
-}
-
-#endif
diff --git a/libsass/output.cpp b/libsass/output.cpp
deleted file mode 100644
--- a/libsass/output.cpp
+++ /dev/null
@@ -1,401 +0,0 @@
-#include "ast.hpp"
-#include "output.hpp"
-#include "to_string.hpp"
-
-namespace Sass {
-  using namespace std;
-
-  Output::Output(Context* ctx)
-  : Inspect(Emitter(ctx)),
-    charset(""),
-    top_nodes(0)
-  {}
-
-  Output::~Output() { }
-
-  void Output::fallback_impl(AST_Node* n)
-  {
-    return n->perform(this);
-  }
-
-  void Output::operator()(Import* imp)
-  {
-    top_nodes.push_back(imp);
-  }
-
-  OutputBuffer Output::get_buffer(void)
-  {
-
-    Emitter emitter(ctx);
-    Inspect inspect(emitter);
-
-    size_t size_nodes = top_nodes.size();
-    for (size_t i = 0; i < size_nodes; i++) {
-      top_nodes[i]->perform(&inspect);
-      inspect.append_mandatory_linefeed();
-    }
-
-    // flush scheduled outputs
-    inspect.finalize();
-    // prepend buffer on top
-    prepend_output(inspect.output());
-    // make sure we end with a linefeed
-    if (!ends_with(wbuf.buffer, ctx->linefeed)) {
-      // if the output is not completely empty
-      if (!wbuf.buffer.empty()) append_string(ctx->linefeed);
-    }
-
-    // search for unicode char
-    for(const char& chr : wbuf.buffer) {
-      // skip all ascii chars
-      if (chr >= 0) continue;
-      // declare the charset
-      if (output_style() != COMPRESSED)
-        charset = "@charset \"UTF-8\";"
-                  + ctx->linefeed;
-      else charset = "\xEF\xBB\xBF";
-      // abort search
-      break;
-    }
-
-    // add charset as first line, before comments and imports
-    if (!charset.empty()) prepend_string(charset);
-
-    return wbuf;
-
-  }
-
-  void Output::operator()(Comment* c)
-  {
-    To_String to_string(ctx);
-    string txt = c->text()->perform(&to_string);
-    // if (indentation && txt == "/**/") return;
-    bool important = c->is_important();
-    if (output_style() != COMPRESSED || important) {
-      if (buffer().size() == 0) {
-        top_nodes.push_back(c);
-      } else {
-        in_comment = true;
-        append_indentation();
-        c->text()->perform(this);
-        in_comment = false;
-        if (indentation == 0) {
-          append_mandatory_linefeed();
-        } else {
-          append_optional_linefeed();
-        }
-      }
-    }
-  }
-
-  void Output::operator()(Ruleset* r)
-  {
-    Selector* s     = r->selector();
-    Block*    b     = r->block();
-    bool      decls = false;
-
-    // Filter out rulesets that aren't printable (process its children though)
-    if (!Util::isPrintable(r, output_style())) {
-      for (size_t i = 0, L = b->length(); i < L; ++i) {
-        Statement* stm = (*b)[i];
-        if (dynamic_cast<Has_Block*>(stm)) {
-          stm->perform(this);
-        }
-      }
-      return;
-    }
-
-    if (b->has_non_hoistable()) {
-      decls = true;
-      if (output_style() == NESTED) indentation += r->tabs();
-      if (ctx && ctx->source_comments) {
-        stringstream ss;
-        append_indentation();
-        ss << "/* line " << r->pstate().line+1 << ", " << r->pstate().path << " */";
-        append_string(ss.str());
-        append_optional_linefeed();
-      }
-      s->perform(this);
-      append_scope_opener(b);
-      for (size_t i = 0, L = b->length(); i < L; ++i) {
-        Statement* stm = (*b)[i];
-        bool bPrintExpression = true;
-        // Check print conditions
-        if (typeid(*stm) == typeid(Declaration)) {
-          Declaration* dec = static_cast<Declaration*>(stm);
-          if (dec->value()->concrete_type() == Expression::STRING) {
-            String_Constant* valConst = static_cast<String_Constant*>(dec->value());
-            string val(valConst->value());
-            if (dynamic_cast<String_Quoted*>(valConst)) {
-              if (!valConst->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);
-        }
-      }
-      if (output_style() == NESTED) indentation -= r->tabs();
-      append_scope_closer(b);
-    }
-
-    if (b->has_hoistable()) {
-      if (decls) ++indentation;
-      for (size_t i = 0, L = b->length(); i < L; ++i) {
-        Statement* stm = (*b)[i];
-        if (stm->is_hoistable()) {
-          stm->perform(this);
-        }
-      }
-      if (decls) --indentation;
-    }
-  }
-
-  void Output::operator()(Keyframe_Rule* r)
-  {
-    Block* b = r->block();
-    Selector* v = r->selector();
-
-    if (v) {
-      v->perform(this);
-    }
-
-    if (!b) {
-      append_colon_separator();
-      return;
-    }
-
-    append_scope_opener();
-    for (size_t i = 0, L = b->length(); i < L; ++i) {
-      Statement* stm = (*b)[i];
-      if (!stm->is_hoistable()) {
-        stm->perform(this);
-        if (i < L - 1) append_special_linefeed();
-      }
-    }
-
-    for (size_t i = 0, L = b->length(); i < L; ++i) {
-      Statement* stm = (*b)[i];
-      if (stm->is_hoistable()) {
-        stm->perform(this);
-      }
-    }
-
-    append_scope_closer();
-  }
-
-  void Output::operator()(Feature_Block* f)
-  {
-    if (f->is_invisible()) return;
-
-    Feature_Query* q    = f->feature_queries();
-    Block* b            = f->block();
-
-    // Filter out feature blocks that aren't printable (process its children though)
-    if (!Util::isPrintable(f, output_style())) {
-      for (size_t i = 0, L = b->length(); i < L; ++i) {
-        Statement* stm = (*b)[i];
-        if (dynamic_cast<Has_Block*>(stm)) {
-          stm->perform(this);
-        }
-      }
-      return;
-    }
-
-    if (output_style() == NESTED) indentation += f->tabs();
-    append_indentation();
-    append_token("@supports", f);
-    append_mandatory_space();
-    q->perform(this);
-    append_scope_opener();
-
-    Selector* e = f->selector();
-    if (e && b->has_non_hoistable()) {
-      // JMA - hoisted, output the non-hoistable in a nested block, followed by the hoistable
-      e->perform(this);
-      append_scope_opener();
-
-      for (size_t i = 0, L = b->length(); i < L; ++i) {
-        Statement* stm = (*b)[i];
-        if (!stm->is_hoistable()) {
-          stm->perform(this);
-        }
-      }
-
-      append_scope_closer();
-
-      for (size_t i = 0, L = b->length(); i < L; ++i) {
-        Statement* stm = (*b)[i];
-        if (stm->is_hoistable()) {
-          stm->perform(this);
-        }
-      }
-    }
-    else {
-      // JMA - not hoisted, just output in order
-      for (size_t i = 0, L = b->length(); i < L; ++i) {
-        Statement* stm = (*b)[i];
-        stm->perform(this);
-        if (i < L - 1) append_special_linefeed();
-      }
-    }
-
-    if (output_style() == NESTED) indentation -= f->tabs();
-
-    append_scope_closer();
-
-  }
-
-  void Output::operator()(Media_Block* m)
-  {
-    if (m->is_invisible()) return;
-
-    List*  q     = m->media_queries();
-    Block* b     = m->block();
-
-    // Filter out media blocks that aren't printable (process its children though)
-    if (!Util::isPrintable(m, output_style())) {
-      for (size_t i = 0, L = b->length(); i < L; ++i) {
-        Statement* stm = (*b)[i];
-        if (dynamic_cast<Has_Block*>(stm)) {
-          stm->perform(this);
-        }
-      }
-      return;
-    }
-    if (output_style() == NESTED) indentation += m->tabs();
-    append_indentation();
-    append_token("@media", m);
-    append_mandatory_space();
-    in_media_block = true;
-    q->perform(this);
-    in_media_block = false;
-    append_scope_opener();
-
-    Selector* e = m->selector();
-    if (e && b->has_non_hoistable()) {
-      // JMA - hoisted, output the non-hoistable in a nested block, followed by the hoistable
-      e->perform(this);
-      append_scope_opener();
-
-      for (size_t i = 0, L = b->length(); i < L; ++i) {
-        Statement* stm = (*b)[i];
-        if (!stm->is_hoistable()) {
-          stm->perform(this);
-        }
-      }
-
-      append_scope_closer();
-
-      for (size_t i = 0, L = b->length(); i < L; ++i) {
-        Statement* stm = (*b)[i];
-        if (stm->is_hoistable()) {
-          stm->perform(this);
-        }
-      }
-    }
-    else {
-      // JMA - not hoisted, just output in order
-      for (size_t i = 0, L = b->length(); i < L; ++i) {
-        Statement* stm = (*b)[i];
-        stm->perform(this);
-        if (i < L - 1) append_special_linefeed();
-      }
-    }
-
-    if (output_style() == NESTED) indentation -= m->tabs();
-    append_scope_closer();
-  }
-
-  void Output::operator()(At_Rule* a)
-  {
-    string      kwd   = a->keyword();
-    Selector*   s     = a->selector();
-    Expression* v     = a->value();
-    Block*      b     = a->block();
-
-    append_indentation();
-    append_token(kwd, a);
-    if (s) {
-      append_mandatory_space();
-      in_wrapped = true;
-      s->perform(this);
-      in_wrapped = false;
-    }
-    else if (v) {
-      append_mandatory_space();
-      v->perform(this);
-    }
-    if (!b) {
-      append_delimiter();
-      return;
-    }
-
-    if (b->is_invisible() || b->length() == 0) {
-      return append_string(" {}");
-    }
-
-    append_scope_opener();
-
-    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();
-      }
-    }
-
-    append_scope_closer();
-  }
-
-  void Output::operator()(String_Quoted* s)
-  {
-    if (s->quote_mark()) {
-      append_token(quote(s->value(), s->quote_mark()), s);
-    } else if (!in_comment) {
-      append_token(string_to_output(s->value()), s);
-    } else {
-      append_token(s->value(), s);
-    }
-  }
-
-  void Output::operator()(String_Constant* s)
-  {
-    if (String_Quoted* quoted = dynamic_cast<String_Quoted*>(s)) {
-      return Output::operator()(quoted);
-    } else {
-      string value(s->value());
-      if (s->can_compress_whitespace() && output_style() == COMPRESSED) {
-        value.erase(std::remove_if(value.begin(), value.end(), ::isspace), value.end());
-      }
-      if (!in_comment) {
-        append_token(string_to_output(value), s);
-      } else {
-        append_token(value, s);
-      }
-    }
-  }
-
-}
diff --git a/libsass/output.hpp b/libsass/output.hpp
deleted file mode 100644
--- a/libsass/output.hpp
+++ /dev/null
@@ -1,55 +0,0 @@
-#ifndef SASS_OUTPUT_H
-#define SASS_OUTPUT_H
-
-#include <string>
-#include <vector>
-
-#include "util.hpp"
-#include "inspect.hpp"
-#include "operation.hpp"
-
-namespace Sass {
-  class Context;
-  using namespace std;
-
-  // Refactor to make it generic to find linefeed (look behind)
-  inline bool ends_with(std::string const & value, std::string const & ending)
-  {
-    if (ending.size() > value.size()) return false;
-    return std::equal(ending.rbegin(), ending.rend(), value.rbegin());
-  }
-
-  class Output : public Inspect {
-  protected:
-    using Inspect::operator();
-
-  public:
-    // change to Emitter
-    Output(Context* ctx);
-    virtual ~Output();
-
-  protected:
-    string charset;
-    vector<AST_Node*> top_nodes;
-
-  public:
-    OutputBuffer get_buffer(void);
-
-    virtual void operator()(Ruleset*);
-    // virtual void operator()(Propset*);
-    virtual void operator()(Feature_Block*);
-    virtual void operator()(Media_Block*);
-    virtual void operator()(At_Rule*);
-    virtual void operator()(Keyframe_Rule*);
-    virtual void operator()(Import*);
-    virtual void operator()(Comment*);
-    virtual void operator()(String_Quoted*);
-    virtual void operator()(String_Constant*);
-
-    void fallback_impl(AST_Node* n);
-
-  };
-
-}
-
-#endif
diff --git a/libsass/parser.cpp b/libsass/parser.cpp
deleted file mode 100644
--- a/libsass/parser.cpp
+++ /dev/null
@@ -1,2408 +0,0 @@
-#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 "sass_functions.h"
-
-#include <typeinfo>
-
-namespace Sass {
-  using namespace std;
-  using namespace Constants;
-
-  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 = 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 = 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_group();
-  }
-
-  bool Parser::peek_newline(const char* start)
-  {
-    return peek_linefeed(start ? start : position);
-  }
-
-  Parser Parser::from_token(Token t, Context& ctx, ParserState pstate)
-  {
-    Parser p(ctx, pstate);
-    p.source   = t.begin;
-    p.position = p.source;
-    p.end      = t.end;
-    Block* root = new (ctx.mem) Block(pstate);
-    p.block_stack.push_back(root);
-    root->is_root(true);
-    return p;
-  }
-
-  Block* Parser::parse()
-  {
-    Block* root = new (ctx.mem) Block(pstate);
-    block_stack.push_back(root);
-    root->is_root(true);
-    read_bom();
-
-    if (ctx.queue.size() == 1) {
-      Import* pre = new (ctx.mem) Import(pstate);
-      string load_path(ctx.queue[0].load_path);
-      do_import(load_path, pre, ctx.c_headers, false);
-      ctx.head_imports = ctx.queue.size() - 1;
-      if (!pre->urls().empty()) (*root) << pre;
-      if (!pre->files().empty()) {
-        for (size_t i = 0, S = pre->files().size(); i < S; ++i) {
-          (*root) << new (ctx.mem) Import_Stub(pstate, pre->files()[i]);
-        }
-      }
-    }
-
-    bool semicolon = false;
-    string(error_message);
-    lex< optional_spaces >();
-    Selector_Lookahead lookahead_result;
-    while (position < end) {
-      parse_block_comments(root);
-      if (peek< kwd_import >()) {
-        Import* imp = parse_import();
-        if (!imp->urls().empty()) (*root) << imp;
-        if (!imp->files().empty()) {
-          for (size_t i = 0, S = imp->files().size(); i < S; ++i) {
-            (*root) << new (ctx.mem) Import_Stub(pstate, imp->files()[i]);
-          }
-        }
-        semicolon = true;
-        error_message = "top-level @import directive must be terminated by ';'";
-      }
-      else if (peek< kwd_mixin >() || peek< kwd_function >()) {
-        (*root) << parse_definition();
-      }
-      else if (peek< variable >()) {
-        (*root) << parse_assignment();
-        semicolon = true;
-        error_message = "top-level variable binding must be terminated by ';'";
-      }
-      /*else if (peek< sequence< optional< exactly<'*'> >, alternatives< identifier_schema, identifier >, optional_spaces, exactly<':'>, optional_spaces, exactly<'{'> > >(position)) {
-        (*root) << parse_propset();
-      }*/
-      else if (peek< kwd_include >() /* || peek< exactly<'+'> >() */) {
-        Mixin_Call* mixin_call = parse_mixin_call();
-        (*root) << mixin_call;
-        if (!mixin_call->block()) {
-          semicolon = true;
-          error_message = "top-level @include directive must be terminated by ';'";
-        }
-      }
-      else if (peek< kwd_if_directive >()) {
-        (*root) << parse_if_directive();
-      }
-      else if (peek< kwd_for_directive >()) {
-        (*root) << parse_for_directive();
-      }
-      else if (peek< kwd_each_directive >()) {
-        (*root) << parse_each_directive();
-      }
-      else if (peek< kwd_while_directive >()) {
-        (*root) << parse_while_directive();
-      }
-      else if (peek< kwd_media >()) {
-        (*root) << parse_media_block();
-      }
-      else if (peek< kwd_at_root >()) {
-        (*root) << parse_at_root_block();
-      }
-      else if (peek< kwd_supports >()) {
-        (*root) << parse_feature_block();
-      }
-      else if (peek< kwd_warn >()) {
-        (*root) << parse_warning();
-        semicolon = true;
-        error_message = "top-level @warn directive must be terminated by ';'";
-      }
-      else if (peek< kwd_err >()) {
-        (*root) << parse_error();
-        semicolon = true;
-        error_message = "top-level @error directive must be terminated by ';'";
-      }
-      else if (peek< kwd_dbg >()) {
-        (*root) << parse_debug();
-        semicolon = true;
-        error_message = "top-level @debug directive must be terminated by ';'";
-      }
-      // ignore the @charset directive for now
-      else if (lex< exactly< charset_kwd > >()) {
-        lex< quoted_string >();
-        lex< one_plus< exactly<';'> > >();
-      }
-      else if (peek< at_keyword >()) {
-        At_Rule* at_rule = parse_at_rule();
-        (*root) << at_rule;
-        if (!at_rule->block()){
-          semicolon = true;
-          error_message = "top-level directive must be terminated by ';'";
-        }
-      }
-      else if ((lookahead_result = lookahead_for_selector(position)).found) {
-        (*root) << parse_ruleset(lookahead_result);
-      }
-      else if (peek< exactly<';'> >()) {
-        lex< one_plus< exactly<';'> > >();
-      }
-      else {
-        lex< css_whitespace >();
-        if (position >= end) break;
-        error("invalid top-level expression", after_token);
-      }
-      if (semicolon) {
-        if (!lex< one_plus< exactly<';'> > >() && peek_css< optional_css_whitespace >() != end)
-        { error(error_message, pstate); }
-        semicolon = false;
-      }
-      lex< optional_spaces >();
-    }
-    block_stack.pop_back();
-    return root;
-  }
-
-  void Parser::add_single_file (Import* imp, string import_path) {
-
-    string extension;
-    string unquoted(unquote(import_path));
-    if (unquoted.length() > 4) { // 2 quote marks + the 4 chars in .css
-      // a string constant is guaranteed to end with a quote mark, so make sure to skip it when indexing from the end
-      extension = unquoted.substr(unquoted.length() - 4, 4);
-    }
-
-    if (extension == ".css") {
-      String_Constant* loc = new (ctx.mem) String_Constant(pstate, unquote(import_path));
-      Argument* loc_arg = new (ctx.mem) Argument(pstate, loc);
-      Arguments* loc_args = new (ctx.mem) Arguments(pstate);
-      (*loc_args) << loc_arg;
-      Function_Call* new_url = new (ctx.mem) Function_Call(pstate, "url", loc_args);
-      imp->urls().push_back(new_url);
-    }
-    else {
-      string current_dir = File::dir_name(path);
-      string resolved(ctx.add_file(current_dir, unquoted));
-      if (resolved.empty()) error("file to import not found or unreadable: " + unquoted + "\nCurrent dir: " + current_dir, pstate);
-      imp->files().push_back(resolved);
-    }
-
-  }
-
-  void Parser::import_single_file (Import* imp, string import_path) {
-
-    if (!unquote(import_path).substr(0, 7).compare("http://") ||
-        !unquote(import_path).substr(0, 8).compare("https://") ||
-        !unquote(import_path).substr(0, 2).compare("//"))
-    {
-      imp->urls().push_back(new (ctx.mem) String_Quoted(pstate, import_path));
-    }
-    else {
-      add_single_file(imp, import_path);
-    }
-
-  }
-
-  bool Parser::do_import(const string& import_path, Import* imp, vector<Sass_Importer_Entry> importers, bool only_one)
-  {
-    bool has_import = false;
-    string load_path = unquote(import_path);
-    for (auto importer : importers) {
-      // int priority = sass_importer_get_priority(importer);
-      Sass_Importer_Fn fn = sass_importer_get_function(importer);
-      if (Sass_Import_List includes =
-          fn(load_path.c_str(), importer, ctx.c_compiler)
-      ) {
-        Sass_Import_List list = includes;
-        while (*includes) {
-          Sass_Import_Entry include = *includes;
-          const char *file = sass_import_get_path(include);
-          char* source = sass_import_take_source(include);
-          size_t line = sass_import_get_error_line(include);
-          size_t column = sass_import_get_error_column(include);
-          const char* message = sass_import_get_error_message(include);
-          if (message) {
-            if (line == string::npos && column == string::npos) error(message, pstate);
-            else error(message, ParserState(message, source, Position(line, column)));
-          } else if (source) {
-            if (file) {
-              ctx.add_source(file, load_path, source);
-              imp->files().push_back(file);
-            } else {
-              ctx.add_source(load_path, load_path, source);
-              imp->files().push_back(load_path);
-            }
-          } else if(file) {
-            import_single_file(imp, file);
-          }
-          ++includes;
-        }
-        // deallocate returned memory
-        sass_delete_import_list(list);
-        // set success flag
-        has_import = true;
-        // break import chain
-        if (only_one) return true;
-      }
-    }
-    // return result
-    return has_import;
-  }
-
-  Import* Parser::parse_import()
-  {
-    lex< kwd_import >();
-    Import* imp = new (ctx.mem) Import(pstate);
-    bool first = true;
-    do {
-      while (lex< block_comment >());
-      if (lex< quoted_string >()) {
-        if (!do_import(lexed, imp, ctx.c_importers, true))
-        {
-          // push single file import
-          import_single_file(imp, lexed);
-        }
-      }
-      else if (lex< uri_prefix >()) {
-        Arguments* args = new (ctx.mem) Arguments(pstate);
-        Function_Call* result = new (ctx.mem) Function_Call(pstate, "url", args);
-        if (lex< quoted_string >()) {
-          Expression* the_url = parse_string();
-          *args << new (ctx.mem) Argument(the_url->pstate(), the_url);
-        }
-        else if (lex < uri_value >(position)) { // chunk seems to work too!
-          String* the_url = parse_interpolated_chunk(lexed);
-          *args << new (ctx.mem) Argument(the_url->pstate(), the_url);
-        }
-        else if (peek < skip_over_scopes < exactly < '(' >, exactly < ')' > > >(position)) {
-          Expression* the_url = parse_list(); // parse_interpolated_chunk(lexed);
-          *args << new (ctx.mem) Argument(the_url->pstate(), the_url);
-        }
-        else {
-          error("malformed URL", pstate);
-        }
-        if (!lex< exactly<')'> >()) error("URI is missing ')'", pstate);
-        imp->urls().push_back(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<','> >());
-    return imp;
-  }
-
-  Definition* Parser::parse_definition()
-  {
-    Definition::Type which_type = Definition::MIXIN;
-    if      (lex< kwd_mixin >())    which_type = Definition::MIXIN;
-    else if (lex< kwd_function >()) which_type = Definition::FUNCTION;
-    string which_str(lexed);
-    if (!lex< identifier >()) error("invalid name in " + which_str + " definition", pstate);
-    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 (!peek< exactly<'{'> >()) error("body for " + which_str + " " + name + " must begin with a '{'", pstate);
-    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 = new (ctx.mem) Definition(source_position_of_def, name, params, body, &ctx, which_type);
-    return def;
-  }
-
-  Parameters* Parser::parse_parameters()
-  {
-    string name(lexed);
-    Position position = after_token;
-    Parameters* params = 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 >();
-    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 = new (ctx.mem) Parameter(pos, name, val, is_rest);
-    return p;
-  }
-
-  Mixin_Call* Parser::parse_mixin_call()
-  {
-    lex< kwd_include >() /* || lex< exactly<'+'> >() */;
-    if (!lex< identifier >()) error("invalid name in @include directive", pstate);
-    ParserState source_position_of_call = pstate;
-    string name(Util::normalize_underscores(lexed));
-    Arguments* args = parse_arguments();
-    Block* content = 0;
-    if (peek< exactly<'{'> >()) {
-      content = parse_block();
-    }
-    Mixin_Call* the_call = new (ctx.mem) Mixin_Call(source_position_of_call, name, args, content);
-    return the_call;
-  }
-
-  Arguments* Parser::parse_arguments(bool has_url)
-  {
-    string name(lexed);
-    Position position = after_token;
-    Arguments* args = new (ctx.mem) Arguments(pstate);
-    if (lex_css< exactly<'('> >()) {
-      // if there's anything there at all
-      if (!peek_css< exactly<')'> >()) {
-        do (*args) << parse_argument(has_url);
-        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(bool has_url)
-  {
-
-    Argument* arg;
-    // some urls can look like line comments (parse literally - chunk would not work)
-    if (has_url && lex< sequence < uri_value, lookahead < loosely<')'> > > >(false)) {
-      String* the_url = parse_interpolated_chunk(lexed);
-      arg = new (ctx.mem) Argument(the_url->pstate(), the_url);
-    }
-    else if (peek_css< sequence < variable, optional_css_comments, exactly<':'> > >()) {
-      lex_css< variable >();
-      string name(Util::normalize_underscores(lexed));
-      ParserState p = pstate;
-      lex_css< exactly<':'> >();
-      Expression* val = parse_space_list();
-      val->is_delayed(false);
-      arg = 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 = new (ctx.mem) Argument(pstate, val, "", is_arglist, is_keyword);
-    }
-    return arg;
-  }
-
-  Assignment* Parser::parse_assignment()
-  {
-    lex< variable >();
-    string name(Util::normalize_underscores(lexed));
-    ParserState var_source_position = pstate;
-    if (!lex< exactly<':'> >()) error("expected ':' after " + name + " in assignment statement", pstate);
-    Expression* val;
-    Selector_Lookahead lookahead = lookahead_for_value(position);
-    if (lookahead.has_interpolants && lookahead.found) {
-      val = parse_value_schema(lookahead.found);
-    } else {
-      val = parse_list();
-    }
-    val->is_delayed(false);
-    bool is_default = false;
-    bool is_global = false;
-    while (peek< default_flag >() || peek< global_flag >()) {
-      is_default = lex< default_flag >() || is_default;
-      is_global = lex< global_flag >() || is_global;
-    }
-    Assignment* var = new (ctx.mem) Assignment(var_source_position, name, val, is_default, is_global);
-    return var;
-  }
-
-  /* not used anymore - remove?
-  Propset* Parser::parse_propset()
-  {
-    String* property_segment;
-    if (peek< sequence< optional< exactly<'*'> >, identifier_schema > >()) {
-      property_segment = parse_identifier_schema();
-    }
-    else {
-      lex< sequence< optional< exactly<'*'> >, identifier > >();
-      property_segment = new (ctx.mem) String_Quoted(pstate, lexed);
-    }
-    Propset* propset = new (ctx.mem) Propset(pstate, property_segment);
-    lex< exactly<':'> >();
-
-    if (!peek< exactly<'{'> >()) error("expected a '{' after namespaced property", pstate);
-
-    propset->block(parse_block());
-
-    propset->tabs(indentation);
-
-    return propset;
-  } */
-
-  Ruleset* Parser::parse_ruleset(Selector_Lookahead lookahead)
-  {
-    Selector* sel;
-    if (lookahead.has_interpolants) {
-      sel = parse_selector_schema(lookahead.found);
-    }
-    else {
-      sel = parse_selector_group();
-    }
-    bool old_in_at_root = in_at_root;
-    ParserState r_source_position = pstate;
-    lex < css_comments >();
-    in_at_root = false;
-    if (!peek< exactly<'{'> >()) error("expected a '{' after the selector", pstate);
-    Block* block = parse_block();
-    in_at_root = old_in_at_root;
-    old_in_at_root = false;
-    Ruleset* ruleset = new (ctx.mem) Ruleset(r_source_position, sel, block);
-    return ruleset;
-  }
-
-  Selector_Schema* Parser::parse_selector_schema(const char* end_of_selector)
-  {
-    lex< optional_spaces >();
-    const char* i = position;
-    String_Schema* schema = new (ctx.mem) String_Schema(pstate);
-    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) << new (ctx.mem) String_Quoted(pstate, string(i, p));
-        // skip to the delimiter by skipping occurences in quoted strings
-        if (peek < sequence < optional_spaces, exactly<rbrace> > >(p+2)) { position = p+2;
-          css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
-        }
-        const char* j = skip_over_scopes< exactly<hash_lbrace>, exactly<rbrace> >(p + 2, end_of_selector);
-        Expression* interpolant = Parser::from_c_str(p+2, j, ctx, pstate).parse_list();
-        interpolant->is_interpolant(true);
-        (*schema) << interpolant;
-        i = j;
-      }
-      // no more interpolants have been found
-      // add the last segment if there is one
-      else {
-        if (i < end_of_selector) (*schema) << new (ctx.mem) String_Quoted(pstate, string(i, end_of_selector));
-        break;
-      }
-    }
-    position = end_of_selector;
-    Selector_Schema* selector_schema = new (ctx.mem) Selector_Schema(pstate, schema);
-    selector_schema->media_block(last_media_block);
-    selector_schema->last_block(block_stack.back());
-    return selector_schema;
-  }
-
-  Selector_List* Parser::parse_selector_group()
-  {
-    bool reloop = true;
-    To_String to_string(&ctx);
-    lex< css_whitespace >();
-    Selector_List* group = new (ctx.mem) Selector_List(pstate);
-    group->media_block(last_media_block);
-    group->last_block(block_stack.back());
-    do {
-      reloop = false;
-      if (peek< alternatives <
-            exactly<'{'>,
-            exactly<'}'>,
-            exactly<')'>,
-            exactly<';'>
-          > >())
-        break; // in case there are superfluous commas at the end
-      Complex_Selector* comb = parse_selector_combination();
-      if (!comb->has_reference() && !in_at_root) {
-        ParserState sel_source_position = pstate;
-        Selector_Reference* ref = new (ctx.mem) Selector_Reference(sel_source_position);
-        Compound_Selector* ref_wrap = new (ctx.mem) Compound_Selector(sel_source_position);
-        ref_wrap->media_block(last_media_block);
-        ref_wrap->last_block(block_stack.back());
-        (*ref_wrap) << ref;
-        if (!comb->head()) {
-          comb->head(ref_wrap);
-          comb->has_reference(true);
-        }
-        else {
-          comb = new (ctx.mem) Complex_Selector(sel_source_position, Complex_Selector::ANCESTOR_OF, ref_wrap, comb);
-          comb->media_block(last_media_block);
-          comb->last_block(block_stack.back());
-          comb->has_reference(true);
-        }
-        if (peek_newline()) ref_wrap->has_line_break(true);
-      }
-      while (peek_css< exactly<','> >())
-      {
-        // consume everything up and including the comma speparator
-        reloop = lex< sequence < optional_css_comments, exactly<','> > >() != 0;
-        // remember line break (also between some commas)
-        if (peek_newline()) comb->has_line_feed(true);
-        if (comb->tail() && peek_newline()) comb->tail()->has_line_feed(true);
-        if (comb->tail() && comb->tail()->head() && peek_newline()) comb->tail()->head()->has_line_feed(true);
-        // remember line break (also between some commas)
-      }
-      (*group) << comb;
-    }
-    while (reloop);
-    while (lex< optional >()) {
-      group->is_optional(true);
-    }
-    return group;
-  }
-
-  Complex_Selector* Parser::parse_selector_combination()
-  {
-    Position sel_source_position(-1);
-    Compound_Selector* lhs;
-    if (peek_css< alternatives <
-          exactly<'+'>,
-          exactly<'~'>,
-          exactly<'>'>
-        > >())
-    // no selector before the combinator
-    { lhs = 0; }
-    else {
-      lhs = parse_simple_selector_sequence();
-      sel_source_position = before_token;
-      lhs->has_line_break(peek_newline());
-    }
-
-    Complex_Selector::Combinator cmb;
-    if      (lex< exactly<'+'> >()) cmb = Complex_Selector::ADJACENT_TO;
-    else if (lex< exactly<'~'> >()) cmb = Complex_Selector::PRECEDES;
-    else if (lex< exactly<'>'> >()) cmb = Complex_Selector::PARENT_OF;
-    else                            cmb = Complex_Selector::ANCESTOR_OF;
-    bool cpx_lf = peek_newline();
-
-    Complex_Selector* rhs;
-    if (peek_css< alternatives <
-                exactly<','>,
-                exactly<')'>,
-                exactly<'{'>,
-                exactly<'}'>,
-                exactly<';'>,
-                optional
-        > >())
-    // no selector after the combinator
-    { rhs = 0; }
-    else {
-      rhs = parse_selector_combination();
-      sel_source_position = before_token;
-    }
-    if (!sel_source_position.line) sel_source_position = before_token;
-    Complex_Selector* cpx = new (ctx.mem) Complex_Selector(ParserState(path, source, sel_source_position), cmb, lhs, rhs);
-    cpx->media_block(last_media_block);
-    cpx->last_block(block_stack.back());
-    if (cpx_lf) cpx->has_line_break(cpx_lf);
-    return cpx;
-  }
-
-  Compound_Selector* Parser::parse_simple_selector_sequence()
-  {
-    Compound_Selector* seq = new (ctx.mem) Compound_Selector(pstate);
-    seq->media_block(last_media_block);
-    seq->last_block(block_stack.back());
-    bool sawsomething = false;
-    if (lex_css< exactly<'&'> >()) {
-      // check if we have a parent selector on the root level block
-      if (block_stack.back() && block_stack.back()->is_root()) {
-        //error("Base-level rules cannot contain the parent-selector-referencing character '&'.", pstate);
-      }
-      (*seq) << new (ctx.mem) Selector_Reference(pstate);
-      sawsomething = true;
-      // if you see a space after a &, then you're done
-      if(peek< spaces >() || peek< alternatives < spaces, exactly<';'> > >()) {
-        return seq;
-      }
-    }
-    if (sawsomething && lex_css< sequence< negate< functional >, alternatives< identifier_alnums, universal, quoted_string, dimension, percentage, number > > >()) {
-      // saw an ampersand, then allow type selectors with arbitrary number of hyphens at the beginning
-      (*seq) << new (ctx.mem) Type_Selector(pstate, unquote(lexed));
-    } else if (lex_css< sequence< negate< functional >, alternatives< type_selector, universal, quoted_string, dimension, percentage, number > > >()) {
-      // if you see a type selector
-      (*seq) << new (ctx.mem) Type_Selector(pstate, lexed);
-      sawsomething = true;
-    }
-    if (!sawsomething) {
-      // don't blindly do this if you saw a & or selector
-      (*seq) << parse_simple_selector();
-    }
-
-    while (!peek< spaces >(position) &&
-           !(peek_css < alternatives <
-               exactly<'+'>,
-               exactly<'~'>,
-               exactly<'>'>,
-               exactly<','>,
-               exactly<')'>,
-               exactly<'{'>,
-               exactly<'}'>,
-               exactly<';'>
-             > >(position))) {
-      (*seq) << parse_simple_selector();
-    }
-    return seq;
-  }
-
-  Simple_Selector* Parser::parse_simple_selector()
-  {
-    lex < css_comments >();
-    if (lex< alternatives < id_name, class_name > >()) {
-      return new (ctx.mem) Selector_Qualifier(pstate, unquote(lexed));
-    }
-    else if (lex< quoted_string >()) {
-      return new (ctx.mem) Type_Selector(pstate, unquote(lexed));
-    }
-    else if (lex< alternatives < number, kwd_sel_deep > >()) {
-      return new (ctx.mem) Type_Selector(pstate, lexed);
-    }
-    else if (peek< pseudo_not >()) {
-      return parse_negated_selector();
-    }
-    else if (peek< exactly<':'> >(position) || peek< functional >()) {
-      return parse_pseudo_selector();
-    }
-    else if (peek< exactly<'['> >(position)) {
-      return parse_attribute_selector();
-    }
-    else if (lex< placeholder >()) {
-      Selector_Placeholder* sel = new (ctx.mem) Selector_Placeholder(pstate, unquote(lexed));
-      sel->media_block(last_media_block);
-      sel->last_block(block_stack.back());
-      return sel;
-    }
-    else {
-      error("invalid selector after " + lexed.to_string(), pstate);
-    }
-    // unreachable statement
-    return 0;
-  }
-
-  Wrapped_Selector* Parser::parse_negated_selector()
-  {
-    lex< pseudo_not >();
-    string name(lexed);
-    ParserState nsource_position = pstate;
-    Selector* negated = parse_selector_group();
-    if (!lex< exactly<')'> >()) {
-      error("negated selector is missing ')'", pstate);
-    }
-    return new (ctx.mem) Wrapped_Selector(nsource_position, name, negated);
-  }
-
-  Simple_Selector* Parser::parse_pseudo_selector() {
-    if (lex< sequence< pseudo_prefix, functional > >() || lex< functional >()) {
-      string name(lexed);
-      String* expr = 0;
-      ParserState p = pstate;
-      Selector* wrapped = 0;
-      if (lex< alternatives< even, odd > >()) {
-        expr = new (ctx.mem) String_Quoted(p, lexed);
-      }
-      else if (lex< binomial >(position)) {
-        expr = new (ctx.mem) String_Constant(p, lexed);
-        ((String_Constant*)expr)->can_compress_whitespace(true);
-      }
-      else if (peek< sequence< optional<sign>,
-                               zero_plus<digit>,
-                               exactly<'n'>,
-                               optional_css_whitespace,
-                               exactly<')'> > >()) {
-        lex< sequence< optional<sign>,
-                       zero_plus<digit>,
-                       exactly<'n'> > >();
-        expr = new (ctx.mem) String_Quoted(p, lexed);
-      }
-      else if (lex< sequence< optional<sign>, one_plus < digit > > >()) {
-        expr = new (ctx.mem) String_Quoted(p, lexed);
-      }
-      else if (peek< sequence< identifier, optional_css_whitespace, exactly<')'> > >()) {
-        lex< identifier >();
-        expr = new (ctx.mem) String_Quoted(p, lexed);
-      }
-      else if (lex< quoted_string >()) {
-        expr = new (ctx.mem) String_Quoted(p, lexed);
-      }
-      else if (peek< exactly<')'> >()) {
-        expr = new (ctx.mem) String_Constant(p, "");
-      }
-      else {
-        wrapped = parse_selector_group();
-      }
-      if (!lex< exactly<')'> >()) error("unterminated argument to " + name + "...)", pstate);
-      if (wrapped) {
-        return new (ctx.mem) Wrapped_Selector(p, name, wrapped);
-      }
-      return new (ctx.mem) Pseudo_Selector(p, name, expr);
-    }
-    else if (lex < sequence< pseudo_prefix, identifier > >()) {
-      return new (ctx.mem) Pseudo_Selector(pstate, unquote(lexed));
-    }
-    else {
-      error("unrecognized pseudo-class or pseudo-element", pstate);
-    }
-    // unreachable statement
-    return 0;
-  }
-
-  Attribute_Selector* Parser::parse_attribute_selector()
-  {
-    lex_css< exactly<'['> >();
-    ParserState p = pstate;
-    if (!lex_css< attribute_name >()) error("invalid attribute name in attribute selector", pstate);
-    string name(lexed);
-    if (lex_css< exactly<']'> >()) return 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);
-    }
-    string matcher(lexed);
-
-    String* value = 0;
-    if (lex_css< identifier >()) {
-      value = 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< exactly<']'> >()) error("unterminated attribute selector for " + name, pstate);
-    return new (ctx.mem) Attribute_Selector(p, name, matcher, value);
-  }
-
-  /* parse block comment and add to block */
-  void Parser::parse_block_comments(Block* block)
-  {
-    while (lex< block_comment >()) {
-      bool is_important = lexed.begin[2] == '!';
-      String*  contents = parse_interpolated_chunk(lexed);
-      (*block) << new (ctx.mem) Comment(pstate, contents, is_important);
-    }
-  }
-
-  Block* Parser::parse_block()
-  {
-    lex< exactly<'{'> >();
-    bool semicolon = false;
-    Selector_Lookahead lookahead_result;
-    Block* block = new (ctx.mem) Block(pstate);
-    block_stack.push_back(block);
-    lex< zero_plus < alternatives < space, line_comment > > >();
-    // JMA - ensure that a block containing only block_comments is parsed
-    parse_block_comments(block);
-
-    while (!lex< exactly<'}'> >()) {
-      parse_block_comments(block);
-      if (semicolon) {
-        if (!lex< one_plus< exactly<';'> > >()) {
-          error("non-terminal statement or declaration must end with ';'", pstate);
-        }
-        semicolon = false;
-        parse_block_comments(block);
-        if (lex< sequence< exactly<'}'>, zero_plus< exactly<';'> > > >()) break;
-      }
-      else if (peek< kwd_import >(position)) {
-        if (stack.back() == mixin_def || stack.back() == function_def) {
-          lex< kwd_import >(); // to adjust the before_token number
-          error("@import directives are not allowed inside mixins and functions", pstate);
-        }
-        Import* imp = parse_import();
-        if (!imp->urls().empty()) (*block) << imp;
-        if (!imp->files().empty()) {
-          for (size_t i = 0, S = imp->files().size(); i < S; ++i) {
-            (*block) << new (ctx.mem) Import_Stub(pstate, imp->files()[i]);
-          }
-        }
-        semicolon = true;
-      }
-      else if (lex< variable >()) {
-        (*block) << parse_assignment();
-        semicolon = true;
-      }
-      else if (lex< line_comment >()) {
-        // throw line comments away
-      }
-      else if (peek< kwd_if_directive >()) {
-        (*block) << parse_if_directive();
-      }
-      else if (peek< kwd_for_directive >()) {
-        (*block) << parse_for_directive();
-      }
-      else if (peek< kwd_each_directive >()) {
-        (*block) << parse_each_directive();
-      }
-      else if (peek < kwd_while_directive >()) {
-        (*block) << parse_while_directive();
-      }
-      else if (lex < kwd_return_directive >()) {
-        (*block) << new (ctx.mem) Return(pstate, parse_list());
-        semicolon = true;
-      }
-      else if (peek< kwd_warn >()) {
-        (*block) << parse_warning();
-        semicolon = true;
-      }
-      else if (peek< kwd_err >()) {
-        (*block) << parse_error();
-        semicolon = true;
-      }
-      else if (peek< kwd_dbg >()) {
-        (*block) << parse_debug();
-        semicolon = true;
-      }
-      else if (stack.back() == function_def) {
-        error("only variable declarations and control directives are allowed inside functions", pstate);
-      }
-      else if (peek< kwd_mixin >() || peek< kwd_function >()) {
-        (*block) << parse_definition();
-      }
-      else if (peek< kwd_include >(position)) {
-        Mixin_Call* the_call = parse_mixin_call();
-        (*block) << the_call;
-        // don't need a semicolon after a content block
-        semicolon = (the_call->block()) ? false : true;
-      }
-      else if (lex< kwd_content >()) {
-        if (stack.back() != mixin_def) {
-          error("@content may only be used within a mixin", pstate);
-        }
-        (*block) << new (ctx.mem) Content(pstate);
-        semicolon = true;
-      }
-      /*
-      else if (peek< exactly<'+'> >()) {
-        (*block) << parse_mixin_call();
-        semicolon = true;
-      }
-      */
-      else if (lex< kwd_extend >()) {
-        Selector_Lookahead lookahead = lookahead_for_extension_target(position);
-        if (!lookahead.found) error("invalid selector for @extend", pstate);
-        Selector* target;
-        if (lookahead.has_interpolants) target = parse_selector_schema(lookahead.found);
-        else                            target = parse_selector_group();
-        (*block) << new (ctx.mem) Extension(pstate, target);
-        semicolon = true;
-      }
-      else if (peek< kwd_media >()) {
-        (*block) << parse_media_block();
-      }
-      else if (peek< kwd_supports >()) {
-        (*block) << parse_feature_block();
-      }
-      else if (peek< kwd_at_root >()) {
-        (*block) << parse_at_root_block();
-      }
-      // ignore the @charset directive for now
-      else if (lex< exactly< charset_kwd > >()) {
-        lex< quoted_string >();
-        lex< one_plus< exactly<';'> > >();
-      }
-      else if (peek< at_keyword >()) {
-        At_Rule* at_rule = parse_at_rule();
-        (*block) << at_rule;
-        if (!at_rule->block()) semicolon = true;
-      }
-      else if ((lookahead_result = lookahead_for_selector(position)).found) {
-        (*block) << parse_ruleset(lookahead_result);
-      }/* not used anymore - remove?
-      else if (peek< sequence< optional< exactly<'*'> >, alternatives< identifier_schema, identifier >, optional_spaces, exactly<':'>, optional_spaces, exactly<'{'> > >(position)) {
-        (*block) << parse_propset();
-      }*/
-      else if (!peek< exactly<';'> >()) {
-        bool indent = ! peek< sequence< optional< exactly<'*'> >, alternatives< identifier_schema, identifier >, optional_spaces, exactly<':'>, optional_spaces, exactly<'{'> > >(position);
-        /* not used anymore - remove?
-        if (peek< sequence< optional< exactly<'*'> >, identifier_schema, exactly<':'>, exactly<'{'> > >()) {
-          (*block) << parse_propset();
-        }
-        else if (peek< sequence< optional< exactly<'*'> >, identifier, exactly<':'>, exactly<'{'> > >()) {
-          (*block) << parse_propset();
-        }
-        else */ {
-          Declaration* decl = parse_declaration();
-          decl->tabs(indentation);
-          (*block) << decl;
-          if (peek< exactly<'{'> >()) {
-            // parse a propset that rides on the declaration's property
-            if (indent) indentation++;
-            Propset* ps = new (ctx.mem) Propset(pstate, decl->property(), parse_block());
-            if (indent) indentation--;
-            (*block) << ps;
-          }
-          else {
-            // finish and let the semicolon get munched
-            semicolon = true;
-          }
-        }
-      }
-      else lex< one_plus< exactly<';'> > >();
-      parse_block_comments(block);
-    }
-    block_stack.pop_back();
-    return block;
-  }
-
-  Declaration* Parser::parse_declaration() {
-    String* prop = 0;
-    if (peek< sequence< optional< exactly<'*'> >, identifier_schema > >()) {
-      prop = parse_identifier_schema();
-    }
-    else if (lex< sequence< optional< exactly<'*'> >, identifier > >()) {
-      prop = new (ctx.mem) String_Quoted(pstate, lexed);
-    }
-    else {
-      error("invalid property name", pstate);
-    }
-    const string property(lexed);
-    if (!lex_css< one_plus< exactly<':'> > >()) error("property \"" + property + "\" must be followed by a ':'", pstate);
-    if (peek_css< exactly<';'> >()) error("style declaration must contain a value", pstate);
-    if (peek_css< static_value >()) {
-      return new (ctx.mem) Declaration(prop->pstate(), prop, parse_static_value()/*, lex<important>()*/);
-    }
-    else {
-      Expression* value;
-      Selector_Lookahead lookahead = lookahead_for_value(position);
-      if (lookahead.found) {
-        if (lookahead.has_interpolants) {
-          value = parse_value_schema(lookahead.found);
-        } else {
-          value = parse_list();
-        }
-      }
-      else {
-        value = parse_list();
-        if (List* list = dynamic_cast<List*>(value)) {
-          if (list->length() == 0 && !peek< exactly <'{'> >()) {
-            css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
-          }
-        }
-      }
-
-      return new (ctx.mem) Declaration(prop->pstate(), prop, value/*, lex<important>()*/);
-    }
-  }
-
-  // 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()
-  {
-    ParserState opstate = pstate;
-    Expression* key = parse_list();
-    if (String_Quoted* str = dynamic_cast<String_Quoted*>(key)) {
-      if (!str->quote_mark() && !str->is_delayed()) {
-        if (ctx.names_to_colors.count(str->value())) {
-          Color* c = new (ctx.mem) Color(*ctx.names_to_colors[str->value()]);
-          c->pstate(str->pstate());
-          c->disp(str->value());
-          key = c;
-        }
-      }
-    }
-
-    // it's not a map so return the lexed value as a list value
-    if (!peek< exactly<':'> >())
-    { return key; }
-
-    lex< exactly<':'> >();
-
-    Expression* value = parse_space_list();
-
-    Map* map = new (ctx.mem) Map(opstate, 1);
-    (*map) << 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 (ctx.names_to_colors.count(str->value())) {
-            Color* c = new (ctx.mem) Color(*ctx.names_to_colors[str->value()]);
-            c->pstate(str->pstate());
-            c->disp(str->value());
-            key = c;
-          }
-        }
-      }
-
-      if (!(lex< exactly<':'> >()))
-      { error("invalid syntax", pstate); }
-
-      Expression* value = parse_space_list();
-
-      (*map) << make_pair(key, value);
-    }
-
-    // Check was moved to eval step
-    // if (map->has_duplicate_key()) {
-    //   To_String to_string(&ctx);
-    //   error("Duplicate key \"" + map->get_duplicate_key()->perform(&to_string) + "\" in map " + map->perform(&to_string) + ".", pstate);
-    // }
-
-    ParserState ps = map->pstate();
-    ps.offset = pstate - ps + pstate.offset;
-    map->pstate(ps);
-
-    return map;
-  }
-
-  Expression* Parser::parse_list()
-  {
-    return parse_comma_list();
-  }
-
-  Expression* Parser::parse_comma_list()
-  {
-    if (peek_css< alternatives <
-          // exactly<'!'>,
-          // exactly<':'>,
-          exactly<';'>,
-          exactly<'}'>,
-          exactly<'{'>,
-          exactly<')'>,
-          exactly<ellipsis>
-        > >(position))
-    { return new (ctx.mem) List(pstate, 0); }
-    Expression* list1 = parse_space_list();
-    // if it's a singleton, return it directly; don't wrap it
-    if (!peek_css< exactly<','> >(position)) return list1;
-
-    List* comma_list = new (ctx.mem) List(pstate, 2, List::COMMA);
-    (*comma_list) << list1;
-
-    while (lex_css< exactly<','> >())
-    {
-      if (peek_css< alternatives <
-            // exactly<'!'>,
-            exactly<';'>,
-            exactly<'}'>,
-            exactly<'{'>,
-            exactly<')'>,
-            exactly<':'>,
-            exactly<ellipsis>
-          > >(position)
-      ) { break; }
-      Expression* list = parse_space_list();
-      (*comma_list) << list;
-    }
-
-    return comma_list;
-  }
-
-  Expression* Parser::parse_space_list()
-  {
-    Expression* disj1 = parse_disjunction();
-    // if it's a singleton, return it directly; 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 = new (ctx.mem) List(pstate, 2, List::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
-    ) {
-      (*space_list) << parse_disjunction();
-    }
-
-    return space_list;
-  }
-
-  Expression* Parser::parse_disjunction()
-  {
-    Expression* conj1 = parse_conjunction();
-    // if it's a singleton, return it directly; don't wrap it
-    if (!peek_css< kwd_or >()) return conj1;
-
-    vector<Expression*> operands;
-    while (lex_css< kwd_or >())
-      operands.push_back(parse_conjunction());
-
-    return fold_operands(conj1, operands, Binary_Expression::OR);
-  }
-
-  Expression* Parser::parse_conjunction()
-  {
-    Expression* rel1 = parse_relation();
-    // if it's a singleton, return it directly; don't wrap it
-    if (!peek_css< kwd_and >()) return rel1;
-
-    vector<Expression*> operands;
-    while (lex_css< kwd_and >())
-      operands.push_back(parse_relation());
-
-    return fold_operands(rel1, operands, Binary_Expression::AND);
-  }
-
-  Expression* Parser::parse_relation()
-  {
-    Expression* expr1 = parse_expression();
-    // if it's a singleton, return it directly; don't wrap it
-    if (!(peek< alternatives <
-            kwd_eq,
-            kwd_neq,
-            kwd_gte,
-            kwd_gt,
-            kwd_lte,
-            kwd_lt
-          > >(position)))
-    { return expr1; }
-
-    Binary_Expression::Type op
-    = lex<kwd_eq>()  ? Binary_Expression::EQ
-    : lex<kwd_neq>() ? Binary_Expression::NEQ
-    : lex<kwd_gte>() ? Binary_Expression::GTE
-    : lex<kwd_lte>() ? Binary_Expression::LTE
-    : lex<kwd_gt>()  ? Binary_Expression::GT
-    : lex<kwd_lt>()  ? Binary_Expression::LT
-    :                 Binary_Expression::LT; // whatever
-
-    Expression* expr2 = parse_expression();
-
-    return new (ctx.mem) Binary_Expression(expr1->pstate(), op, expr1, expr2);
-  }
-
-  Expression* Parser::parse_expression()
-  {
-    Expression* term1 = parse_term();
-    // if it's a singleton, return it directly; don't wrap it
-    if (!(peek< exactly<'+'> >(position) ||
-          (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 term1; }
-
-    vector<Expression*> operands;
-    vector<Binary_Expression::Type> operators;
-    while (lex< exactly<'+'> >() || lex< sequence< negate< digit >, exactly<'-'> > >()) {
-      operators.push_back(lexed.to_string() == "+" ? Binary_Expression::ADD : Binary_Expression::SUB);
-      operands.push_back(parse_term());
-    }
-
-    return fold_operands(term1, operands, operators);
-  }
-
-  Expression* Parser::parse_term()
-  {
-    Expression* factor = parse_factor();
-    // Special case: Ruby sass never tries to modulo if the lhs contains an interpolant
-    if (peek_css< exactly<'%'> >(position) && 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 directly; don't wrap it
-    if (!peek< class_char< static_ops > >(position)) return factor;
-    return parse_operators(factor);
-  }
-
-  Expression* Parser::parse_operators(Expression* factor)
-  {
-    // parse more factors and operators
-    vector<Expression*> operands; // factors
-    vector<Binary_Expression::Type> operators; // ops
-    while (lex_css< class_char< static_ops > >()) {
-      switch(*lexed.begin) {
-        case '*': operators.push_back(Binary_Expression::MUL); break;
-        case '/': operators.push_back(Binary_Expression::DIV); break;
-        case '%': operators.push_back(Binary_Expression::MOD); break;
-        default: throw runtime_error("unknown static op parsed"); break;
-      }
-      operands.push_back(parse_factor());
-    }
-    // operands and operators to binary expression
-    return fold_operands(factor, operands, operators);
-  }
-
-  Expression* Parser::parse_factor()
-  {
-    if (lex_css< exactly<'('> >()) {
-      Expression* value = parse_map();
-      if (!lex_css< exactly<')'> >()) error("unclosed parenthesis", pstate);
-      value->is_delayed(false);
-      // make sure wrapped lists and division expressions are non-delayed within parentheses
-      if (value->concrete_type() == Expression::LIST) {
-        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() == Binary_Expression::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 (peek< functional_schema >()) {
-      return parse_function_call_schema();
-    }
-    else if (peek< sequence< identifier_schema, negate< exactly<'%'> > > >()) {
-      return parse_identifier_schema();
-    }
-    else if (peek< functional >()) {
-      return parse_function_call();
-    }
-    else if (lex< sequence< exactly<'+'>, optional_css_whitespace, negate< number > > >()) {
-      return new (ctx.mem) Unary_Expression(pstate, Unary_Expression::PLUS, parse_factor());
-    }
-    else if (lex< sequence< exactly<'-'>, optional_css_whitespace, negate< number> > >()) {
-      return new (ctx.mem) Unary_Expression(pstate, Unary_Expression::MINUS, parse_factor());
-    }
-    else if (lex< sequence< kwd_not, css_whitespace > >()) {
-      return 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 new (ctx.mem) Unary_Expression(pstate, Unary_Expression::MINUS, parse_value());
-    }
-    else {
-      return parse_value();
-    }
-  }
-
-  Expression* Parser::parse_value()
-  {
-    lex< css_comments >();
-    if (lex< ampersand >())
-    {
-      return new (ctx.mem) Parent_Selector(pstate, parse_selector_group()); }
-
-    if (lex< important >())
-    { return new (ctx.mem) String_Constant(pstate, "!important"); }
-
-    const char* stop;
-    if ((stop = peek< value_schema >()))
-    { return parse_value_schema(stop); }
-
-    if (lex< kwd_true >())
-    { return new (ctx.mem) Boolean(pstate, true); }
-
-    if (lex< kwd_false >())
-    { return new (ctx.mem) Boolean(pstate, false); }
-
-    if (lex< kwd_null >())
-    { return new (ctx.mem) Null(pstate); }
-
-    if (lex< identifier >()) {
-      String_Constant* str = new (ctx.mem) String_Quoted(pstate, lexed);
-      // Dont' delay this string if it is a name color. Fixes #652.
-      str->is_delayed(ctx.names_to_colors.count(unquote(lexed)) == 0);
-      return str;
-    }
-
-    if (lex< percentage >())
-    { return new (ctx.mem) Textual(pstate, Textual::PERCENTAGE, lexed); }
-
-    // match hex number first because 0x000 looks like a number followed by an indentifier
-    if (lex< alternatives< hex, hex0 > >())
-    { return new (ctx.mem) Textual(pstate, Textual::HEX, lexed); }
-
-    // also handle the 10em- foo special case
-    if (lex< sequence< dimension, optional< sequence< exactly<'-'>, negate< digit > > > > >())
-    { return new (ctx.mem) Textual(pstate, Textual::DIMENSION, lexed); }
-
-    if (lex< number >())
-    { return new (ctx.mem) Textual(pstate, Textual::NUMBER, lexed); }
-
-    if (peek< quoted_string >())
-    { return parse_string(); }
-
-    if (lex< variable >())
-    { return new (ctx.mem) Variable(pstate, Util::normalize_underscores(lexed)); }
-
-    // Special case handling for `%` proceeding an interpolant.
-    if (lex< sequence< exactly<'%'>, optional< percentage > > >())
-    { return new (ctx.mem) String_Quoted(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 = new (ctx.mem) String_Quoted(pstate, string(i, chunk.end));
-      if (!constant && str_quoted->quote_mark()) str_quoted->quote_mark('*');
-      str_quoted->is_delayed(true);
-      return str_quoted;
-    }
-
-    String_Schema* schema = new (ctx.mem) String_Schema(pstate);
-    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) << new (ctx.mem) String_Quoted(pstate, 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) << new (ctx.mem) String_Quoted(pstate, 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 = new (ctx.mem) String_Constant(pstate, str.time_wspace());
-    // str_node->is_delayed(true);
-    return str_node;
-  }
-
-  String* Parser::parse_string()
-  {
-    lex< quoted_string >();
-    Token token(lexed);
-    return parse_interpolated_chunk(token);
-  }
-
-  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) {
-      String_Constant* str_node = new (ctx.mem) String_Constant(pstate, normalize_wspace(string(str.begin, str.end)));
-      str_node->is_delayed(true);
-      str_node->quote_mark('*');
-      return str_node;
-    }
-
-    String_Schema* schema = 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) {
-          String_Constant* part = new (ctx.mem) String_Constant(pstate, normalize_wspace(string(i, p))); // accumulate the preceding segment if it's nonempty
-          part->is_delayed(true);
-          part->quote_mark('*'); // avoid unquote in interpolation
-          (*schema) << part;
-        }
-        if (peek < sequence < optional_spaces, exactly<rbrace> > >(p+2)) { position = p+2;
-          css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
-        }
-        const char* j = skip_over_scopes< exactly<hash_lbrace>, exactly<rbrace> >(p+2, str.end); // find the closing brace
-        if (j) {
-          // parse the interpolant and accumulate it
-          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) {
-          String_Constant* part = new (ctx.mem) String_Constant(pstate, normalize_wspace(string(i, str.end)));
-          part->is_delayed(true);
-          part->quote_mark('*'); // avoid unquote in interpolation
-          (*schema) << part;
-        }
-        break;
-      }
-    }
-    return schema;
-  }
-
-  String* Parser::parse_ie_keyword_arg()
-  {
-    String_Schema* kwd_arg = new (ctx.mem) String_Schema(pstate, 3);
-    if (lex< variable >()) {
-      *kwd_arg << new (ctx.mem) Variable(pstate, Util::normalize_underscores(lexed));
-    } else {
-      lex< alternatives< identifier_schema, identifier > >();
-      *kwd_arg << new (ctx.mem) String_Constant(pstate, lexed);
-    }
-    lex< exactly<'='> >();
-    *kwd_arg << new (ctx.mem) String_Constant(pstate, lexed);
-    if (peek< variable >()) *kwd_arg << parse_list();
-    else if (lex< number >()) *kwd_arg << new (ctx.mem) Textual(pstate, Textual::NUMBER, Util::normalize_decimals(lexed));
-    else if (peek < ie_keyword_arg_value >()) { *kwd_arg << parse_list(); }
-    return kwd_arg;
-  }
-
-  String_Schema* Parser::parse_value_schema(const char* stop)
-  {
-    String_Schema* schema = new (ctx.mem) String_Schema(pstate);
-    size_t num_items = 0;
-    if (peek<exactly<'}'>>()) {
-      css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
-    }
-    while (position < stop) {
-      if (lex< spaces >() && num_items) {
-        (*schema) << new (ctx.mem) String_Constant(pstate, " ");
-      }
-      else if (lex< interpolant >()) {
-        Token insides(Token(lexed.begin + 2, lexed.end - 1));
-        Expression* interp_node;
-        Parser p = Parser::from_token(insides, ctx, pstate);
-        if (!(interp_node = p.parse_static_expression())) {
-          interp_node = p.parse_list();
-          interp_node->is_interpolant(true);
-        }
-        (*schema) << interp_node;
-      }
-      else if (lex< exactly<'%'> >()) {
-        (*schema) << new (ctx.mem) String_Constant(pstate, lexed);
-      }
-      else if (lex< identifier >()) {
-        (*schema) << new (ctx.mem) String_Quoted(pstate, lexed);
-      }
-      else if (lex< percentage >()) {
-        (*schema) << new (ctx.mem) Textual(pstate, Textual::PERCENTAGE, lexed);
-      }
-      else if (lex< dimension >()) {
-        (*schema) << new (ctx.mem) Textual(pstate, Textual::DIMENSION, lexed);
-      }
-      else if (lex< number >()) {
-        Expression* factor = new (ctx.mem) Textual(pstate, Textual::NUMBER, lexed);
-        if (peek< class_char< static_ops > >()) {
-          (*schema) << parse_operators(factor);
-        } else {
-          (*schema) << factor;
-        }
-      }
-      else if (lex< hex >()) {
-        (*schema) << new (ctx.mem) Textual(pstate, Textual::HEX, unquote(lexed));
-      }
-      else if (lex < exactly < '-' > >()) {
-        (*schema) << new (ctx.mem) String_Constant(pstate, lexed);
-      }
-      else if (lex< quoted_string >()) {
-        (*schema) << new (ctx.mem) String_Quoted(pstate, lexed);
-      }
-      else if (lex< variable >()) {
-        (*schema) << new (ctx.mem) Variable(pstate, Util::normalize_underscores(lexed));
-      }
-      else if (peek< parenthese_scope >()) {
-        (*schema) << parse_factor();
-      }
-      else {
-        error("error parsing interpolated value", pstate);
-      }
-      ++num_items;
-    }
-    return schema;
-  }
-
-  /* not used anymore - remove?
-  String_Schema* Parser::parse_url_schema()
-  {
-    String_Schema* schema = new (ctx.mem) String_Schema(pstate);
-
-    while (position < end) {
-      if (position[0] == '/') {
-        lexed = Token(position, position+1, before_token);
-        (*schema) << new (ctx.mem) String_Quoted(pstate, lexed);
-        ++position;
-      }
-      else if (lex< interpolant >()) {
-        Token insides(Token(lexed.begin + 2, lexed.end - 1, before_token));
-        Expression* interp_node = Parser::from_token(insides, ctx, pstate).parse_list();
-        interp_node->is_interpolant(true);
-        (*schema) << interp_node;
-      }
-      else if (lex< sequence< identifier, exactly<':'> > >()) {
-        (*schema) << new (ctx.mem) String_Quoted(pstate, lexed);
-      }
-      else if (lex< filename >()) {
-        (*schema) << new (ctx.mem) String_Quoted(pstate, lexed);
-      }
-      else {
-        error("error parsing interpolated url", pstate);
-      }
-    }
-    return schema;
-  } */
-
-  // this parses interpolation outside other strings
-  // means the result must not be quoted again later
-  String* Parser::parse_identifier_schema()
-  {
-    // first lex away whatever we have found
-    lex< sequence< optional< exactly<'*'> >, identifier_schema > >();
-    Token id(lexed);
-    const char* i = id.begin;
-    // see if there any interpolants
-    const char* p = find_first_in_interval< exactly<hash_lbrace> >(id.begin, id.end);
-    if (!p) {
-      return new (ctx.mem) String_Quoted(pstate, string(id.begin, id.end));
-    }
-
-    String_Schema* schema = 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
-          (*schema) << new (ctx.mem) String_Constant(pstate, 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, 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) (*schema) << new (ctx.mem) String_Quoted(pstate, string(i, id.end));
-        break;
-      }
-    }
-    return schema;
-  }
-
-  Function_Call* Parser::parse_calc_function()
-  {
-    lex< identifier >();
-    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< exactly<')'> >();
-
-    Argument* arg = new (ctx.mem) Argument(arg_pos, parse_interpolated_chunk(Token(arg_beg, arg_end)));
-    Arguments* args = new (ctx.mem) Arguments(arg_pos);
-    *args << arg;
-    return new (ctx.mem) Function_Call(call_pos, name, args);
-  }
-
-  Function_Call* Parser::parse_function_call()
-  {
-    lex< identifier >();
-    string name(lexed);
-
-    ParserState call_pos = pstate;
-    Arguments* args = parse_arguments(name == "url");
-    return 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 = new (ctx.mem) Function_Call_Schema(source_position_of_call, name, parse_arguments());
-    return the_call;
-  }
-
-  If* Parser::parse_if_directive(bool else_if)
-  {
-    lex< kwd_if_directive >() || (else_if && lex< exactly<if_after_else_kwd> >());
-    ParserState if_source_position = pstate;
-    Expression* predicate = parse_list();
-    predicate->is_delayed(false);
-    if (!peek< exactly<'{'> >()) error("expected '{' after the predicate for @if", pstate);
-    Block* consequent = parse_block();
-    Block* alternative = 0;
-
-    if (lex< elseif_directive >()) {
-      alternative = new (ctx.mem) Block(pstate);
-      (*alternative) << parse_if_directive(true);
-    }
-    else if (lex< kwd_else_directive >()) {
-      if (!peek< exactly<'{'> >()) {
-        error("expected '{' after @else", pstate);
-      }
-      else {
-        alternative = parse_block();
-      }
-    }
-    return new (ctx.mem) If(if_source_position, predicate, consequent, alternative);
-  }
-
-  For* Parser::parse_for_directive()
-  {
-    lex< kwd_for_directive >();
-    ParserState for_source_position = pstate;
-    if (!lex< variable >()) error("@for directive requires an iteration variable", pstate);
-    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);
-    if (!peek< exactly<'{'> >()) error("expected '{' after the upper bound in @for directive", pstate);
-    Block* body = parse_block();
-    return new (ctx.mem) For(for_source_position, var, lower_bound, upper_bound, body, inclusive);
-  }
-
-  Each* Parser::parse_each_directive()
-  {
-    lex < kwd_each_directive >();
-    ParserState each_source_position = pstate;
-    if (!lex< variable >()) error("@each directive requires an iteration variable", pstate);
-    vector<string> vars;
-    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);
-      }
-    }
-    if (!peek< exactly<'{'> >()) error("expected '{' after the upper bound in @each directive", pstate);
-    Block* body = parse_block();
-    return new (ctx.mem) Each(each_source_position, vars, list, body);
-  }
-
-  While* Parser::parse_while_directive()
-  {
-    lex< kwd_while_directive >();
-    ParserState while_source_position = pstate;
-    Expression* predicate = parse_list();
-    predicate->is_delayed(false);
-    Block* body = parse_block();
-    return new (ctx.mem) While(while_source_position, predicate, body);
-  }
-
-  Media_Block* Parser::parse_media_block()
-  {
-    lex< kwd_media >();
-    ParserState media_source_position = pstate;
-
-    List* media_queries = parse_media_queries();
-
-    if (!peek< exactly<'{'> >()) {
-      error("expected '{' in media query", pstate);
-    }
-    Media_Block* media_block = new (ctx.mem) Media_Block(media_source_position, media_queries, 0);
-    Media_Block* prev_media_block = last_media_block;
-    last_media_block = media_block;
-    media_block->block(parse_block());
-    last_media_block = prev_media_block;
-
-    return media_block;
-  }
-
-  List* Parser::parse_media_queries()
-  {
-    List* media_queries = new (ctx.mem) List(pstate, 0, List::COMMA);
-    if (!peek< exactly<'{'> >()) (*media_queries) << parse_media_query();
-    while (lex< exactly<','> >()) (*media_queries) << parse_media_query();
-    return media_queries;
-  }
-
-  // Expression* Parser::parse_media_query()
-  Media_Query* Parser::parse_media_query()
-  {
-    Media_Query* media_query = new (ctx.mem) Media_Query(pstate);
-
-    if (lex< exactly< not_kwd > >()) media_query->is_negated(true);
-    else if (lex< exactly< only_kwd > >()) media_query->is_restricted(true);
-
-    if (peek< identifier_schema >()) media_query->media_type(parse_identifier_schema());
-    else if (lex< identifier >())    media_query->media_type(parse_interpolated_chunk(lexed));
-    else                             (*media_query) << parse_media_expression();
-
-    while (lex< exactly< and_kwd > >()) (*media_query) << parse_media_expression();
-    if (peek< identifier_schema >()) {
-      String_Schema* schema = new (ctx.mem) String_Schema(pstate);
-      *schema << media_query->media_type();
-      *schema << new (ctx.mem) String_Constant(pstate, " ");
-      *schema << parse_identifier_schema();
-      media_query->media_type(schema);
-    }
-    while (lex< exactly< and_kwd > >()) (*media_query) << parse_media_expression();
-    return media_query;
-  }
-
-  Media_Query_Expression* Parser::parse_media_expression()
-  {
-    if (peek< identifier_schema >()) {
-      String* ss = parse_identifier_schema();
-      return new (ctx.mem) Media_Query_Expression(pstate, ss, 0, true);
-    }
-    if (!lex< exactly<'('> >()) {
-      error("media query expression must begin with '('", pstate);
-    }
-    Expression* feature = 0;
-    if (peek< 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 new (ctx.mem) Media_Query_Expression(feature->pstate(), feature, expression);
-  }
-
-  Feature_Block* Parser::parse_feature_block()
-  {
-    lex< kwd_supports >();
-    ParserState supports_source_position = pstate;
-
-    Feature_Query* feature_queries = parse_feature_queries();
-
-    if (!peek< exactly<'{'> >()) {
-      error("expected '{' in feature query", pstate);
-    }
-    Block* block = parse_block();
-
-    return new (ctx.mem) Feature_Block(supports_source_position, feature_queries, block);
-  }
-
-  Feature_Query* Parser::parse_feature_queries()
-  {
-    Feature_Query* fq = new (ctx.mem) Feature_Query(pstate);
-    Feature_Query_Condition* cond = new (ctx.mem) Feature_Query_Condition(pstate);
-    cond->is_root(true);
-    while (!peek< exactly<')'> >(position) && !peek< exactly<'{'> >(position))
-      (*cond) << parse_feature_query();
-    (*fq) << cond;
-
-    if (fq->empty()) error("expected @supports condition (e.g. (display: flexbox))", pstate);
-
-    return fq;
-  }
-
-  Feature_Query_Condition* Parser::parse_feature_query()
-  {
-    if (peek< kwd_not >(position)) return parse_supports_negation();
-    else if (peek< kwd_and >(position)) return parse_supports_conjunction();
-    else if (peek< kwd_or >(position)) return parse_supports_disjunction();
-    else if (peek< exactly<'('> >(position)) return parse_feature_query_in_parens();
-    else return parse_supports_declaration();
-  }
-
-  Feature_Query_Condition* Parser::parse_feature_query_in_parens()
-  {
-    Feature_Query_Condition* cond = new (ctx.mem) Feature_Query_Condition(pstate);
-
-    if (!lex< exactly<'('> >()) error("@supports declaration expected '('", pstate);
-    while (!peek< exactly<')'> >(position) && !peek< exactly<'{'> >(position))
-      (*cond) << parse_feature_query();
-    if (!lex< exactly<')'> >()) error("unclosed parenthesis in @supports declaration", pstate);
-
-    return (cond->length() == 1) ? (*cond)[0] : cond;
-  }
-
-  Feature_Query_Condition* Parser::parse_supports_negation()
-  {
-    lex< kwd_not >();
-
-    Feature_Query_Condition* cond = parse_feature_query();
-    cond->operand(Feature_Query_Condition::NOT);
-
-    return cond;
-  }
-
-  Feature_Query_Condition* Parser::parse_supports_conjunction()
-  {
-    lex< kwd_and >();
-
-    Feature_Query_Condition* cond = parse_feature_query();
-    cond->operand(Feature_Query_Condition::AND);
-
-    return cond;
-  }
-
-  Feature_Query_Condition* Parser::parse_supports_disjunction()
-  {
-    lex< kwd_or >();
-
-    Feature_Query_Condition* cond = parse_feature_query();
-    cond->operand(Feature_Query_Condition::OR);
-
-    return cond;
-  }
-
-  Feature_Query_Condition* Parser::parse_supports_declaration()
-  {
-    Declaration* declaration = parse_declaration();
-    Feature_Query_Condition* cond = new (ctx.mem) Feature_Query_Condition(declaration->pstate(),
-                                                                          1,
-                                                                          declaration->property(),
-                                                                          declaration->value());
-    return cond;
-  }
-
-  At_Root_Block* Parser::parse_at_root_block()
-  {
-    lex<kwd_at_root>();
-    ParserState at_source_position = pstate;
-    Block* body = 0;
-    At_Root_Expression* expr = 0;
-    Selector_Lookahead lookahead_result;
-    in_at_root = true;
-    if (peek< exactly<'('> >()) {
-      expr = parse_at_root_expression();
-      body = parse_block();
-    }
-    else if (peek< exactly<'{'> >()) {
-      body = parse_block();
-    }
-    else if ((lookahead_result = lookahead_for_selector(position)).found) {
-      Ruleset* r = parse_ruleset(lookahead_result);
-      body = new (ctx.mem) Block(r->pstate(), 1);
-      *body << r;
-    }
-    in_at_root = false;
-    At_Root_Block* at_root = 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()
-  {
-    lex< exactly<'('> >();
-    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 = 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 = 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()
-  {
-    lex<at_keyword>();
-    string kwd(lexed);
-    ParserState at_source_position = pstate;
-    Selector* sel = 0;
-    Expression* val = 0;
-    Selector_Lookahead lookahead = lookahead_for_extension_target(position);
-    if (lookahead.found) {
-      if (lookahead.has_interpolants) {
-        sel = parse_selector_schema(lookahead.found);
-      }
-      else {
-        sel = parse_selector_group();
-      }
-    }
-    else if (!(peek<exactly<'{'> >() || peek<exactly<'}'> >() || peek<exactly<';'> >())) {
-      val = parse_list();
-    }
-    Block* body = 0;
-    if (peek< exactly<'{'> >()) body = parse_block();
-    At_Rule* rule = new (ctx.mem) At_Rule(at_source_position, kwd, sel, body);
-    if (!sel) rule->value(val);
-    return rule;
-  }
-
-  Warning* Parser::parse_warning()
-  {
-    lex< kwd_warn >();
-    return new (ctx.mem) Warning(pstate, parse_list());
-  }
-
-  Error* Parser::parse_error()
-  {
-    lex< kwd_err >();
-    return new (ctx.mem) Error(pstate, parse_list());
-  }
-
-  Debug* Parser::parse_debug()
-  {
-    lex< kwd_dbg >();
-    return new (ctx.mem) Debug(pstate, parse_list());
-  }
-
-  Selector_Lookahead Parser::lookahead_for_selector(const char* start)
-  {
-    const char* p = start ? start : position;
-    const char* q;
-    bool saw_stuff = false;
-    bool saw_interpolant = false;
-
-    while ((q = peek< identifier >(p))                             ||
-           (q = peek< hyphens_and_identifier >(p))                 ||
-           (q = peek< hyphens_and_name >(p))                       ||
-           (q = peek< type_selector >(p))                          ||
-           (q = peek< id_name >(p))                                ||
-           (q = peek< class_name >(p))                             ||
-           (q = peek< sequence< pseudo_prefix, identifier > >(p))  ||
-           (q = peek< percentage >(p))                             ||
-           (q = peek< variable >(p))                            ||
-           (q = peek< dimension >(p))                              ||
-           (q = peek< quoted_string >(p))                          ||
-           (q = peek< exactly<'*'> >(p))                           ||
-           (q = peek< exactly<sel_deep_kwd> >(p))                           ||
-           (q = peek< exactly<'('> >(p))                           ||
-           (q = peek< exactly<')'> >(p))                           ||
-           (q = peek< exactly<'['> >(p))                           ||
-           (q = peek< exactly<']'> >(p))                           ||
-           (q = peek< exactly<'+'> >(p))                           ||
-           (q = peek< exactly<'~'> >(p))                           ||
-           (q = peek< exactly<'>'> >(p))                           ||
-           (q = peek< exactly<','> >(p))                           ||
-           (saw_stuff && (q = peek< exactly<'-'> >(p)))            ||
-           (q = peek< binomial >(p))                               ||
-           (q = peek< block_comment >(p))                          ||
-           (q = peek< sequence< optional<sign>,
-                                zero_plus<digit>,
-                                exactly<'n'> > >(p))               ||
-           (q = peek< sequence< optional<sign>,
-                                one_plus<digit> > >(p))                     ||
-           (q = peek< number >(p))                                 ||
-           (q = peek< sequence< exactly<'&'>,
-                                identifier_alnums > >(p))        ||
-           (q = peek< exactly<'&'> >(p))                           ||
-           (q = peek< exactly<'%'> >(p))                           ||
-           (q = peek< alternatives<exact_match,
-                                   class_match,
-                                   dash_match,
-                                   prefix_match,
-                                   suffix_match,
-                                   substring_match> >(p))          ||
-           (q = peek< sequence< exactly<'.'>, interpolant > >(p))  ||
-           (q = peek< sequence< exactly<'#'>, interpolant > >(p))  ||
-           (q = peek< sequence< one_plus< exactly<'-'> >, interpolant > >(p))  ||
-           (q = peek< sequence< pseudo_prefix, interpolant > >(p)) ||
-           (q = peek< interpolant >(p))) {
-      saw_stuff = true;
-      p = q;
-      if (*(p - 1) == '}') saw_interpolant = true;
-    }
-
-    Selector_Lookahead result;
-    result.found            = saw_stuff && peek< exactly<'{'> >(p) ? p : 0;
-    result.has_interpolants = saw_interpolant;
-
-    return result;
-  }
-
-  Selector_Lookahead Parser::lookahead_for_extension_target(const char* start)
-  {
-    const char* p = start ? start : position;
-    const char* q;
-    bool saw_interpolant = false;
-    bool saw_stuff = false;
-
-    while ((q = peek< identifier >(p))                             ||
-           (q = peek< type_selector >(p))                          ||
-           (q = peek< id_name >(p))                                ||
-           (q = peek< class_name >(p))                             ||
-           (q = peek< sequence< pseudo_prefix, identifier > >(p))  ||
-           (q = peek< percentage >(p))                             ||
-           (q = peek< dimension >(p))                              ||
-           (q = peek< quoted_string >(p))                          ||
-           (q = peek< exactly<'*'> >(p))                           ||
-           (q = peek< exactly<'('> >(p))                           ||
-           (q = peek< exactly<')'> >(p))                           ||
-           (q = peek< exactly<'['> >(p))                           ||
-           (q = peek< exactly<']'> >(p))                           ||
-           (q = peek< exactly<'+'> >(p))                           ||
-           (q = peek< exactly<'~'> >(p))                           ||
-           (q = peek< exactly<'>'> >(p))                           ||
-           (q = peek< exactly<','> >(p))                           ||
-           (saw_stuff && (q = peek< exactly<'-'> >(p)))            ||
-           (q = peek< binomial >(p))                               ||
-           (q = peek< block_comment >(p))                          ||
-           (q = peek< sequence< optional<sign>,
-                                zero_plus<digit>,
-                                exactly<'n'> > >(p))               ||
-           (q = peek< sequence< optional<sign>,
-                                one_plus<digit> > >(p))                     ||
-           (q = peek< number >(p))                                 ||
-           (q = peek< sequence< exactly<'&'>,
-                                identifier_alnums > >(p))        ||
-           (q = peek< exactly<'&'> >(p))                           ||
-           (q = peek< exactly<'%'> >(p))                           ||
-           (q = peek< alternatives<exact_match,
-                                   class_match,
-                                   dash_match,
-                                   prefix_match,
-                                   suffix_match,
-                                   substring_match> >(p))          ||
-           (q = peek< sequence< exactly<'.'>, interpolant > >(p))  ||
-           (q = peek< sequence< exactly<'#'>, interpolant > >(p))  ||
-           (q = peek< sequence< one_plus< exactly<'-'> >, interpolant > >(p))  ||
-           (q = peek< sequence< pseudo_prefix, interpolant > >(p)) ||
-           (q = peek< interpolant >(p))                            ||
-           (q = peek< optional >(p))) {
-      p = q;
-      if (*(p - 1) == '}') saw_interpolant = true;
-      saw_stuff = true;
-    }
-
-    Selector_Lookahead result;
-    result.found            = peek< alternatives< exactly<';'>, exactly<'}'>, exactly<'{'> > >(p) && saw_stuff ? p : 0;
-    result.has_interpolants = saw_interpolant;
-
-    return result;
-  }
-
-
-  Selector_Lookahead Parser::lookahead_for_value(const char* start)
-  {
-    const char* p = start ? start : position;
-    const char* q;
-    bool saw_interpolant = false;
-    bool saw_stuff = false;
-
-    while ((q = peek< identifier >(p))                             ||
-           (q = peek< percentage >(p))                             ||
-           (q = peek< dimension >(p))                              ||
-           (q = peek< quoted_string >(p))                          ||
-           (q = peek< variable >(p))                               ||
-           (q = peek< exactly<'*'> >(p))                           ||
-           (q = peek< exactly<'+'> >(p))                           ||
-           (q = peek< exactly<'~'> >(p))                           ||
-           (q = peek< exactly<'>'> >(p))                           ||
-           (q = peek< exactly<','> >(p))                           ||
-           (q = peek< sequence<parenthese_scope, interpolant>>(p)) ||
-           (saw_stuff && (q = peek< exactly<'-'> >(p)))            ||
-           (q = peek< binomial >(p))                               ||
-           (q = peek< block_comment >(p))                          ||
-           (q = peek< sequence< optional<sign>,
-                                zero_plus<digit>,
-                                exactly<'n'> > >(p))               ||
-           (q = peek< sequence< optional<sign>,
-                                one_plus<digit> > >(p))            ||
-           (q = peek< number >(p))                                 ||
-           (q = peek< sequence< exactly<'&'>,
-                                identifier_alnums > >(p))          ||
-           (q = peek< exactly<'&'> >(p))                           ||
-           (q = peek< exactly<'%'> >(p))                           ||
-           (q = peek< sequence< exactly<'.'>, interpolant > >(p))  ||
-           (q = peek< sequence< exactly<'#'>, interpolant > >(p))  ||
-           (q = peek< sequence< one_plus< exactly<'-'> >, interpolant > >(p))  ||
-           (q = peek< sequence< pseudo_prefix, interpolant > >(p)) ||
-           (q = peek< interpolant >(p))                            ||
-           (q = peek< optional >(p))) {
-      p = q;
-      if (*(p - 1) == '}') saw_interpolant = true;
-      saw_stuff = true;
-    }
-
-    Selector_Lookahead result;
-    result.found            = peek< alternatives< exactly<';'>, exactly<'}'>, exactly<'{'> > >(p) && saw_stuff ? p : 0;
-    result.has_interpolants = saw_interpolant;
-
-    return result;
-  }
-
-  void Parser::read_bom()
-  {
-    size_t skip = 0;
-    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, vector<Expression*>& operands, Binary_Expression::Type op)
-  {
-    for (size_t i = 0, S = operands.size(); i < S; ++i) {
-      base = new (ctx.mem) Binary_Expression(pstate, op, base, operands[i]);
-      Binary_Expression* b = static_cast<Binary_Expression*>(base);
-      if (op == Binary_Expression::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, vector<Expression*>& operands, vector<Binary_Expression::Type>& ops)
-  {
-    for (size_t i = 0, S = operands.size(); i < S; ++i) {
-      base = new (ctx.mem) Binary_Expression(base->pstate(), ops[i], base, operands[i]);
-      Binary_Expression* b = static_cast<Binary_Expression*>(base);
-      if (ops[i] == Binary_Expression::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(string msg, Position pos)
-  {
-    throw Sass_Error(Sass_Error::syntax, 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 string& msg, const string& prefix, const string& middle)
-  {
-    int max_len = 14;
-    const char* pos = peek < optional_spaces >();
-    bool ellipsis_left = false;
-    const char* pos_left(pos);
-    while (*pos_left && pos_left > source) {
-      if (pos - pos_left > max_len) {
-        ellipsis_left = true;
-        break;
-      }
-      const char* prev = pos_left - 1;
-      if (*prev == '\r') break;
-      if (*prev == '\n') break;
-      if (*prev == 10) break;
-      pos_left = prev;
-    }
-    bool ellipsis_right = false;
-    const char* pos_right(pos);
-    while (*pos_right && pos_right <= end) {
-      if (pos_right - pos > max_len) {
-        ellipsis_right = true;
-        break;
-      }
-      if (*pos_right == '\r') break;
-      if (*pos_right == '\n') break;
-      if (*pos_left == 10) break;
-      ++ pos_right;
-    }
-    string left(pos_left, pos);
-    string right(pos, pos_right);
-    if (ellipsis_left) left = ellipsis + left;
-    if (ellipsis_right) right = right + ellipsis;
-    // now pass new message to the more generic error function
-    error(msg + prefix + quote(left) + middle + quote(right), pstate);
-  }
-
-}
diff --git a/libsass/parser.hpp b/libsass/parser.hpp
deleted file mode 100644
--- a/libsass/parser.hpp
+++ /dev/null
@@ -1,291 +0,0 @@
-#ifndef SASS_PARSER_H
-#define SASS_PARSER_H
-
-#include <map>
-#include <vector>
-#include <iostream>
-
-#include "ast.hpp"
-#include "position.hpp"
-#include "context.hpp"
-#include "position.hpp"
-#include "prelexer.hpp"
-
-struct Selector_Lookahead {
-  const char* found;
-  bool has_interpolants;
-};
-
-namespace Sass {
-  using std::string;
-  using std::vector;
-  using std::map;
-  using namespace Prelexer;
-
-  class Parser : public ParserState {
-  private:
-    void add_single_file (Import* imp, string import_path);
-    void import_single_file (Import* imp, string import_path);
-  public:
-    class AST_Node;
-
-    enum Syntactic_Context { nothing, mixin_def, function_def };
-    bool do_import(const string& import_path, Import* imp, vector<Sass_Importer_Entry> importers, bool only_one = true);
-
-    Context& ctx;
-    vector<Block*> block_stack;
-    vector<Syntactic_Context> stack;
-    Media_Block* last_media_block;
-    const char* source;
-    const char* position;
-    const char* end;
-    Position before_token;
-    Position after_token;
-    ParserState pstate;
-    int indentation;
-
-
-    Token lexed;
-    bool in_at_root;
-
-    Parser(Context& ctx, const ParserState& pstate)
-    : ParserState(pstate), ctx(ctx), block_stack(0), stack(0), last_media_block(0),
-      source(0), position(0), end(0), before_token(pstate), after_token(pstate), pstate(pstate), indentation(0)
-    { in_at_root = false; stack.push_back(nothing); }
-
-    // static Parser from_string(const string& src, Context& ctx, ParserState pstate = ParserState("[STRING]"));
-    static Parser from_c_str(const char* src, Context& ctx, ParserState pstate = ParserState("[CSTRING]"));
-    static Parser from_c_str(const char* beg, const char* end, Context& ctx, ParserState pstate = ParserState("[CSTRING]"));
-    static Parser from_token(Token t, Context& ctx, ParserState pstate = ParserState("[TOKEN]"));
-    // special static parsers to convert strings into certain selectors
-    static Selector_List* parse_selector(const char* src, Context& ctx, ParserState pstate = ParserState("[SELECTOR]"));
-
-#ifdef __clang__
-
-    // lex and peak uses the template parameter to branch on the action, which
-    // triggers clangs tautological comparison on the single-comparison
-    // branches. This is not a bug, just a merging of behaviour into
-    // one function
-
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wtautological-compare"
-
-#endif
-
-
-    bool peek_newline(const char* start = 0);
-
-    // skip over spaces, tabs and line comments
-    template <prelexer mx>
-    const char* sneak(const char* start = 0)
-    {
-
-      // maybe use optional start position from arguments?
-      const char* it_position = start ? start : position;
-
-      // skip white-space?
-      if (mx == spaces ||
-          mx == no_spaces ||
-          mx == css_comments ||
-          mx == css_whitespace ||
-          mx == optional_spaces ||
-          mx == optional_css_comments ||
-          mx == optional_css_whitespace
-      ) {
-        return it_position;
-      }
-
-      // skip over spaces, tabs and sass line comments
-      const char* pos = optional_css_whitespace(it_position);
-      // always return a valid position
-      return pos ? pos : it_position;
-
-    }
-
-    // peek will only skip over space, tabs and line comment
-    // return the position where the lexer match will occur
-    template <prelexer mx>
-    const char* peek(const char* start = 0)
-    {
-
-      // sneak up to the actual token we want to lex
-      // this should skip over white-space if desired
-      const char* it_before_token = sneak < mx >(start);
-
-      // match the given prelexer
-      return mx(it_before_token);
-
-    }
-
-    // white-space handling is built into the lexer
-    // this way you do not need to parse it yourself
-    // some matchers don't accept certain white-space
-    // we do not support start arg, since we manipulate
-    // sourcemap offset and we modify the position pointer!
-    // lex will only skip over space, tabs and line comment
-    template <prelexer mx>
-    const char* lex(bool lazy = true)
-    {
-
-      // position considered before lexed token
-      // we can skip whitespace or comments for
-      // lazy developers (but we need control)
-      const char* it_before_token = position;
-
-      // sneak up to the actual token we want to lex
-      // this should skip over white-space if desired
-      if (lazy) it_before_token = sneak < mx >(position);
-
-      // now call matcher to get position after token
-      const char* it_after_token = mx(it_before_token);
-
-      // assertion that we got a valid match
-      if (it_after_token == 0) return 0;
-      // assertion that we actually lexed something
-      if (it_after_token == it_before_token) return 0;
-
-      // create new lexed token object (holds all parse result information)
-      lexed = Token(position, it_before_token, it_after_token);
-
-      // advance position (add whitespace before current token)
-      before_token = after_token.add(position, it_before_token);
-
-      // update after_token position for current token
-      after_token.add(it_before_token, it_after_token);
-
-      // ToDo: could probably do this incremetal on original object (API wants offset?)
-      pstate = ParserState(path, source, lexed, before_token, after_token - before_token);
-
-      // advance internal char iterator
-      return position = it_after_token;
-
-    }
-
-    // lex_css skips over space, tabs, line and block comment
-    // all block comments will be consumed and thrown away
-    // source-map position will point to token after the comment
-    template <prelexer mx>
-    const char* lex_css()
-    {
-      // copy old token
-      Token prev = lexed;
-      // throw away comments
-      // update srcmap position
-      lex < css_comments >();
-      // now lex a new token
-      const char* pos = lex< mx >();
-      // maybe restore prev token
-      if (pos == 0) lexed = prev;
-      // return match
-      return pos;
-    }
-
-    // all block comments will be skipped and thrown away
-    template <prelexer mx>
-    const char* peek_css(const char* start = 0)
-    {
-      // now peek a token (skip comments first)
-      return peek< mx >(peek < css_comments >(start));
-    }
-
-#ifdef __clang__
-
-#pragma clang diagnostic pop
-
-#endif
-
-    void error(string msg, Position pos);
-    // generate message with given and expected sample
-    // text before and in the middle are configurable
-    void css_error(const string& msg,
-                   const string& prefix = " after ",
-                   const string& middle = ", was: ");
-    void read_bom();
-
-    Block* parse();
-    Import* parse_import();
-    Definition* parse_definition();
-    Parameters* parse_parameters();
-    Parameter* parse_parameter();
-    Mixin_Call* parse_mixin_call();
-    Arguments* parse_arguments(bool has_url = false);
-    Argument* parse_argument(bool has_url = false);
-    Assignment* parse_assignment();
-    // Propset* parse_propset();
-    Ruleset* parse_ruleset(Selector_Lookahead lookahead);
-    Selector_Schema* parse_selector_schema(const char* end_of_selector);
-    Selector_List* parse_selector_group();
-    Complex_Selector* parse_selector_combination();
-    Compound_Selector* parse_simple_selector_sequence();
-    Simple_Selector* parse_simple_selector();
-    Wrapped_Selector* parse_negated_selector();
-    Simple_Selector* parse_pseudo_selector();
-    Attribute_Selector* parse_attribute_selector();
-    Block* parse_block();
-    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_term();
-    Expression* parse_factor();
-    Expression* parse_value();
-    Function_Call* parse_calc_function();
-    Function_Call* parse_function_call();
-    Function_Call_Schema* parse_function_call_schema();
-    String* parse_interpolated_chunk(Token, bool constant = false);
-    String* parse_string();
-    String_Constant* parse_static_expression();
-    String_Constant* parse_static_value();
-    String* parse_ie_property();
-    String* parse_ie_keyword_arg();
-    String_Schema* parse_value_schema(const char* stop);
-    Expression* parse_operators(Expression* factor);
-    String* parse_identifier_schema();
-    // String_Schema* parse_url_schema();
-    If* parse_if_directive(bool else_if = false);
-    For* parse_for_directive();
-    Each* parse_each_directive();
-    While* parse_while_directive();
-    Media_Block* parse_media_block();
-    List* parse_media_queries();
-    Media_Query* parse_media_query();
-    Media_Query_Expression* parse_media_expression();
-    Feature_Block* parse_feature_block();
-    Feature_Query* parse_feature_queries();
-    Feature_Query_Condition* parse_feature_query();
-    Feature_Query_Condition* parse_feature_query_in_parens();
-    Feature_Query_Condition* parse_supports_negation();
-    Feature_Query_Condition* parse_supports_conjunction();
-    Feature_Query_Condition* parse_supports_disjunction();
-    Feature_Query_Condition* parse_supports_declaration();
-    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();
-
-    void parse_block_comments(Block* block);
-
-    Selector_Lookahead lookahead_for_value(const char* start = 0);
-    Selector_Lookahead lookahead_for_selector(const char* start = 0);
-    Selector_Lookahead lookahead_for_extension_target(const char* start = 0);
-
-    Expression* fold_operands(Expression* base, vector<Expression*>& operands, Binary_Expression::Type op);
-    Expression* fold_operands(Expression* base, vector<Expression*>& operands, vector<Binary_Expression::Type>& ops);
-
-    void throw_syntax_error(string message, size_t ln = 0);
-    void throw_read_error(string message, size_t ln = 0);
-  };
-
-  size_t check_bom_chars(const char* src, const char *end, const unsigned char* bom, size_t len);
-}
-
-#endif
diff --git a/libsass/paths.hpp b/libsass/paths.hpp
deleted file mode 100644
--- a/libsass/paths.hpp
+++ /dev/null
@@ -1,74 +0,0 @@
-#ifndef SASS_PATHS_H
-#define SASS_PATHS_H
-
-#include <string>
-#include <vector>
-#include <sstream>
-#include <iostream>
-
-using namespace std;
-
-template<typename T>
-string vector_to_string(vector<T> v)
-{
-  stringstream buffer;
-  buffer << "[";
-
-  if (!v.empty())
-  {  buffer << v[0]; }
-  else
-  { buffer << "]"; }
-
-  if (v.size() == 1)
-  { buffer << "]"; }
-  else
-  {
-    for (size_t i = 1, S = v.size(); i < S; ++i) buffer << ", " << v[i];
-    buffer << "]";
-  }
-
-  return buffer.str();
-}
-
-namespace Sass {
-
-  using namespace std;
-
-  template<typename T>
-  vector<vector<T> > paths(vector<vector<T> > strata, size_t from_end = 0)
-  {
-    if (strata.empty()) {
-      return vector<vector<T> >();
-    }
-
-    size_t end = strata.size() - from_end;
-    if (end <= 1) {
-      vector<vector<T> > starting_points;
-      starting_points.reserve(strata[0].size());
-      for (size_t i = 0, S = strata[0].size(); i < S; ++i) {
-        vector<T> starting_point;
-        starting_point.push_back(strata[0][i]);
-        starting_points.push_back(starting_point);
-      }
-      return starting_points;
-    }
-
-    vector<vector<T> > up_to_here = paths(strata, from_end + 1);
-    vector<T>          here       = strata[end-1];
-
-    vector<vector<T> > branches;
-    branches.reserve(up_to_here.size() * here.size());
-    for (size_t i = 0, S1 = up_to_here.size(); i < S1; ++i) {
-      for (size_t j = 0, S2 = here.size(); j < S2; ++j) {
-        vector<T> branch = up_to_here[i];
-        branch.push_back(here[j]);
-        branches.push_back(branch);
-      }
-    }
-
-    return branches;
-  }
-
-}
-
-#endif
diff --git a/libsass/plugins.cpp b/libsass/plugins.cpp
deleted file mode 100644
--- a/libsass/plugins.cpp
+++ /dev/null
@@ -1,168 +0,0 @@
-#ifdef _WIN32
-#include <windows.h>
-#else
-#include <sys/types.h>
-#include <dirent.h>
-#include <errno.h>
-#include <dlfcn.h>
-#endif
-
-#include <iostream>
-#include "output.hpp"
-#include "plugins.hpp"
-
-#define npos string::npos
-
-namespace Sass {
-
-  Plugins::Plugins(void) { }
-  Plugins::~Plugins(void) { }
-
-  // check if plugin is compatible with this version
-  // plugins may be linked static against libsass
-  // we try to be compatible between major versions
-  inline bool compatibility(const char* their_version)
-  {
-// const char* their_version = "3.1.2";
-    // first check if anyone has an unknown version
-    const char* our_version = libsass_version();
-    if (!strcmp(their_version, "[na]")) return false;
-    if (!strcmp(our_version, "[na]")) return false;
-
-    // find the position of the second dot
-    size_t pos = string(our_version).find('.', 0);
-    if (pos != npos) pos = string(our_version).find('.', pos + 1);
-
-    // if we do not have two dots we fallback to compare complete string
-    if (pos == npos) { return strcmp(their_version, our_version) ? 0 : 1; }
-    // otherwise only compare up to the second dot (major versions)
-    else { return strncmp(their_version, our_version, pos) ? 0 : 1; }
-
-  }
-
-  // load one specific plugin
-  bool Plugins::load_plugin (const string& path)
-  {
-
-    typedef const char* (*__plugin_version__)(void);
-    typedef Sass_Function_List (*__plugin_load_fns__)(void);
-    typedef Sass_Importer_List (*__plugin_load_imps__)(void);
-
-    if (LOAD_LIB(plugin, path))
-    {
-      // try to load initial function to query libsass version suppor
-      if (LOAD_LIB_FN(__plugin_version__, plugin_version, "libsass_get_version"))
-      {
-        // get the libsass version of the plugin
-        if (!compatibility(plugin_version())) return false;
-        // try to get import address for "libsass_load_functions"
-        if (LOAD_LIB_FN(__plugin_load_fns__, plugin_load_functions, "libsass_load_functions"))
-        {
-          Sass_Function_List fns = plugin_load_functions();
-          while (fns && *fns) { functions.push_back(*fns); ++ fns; }
-        }
-        // try to get import address for "libsass_load_importers"
-        if (LOAD_LIB_FN(__plugin_load_imps__, plugin_load_importers, "libsass_load_importers"))
-        {
-          Sass_Importer_List imps = plugin_load_importers();
-          while (imps && *imps) { importers.push_back(*imps); ++ imps; }
-        }
-        // try to get import address for "libsass_load_headers"
-        if (LOAD_LIB_FN(__plugin_load_imps__, plugin_load_headers, "libsass_load_headers"))
-        {
-          Sass_Importer_List imps = plugin_load_headers();
-          while (imps && *imps) { headers.push_back(*imps); ++ imps; }
-        }
-        // success
-        return true;
-      }
-      else
-      {
-        // print debug message to stderr (should not happen)
-        cerr << "failed loading 'libsass_support' in <" << path << ">" << endl;
-        if (const char* dlsym_error = dlerror()) cerr << dlsym_error << endl;
-        CLOSE_LIB(plugin);
-      }
-    }
-    else
-    {
-      // print debug message to stderr (should not happen)
-      cerr << "failed loading plugin <" << path << ">" << endl;
-      if (const char* dlopen_error = dlerror()) cerr << dlopen_error << endl;
-    }
-
-    return false;
-
-  }
-
-  size_t Plugins::load_plugins(const string& path)
-  {
-
-    // count plugins
-    size_t loaded = 0;
-
-    #ifdef _WIN32
-
-      try
-      {
-
-        // use wchar (utf16)
-        WIN32_FIND_DATAW data;
-        // trailing slash is guaranteed
-        string globsrch(path + "*.dll");
-        // convert to wide chars (utf16) for system call
-        wstring wglobsrch(UTF_8::convert_to_utf16(globsrch));
-        HANDLE hFile = FindFirstFileW(wglobsrch.c_str(), &data);
-        // check if system called returned a result
-        // ToDo: maybe we should print a debug message
-        if (hFile == INVALID_HANDLE_VALUE) return -1;
-
-        // read directory
-        while (true)
-        {
-          try
-          {
-            // the system will report the filenames with wide chars (utf16)
-            string entry = UTF_8::convert_from_utf16(data.cFileName);
-            // check if file ending matches exactly
-            if (!ends_with(entry, ".dll")) continue;
-            // load the plugin and increase counter
-            if (load_plugin(path + entry)) ++ loaded;
-            // check if there should be more entries
-            if (GetLastError() == ERROR_NO_MORE_FILES) break;
-            // load next entry (check for return type)
-            if (!FindNextFileW(hFile, &data)) break;
-          }
-          catch (...)
-          {
-            // report the error to the console (should not happen)
-            // seems like we got strange data from the system call?
-            cerr << "filename in plugin path has invalid utf8?" << endl;
-          }
-        }
-      }
-      catch (utf8::invalid_utf8)
-      {
-        // report the error to the console (should not happen)
-        // implementors should make sure to provide valid utf8
-        cerr << "plugin path contains invalid utf8" << endl;
-      }
-
-    #else
-
-      DIR *dp;
-      struct dirent *dirp;
-      if((dp  = opendir(path.c_str())) == NULL) return -1;
-      while ((dirp = readdir(dp)) != NULL) {
-        if (!ends_with(dirp->d_name, ".so")) continue;
-        if (load_plugin(path + dirp->d_name)) ++ loaded;
-      }
-      closedir(dp);
-
-    #endif
-    return loaded;
-
-  }
-
-}
-
diff --git a/libsass/plugins.hpp b/libsass/plugins.hpp
deleted file mode 100644
--- a/libsass/plugins.hpp
+++ /dev/null
@@ -1,58 +0,0 @@
-#ifndef SASS_PLUGINS_H
-#define SASS_PLUGINS_H
-
-#include <string>
-#include <vector>
-#include "utf8_string.hpp"
-#include "sass_functions.h"
-
-#ifdef _WIN32
-
-  #define LOAD_LIB(var, path) HMODULE var = LoadLibraryW(UTF_8::convert_to_utf16(path).c_str())
-  #define LOAD_LIB_WCHR(var, path_wide_str) HMODULE var = LoadLibraryW(path_wide_str.c_str())
-  #define LOAD_LIB_FN(type, var, name) type var = (type) GetProcAddress(plugin, name)
-  #define CLOSE_LIB(var) FreeLibrary(var)
-
-  #ifndef dlerror
-  #define dlerror() 0
-  #endif
-
-#else
-
-  #define LOAD_LIB(var, path) void* var = dlopen(path.c_str(), RTLD_LAZY)
-  #define LOAD_LIB_FN(type, var, name) type var = (type) dlsym(plugin, name)
-  #define CLOSE_LIB(var) dlclose(var)
-
-#endif
-
-namespace Sass {
-
-  using namespace std;
-
-  class Plugins {
-
-    public: // c-tor
-      Plugins(void);
-      ~Plugins(void);
-
-    public: // methods
-      // load one specific plugin
-      bool load_plugin(const string& path);
-      // load all plugins from a directory
-      size_t load_plugins(const string& path);
-
-    public: // public accessors
-      const vector<Sass_Importer_Entry> get_headers(void) { return headers; };
-      const vector<Sass_Importer_Entry> get_importers(void) { return importers; };
-      const vector<Sass_Function_Entry> get_functions(void) { return functions; };
-
-    private: // private vars
-      vector<Sass_Importer_Entry> headers;
-      vector<Sass_Importer_Entry> importers;
-      vector<Sass_Function_Entry> functions;
-
-  };
-
-}
-
-#endif
diff --git a/libsass/position.cpp b/libsass/position.cpp
deleted file mode 100644
--- a/libsass/position.cpp
+++ /dev/null
@@ -1,163 +0,0 @@
-#include "position.hpp"
-
-namespace Sass {
-
-  using namespace std;
-
-  Offset::Offset(const char* string)
-  : line(0), column(0)
-  {
-    *this = inc(string, string + strlen(string));
-  }
-
-  Offset::Offset(const string& text)
-  : line(0), column(0)
-  {
-    *this = inc(text.c_str(), text.c_str() + text.size());
-  }
-
-  Offset::Offset(const size_t line, const size_t column)
-  : line(line), column(column) { }
-
-  // init/create instance from const char substring
-  Offset Offset::init(const char* beg, const char* end)
-  {
-    Offset offset(0, 0);
-    if (end == 0) {
-      end += strlen(beg);
-    }
-    offset.add(beg, end);
-    return offset;
-  }
-
-  // increase offset by given string (mostly called by lexer)
-  // increase line counter and count columns on the last line
-  // ToDo: make the col count utf8 aware
-  Offset Offset::add(const char* begin, const char* end)
-  {
-    if (end == 0) return *this;
-    while (begin < end && *begin) {
-      if (*begin == '\n') {
-        ++ line;
-        // start new line
-        column = 0;
-      } else {
-        ++ column;
-      }
-      ++begin;
-    }
-    return *this;
-  }
-
-  // increase offset by given string (mostly called by lexer)
-  // increase line counter and count columns on the last line
-  Offset Offset::inc(const char* begin, const char* end) const
-  {
-    Offset offset(line, column);
-    offset.add(begin, end);
-    return offset;
-  }
-
-  bool Offset::operator== (const Offset &pos) const
-  {
-    return line == pos.line && column == pos.column;
-  }
-
-  bool Offset::operator!= (const Offset &pos) const
-  {
-    return line != pos.line || column != pos.column;
-  }
-
-  void Offset::operator+= (const Offset &off)
-  {
-    *this = Offset(line + off.line, off.line > 0 ? off.column : column + off.column);
-  }
-
-  Offset Offset::operator+ (const Offset &off) const
-  {
-    return Offset(line + off.line, off.line > 0 ? off.column : column + off.column);
-  }
-
-  Offset Offset::operator- (const Offset &off) const
-  {
-    return Offset(line - off.line, off.line == line ? column - off.column : column);
-  }
-
-  Position::Position(const size_t file)
-  : Offset(0, 0), file(file) { }
-
-  Position::Position(const size_t file, const Offset& offset)
-  : Offset(offset), file(file) { }
-
-  Position::Position(const size_t line, const size_t column)
-  : Offset(line, column), file(-1) { }
-
-  Position::Position(const size_t file, const size_t line, const size_t column)
-  : Offset(line, column), file(file) { }
-
-
-  ParserState::ParserState(string path, const char* src, const size_t file)
-  : Position(file, 0, 0), path(path), src(src), offset(0, 0), token() { }
-
-  ParserState::ParserState(string path, const char* src, Position position, Offset offset)
-  : Position(position), path(path), src(src), offset(offset), token() { }
-
-  ParserState::ParserState(string path, const char* src, Token token, Position position, Offset offset)
-  : Position(position), path(path), src(src), offset(offset), token(token) { }
-
-  Position Position::add(const char* begin, const char* end)
-  {
-    Offset::add(begin, end);
-    return *this;
-  }
-
-  Position Position::inc(const char* begin, const char* end) const
-  {
-    Offset offset(line, column);
-    offset = offset.inc(begin, end);
-    return Position(file, offset);
-  }
-
-  bool Position::operator== (const Position &pos) const
-  {
-    return file == pos.file && line == pos.line && column == pos.column;
-  }
-
-  bool Position::operator!= (const Position &pos) const
-  {
-    return file == pos.file || line != pos.line || column != pos.column;
-  }
-
-  void Position::operator+= (const Offset &off)
-  {
-    *this = Position(file, line + off.line, off.line > 0 ? off.column : column + off.column);
-  }
-
-  const Position Position::operator+ (const Offset &off) const
-  {
-    return Position(file, line + off.line, off.line > 0 ? off.column : column + off.column);
-  }
-
-  const Offset Position::operator- (const Offset &off) const
-  {
-    return Offset(line - off.line, off.line == line ? column - off.column : column);
-  }
-
-  /* not used anymore - remove?
-  std::ostream& operator<<(std::ostream& strm, const Offset& off)
-  {
-    if (off.line == string::npos) strm << "-1:"; else strm << off.line << ":";
-    if (off.column == string::npos) strm << "-1"; else strm << off.column;
-    return strm;
-  } */
-
-  /* not used anymore - remove?
-  std::ostream& operator<<(std::ostream& strm, const Position& pos)
-  {
-    if (pos.file != string::npos) strm << pos.file << ":";
-    if (pos.line == string::npos) strm << "-1:"; else strm << pos.line << ":";
-    if (pos.column == string::npos) strm << "-1"; else strm << pos.column;
-    return strm;
-  } */
-
-}
diff --git a/libsass/position.hpp b/libsass/position.hpp
deleted file mode 100644
--- a/libsass/position.hpp
+++ /dev/null
@@ -1,126 +0,0 @@
-#ifndef SASS_POSITION_H
-#define SASS_POSITION_H
-
-#include <string>
-#include <cstring>
-#include <cstdlib>
-#include <sstream>
-#include <iostream>
-
-namespace Sass {
-
-  using namespace std;
-
-  class Offset {
-
-    public: // c-tor
-      Offset(const char* string);
-      Offset(const string& text);
-      Offset(const size_t line, const size_t column);
-
-      // return new position, incremented by the given string
-      Offset add(const char* begin, const char* end);
-      Offset inc(const char* begin, const char* end) const;
-
-      // init/create instance from const char substring
-      static Offset init(const char* beg, const char* end);
-
-    public: // overload operators for position
-      void operator+= (const Offset &pos);
-      bool operator== (const Offset &pos) const;
-      bool operator!= (const Offset &pos) const;
-      Offset operator+ (const Offset &off) const;
-      Offset operator- (const Offset &off) const;
-
-    public: // overload output stream operator
-      // friend ostream& operator<<(ostream& strm, const Offset& off);
-
-    public:
-      Offset off() { return *this; };
-
-    public:
-      size_t line;
-      size_t column;
-
-  };
-
-  class Position : public Offset {
-
-    public: // c-tor
-      Position(const size_t file); // line(0), column(0)
-      Position(const size_t file, const Offset& offset);
-      Position(const size_t line, const size_t column); // file(-1)
-      Position(const size_t file, const size_t line, const size_t column);
-
-    public: // overload operators for position
-      void operator+= (const Offset &off);
-      bool operator== (const Position &pos) const;
-      bool operator!= (const Position &pos) const;
-      const Position operator+ (const Offset &off) const;
-      const Offset operator- (const Offset &off) const;
-      // return new position, incremented by the given string
-      Position add(const char* begin, const char* end);
-      Position inc(const char* begin, const char* end) const;
-
-    public: // overload output stream operator
-      // friend ostream& operator<<(ostream& strm, const Position& pos);
-
-    public:
-      size_t file;
-
-  };
-
-  // Token type for representing lexed chunks of text
-  class Token {
-  public:
-    const char* prefix;
-    const char* begin;
-    const char* end;
-
-    Token()
-    : prefix(0), begin(0), end(0) { }
-    Token(const char* b, const char* e)
-    : prefix(b), begin(b), end(e) { }
-    Token(const char* str)
-    : prefix(str), begin(str), end(str + strlen(str)) { }
-    Token(const char* p, const char* b, const char* e)
-    : prefix(p), begin(b), end(e) { }
-
-    size_t length()    const { return end - begin; }
-    string ws_before() const { return string(prefix, begin); }
-    string to_string() const { return string(begin, end); }
-    string time_wspace() const {
-      string str(to_string());
-      string whitespaces(" \t\f\v\n\r");
-      return str.erase(str.find_last_not_of(whitespaces)+1);
-    }
-
-    operator bool()   { return begin && end && begin >= end; }
-    operator string() { return to_string(); }
-
-    bool operator==(Token t)  { return to_string() == t.to_string(); }
-  };
-
-  class ParserState : public Position {
-
-    public: // c-tor
-      ParserState(string path, const char* src = 0, const size_t file = string::npos);
-      ParserState(string path, const char* src, Position position, Offset offset = Offset(0, 0));
-      ParserState(string path, const char* src, Token token, Position position, Offset offset = Offset(0, 0));
-
-    public: // down casts
-      Offset off() { return *this; };
-      Position pos() { return *this; };
-      ParserState pstate() { return *this; };
-
-    public:
-      string path;
-      const char* src;
-      Offset offset;
-      Token token;
-
-  };
-
-}
-
-#endif
diff --git a/libsass/posix/getopt.c b/libsass/posix/getopt.c
deleted file mode 100644
--- a/libsass/posix/getopt.c
+++ /dev/null
@@ -1,562 +0,0 @@
-/*	$OpenBSD: getopt_long.c,v 1.23 2007/10/31 12:34:57 chl Exp $	*/
-/*	$NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $	*/
-
-/*
- * Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- * Sponsored in part by the Defense Advanced Research Projects
- * Agency (DARPA) and Air Force Research Laboratory, Air Force
- * Materiel Command, USAF, under agreement number F39502-99-1-0512.
- */
-/*-
- * Copyright (c) 2000 The NetBSD Foundation, Inc.
- * All rights reserved.
- *
- * This code is derived from software contributed to The NetBSD Foundation
- * by Dieter Baron and Thomas Klausner.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <getopt.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <windows.h>
-
-#define	REPLACE_GETOPT		/* use this getopt as the system getopt(3) */
-
-#ifdef REPLACE_GETOPT
-int	opterr = 1;		/* if error message should be printed */
-int	optind = 1;		/* index into parent argv vector */
-int	optopt = '?';		/* character checked for validity */
-#undef	optreset		/* see getopt.h */
-#define	optreset		__mingw_optreset
-int	optreset;		/* reset getopt */
-char    *optarg;		/* argument associated with option */
-#endif
-
-#define PRINT_ERROR	((opterr) && (*options != ':'))
-
-#define FLAG_PERMUTE	0x01	/* permute non-options to the end of argv */
-#define FLAG_ALLARGS	0x02	/* treat non-options as args to option "-1" */
-#define FLAG_LONGONLY	0x04	/* operate as getopt_long_only */
-
-/* return values */
-#define	BADCH		(int)'?'
-#define	BADARG		((*options == ':') ? (int)':' : (int)'?')
-#define	INORDER 	(int)1
-
-#ifndef __CYGWIN__
-#define __progname __argv[0]
-#else
-extern char __declspec(dllimport) *__progname;
-#endif
-
-#ifdef __CYGWIN__
-static char EMSG[] = "";
-#else
-#define	EMSG		""
-#endif
-
-static int getopt_internal(int, char * const *, const char *,
-			   const struct option *, int *, int);
-static int parse_long_options(char * const *, const char *,
-			      const struct option *, int *, int);
-static int gcd(int, int);
-static void permute_args(int, int, int, char * const *);
-
-static char *place = EMSG; /* option letter processing */
-
-/* XXX: set optreset to 1 rather than these two */
-static int nonopt_start = -1; /* first non option argument (for permute) */
-static int nonopt_end = -1;   /* first option after non options (for permute) */
-
-/* Error messages */
-static const char recargchar[] = "option requires an argument -- %c";
-static const char recargstring[] = "option requires an argument -- %s";
-static const char ambig[] = "ambiguous option -- %.*s";
-static const char noarg[] = "option doesn't take an argument -- %.*s";
-static const char illoptchar[] = "unknown option -- %c";
-static const char illoptstring[] = "unknown option -- %s";
-
-static void
-_vwarnx(const char *fmt,va_list ap)
-{
-  (void)fprintf(stderr,"%s: ",__progname);
-  if (fmt != NULL)
-    (void)vfprintf(stderr,fmt,ap);
-  (void)fprintf(stderr,"\n");
-}
-
-static void
-warnx(const char *fmt,...)
-{
-  va_list ap;
-  va_start(ap,fmt);
-  _vwarnx(fmt,ap);
-  va_end(ap);
-}
-
-/*
- * Compute the greatest common divisor of a and b.
- */
-static int
-gcd(int a, int b)
-{
-	int c;
-
-	c = a % b;
-	while (c != 0) {
-		a = b;
-		b = c;
-		c = a % b;
-	}
-
-	return (b);
-}
-
-/*
- * Exchange the block from nonopt_start to nonopt_end with the block
- * from nonopt_end to opt_end (keeping the same order of arguments
- * in each block).
- */
-static void
-permute_args(int panonopt_start, int panonopt_end, int opt_end,
-	char * const *nargv)
-{
-	int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
-	char *swap;
-
-	/*
-	 * compute lengths of blocks and number and size of cycles
-	 */
-	nnonopts = panonopt_end - panonopt_start;
-	nopts = opt_end - panonopt_end;
-	ncycle = gcd(nnonopts, nopts);
-	cyclelen = (opt_end - panonopt_start) / ncycle;
-
-	for (i = 0; i < ncycle; i++) {
-		cstart = panonopt_end+i;
-		pos = cstart;
-		for (j = 0; j < cyclelen; j++) {
-			if (pos >= panonopt_end)
-				pos -= nnonopts;
-			else
-				pos += nopts;
-			swap = nargv[pos];
-			/* LINTED const cast */
-			((char **) nargv)[pos] = nargv[cstart];
-			/* LINTED const cast */
-			((char **)nargv)[cstart] = swap;
-		}
-	}
-}
-
-/*
- * parse_long_options --
- *	Parse long options in argc/argv argument vector.
- * Returns -1 if short_too is set and the option does not match long_options.
- */
-static int
-parse_long_options(char * const *nargv, const char *options,
-	const struct option *long_options, int *idx, int short_too)
-{
-	char *current_argv, *has_equal;
-	size_t current_argv_len;
-	int i, ambiguous, match;
-
-#define IDENTICAL_INTERPRETATION(_x, _y)                                \
-	(long_options[(_x)].has_arg == long_options[(_y)].has_arg &&    \
-	 long_options[(_x)].flag == long_options[(_y)].flag &&          \
-	 long_options[(_x)].val == long_options[(_y)].val)
-
-	current_argv = place;
-	match = -1;
-	ambiguous = 0;
-
-	optind++;
-
-	if ((has_equal = strchr(current_argv, '=')) != NULL) {
-		/* argument found (--option=arg) */
-		current_argv_len = has_equal - current_argv;
-		has_equal++;
-	} else
-		current_argv_len = strlen(current_argv);
-
-	for (i = 0; long_options[i].name; i++) {
-		/* find matching long option */
-		if (strncmp(current_argv, long_options[i].name,
-		    current_argv_len))
-			continue;
-
-		if (strlen(long_options[i].name) == current_argv_len) {
-			/* exact match */
-			match = i;
-			ambiguous = 0;
-			break;
-		}
-		/*
-		 * If this is a known short option, don't allow
-		 * a partial match of a single character.
-		 */
-		if (short_too && current_argv_len == 1)
-			continue;
-
-		if (match == -1)	/* partial match */
-			match = i;
-		else if (!IDENTICAL_INTERPRETATION(i, match))
-			ambiguous = 1;
-	}
-	if (ambiguous) {
-		/* ambiguous abbreviation */
-		if (PRINT_ERROR)
-			warnx(ambig, (int)current_argv_len,
-			     current_argv);
-		optopt = 0;
-		return (BADCH);
-	}
-	if (match != -1) {		/* option found */
-		if (long_options[match].has_arg == no_argument
-		    && has_equal) {
-			if (PRINT_ERROR)
-				warnx(noarg, (int)current_argv_len,
-				     current_argv);
-			/*
-			 * XXX: GNU sets optopt to val regardless of flag
-			 */
-			if (long_options[match].flag == NULL)
-				optopt = long_options[match].val;
-			else
-				optopt = 0;
-			return (BADARG);
-		}
-		if (long_options[match].has_arg == required_argument ||
-		    long_options[match].has_arg == optional_argument) {
-			if (has_equal)
-				optarg = has_equal;
-			else if (long_options[match].has_arg ==
-			    required_argument) {
-				/*
-				 * optional argument doesn't use next nargv
-				 */
-				optarg = nargv[optind++];
-			}
-		}
-		if ((long_options[match].has_arg == required_argument)
-		    && (optarg == NULL)) {
-			/*
-			 * Missing argument; leading ':' indicates no error
-			 * should be generated.
-			 */
-			if (PRINT_ERROR)
-				warnx(recargstring,
-				    current_argv);
-			/*
-			 * XXX: GNU sets optopt to val regardless of flag
-			 */
-			if (long_options[match].flag == NULL)
-				optopt = long_options[match].val;
-			else
-				optopt = 0;
-			--optind;
-			return (BADARG);
-		}
-	} else {			/* unknown option */
-		if (short_too) {
-			--optind;
-			return (-1);
-		}
-		if (PRINT_ERROR)
-			warnx(illoptstring, current_argv);
-		optopt = 0;
-		return (BADCH);
-	}
-	if (idx)
-		*idx = match;
-	if (long_options[match].flag) {
-		*long_options[match].flag = long_options[match].val;
-		return (0);
-	} else
-		return (long_options[match].val);
-#undef IDENTICAL_INTERPRETATION
-}
-
-/*
- * getopt_internal --
- *	Parse argc/argv argument vector.  Called by user level routines.
- */
-static int
-getopt_internal(int nargc, char * const *nargv, const char *options,
-	const struct option *long_options, int *idx, int flags)
-{
-	char *oli;				/* option letter list index */
-	int optchar, short_too;
-	static int posixly_correct = -1;
-
-	if (options == NULL)
-		return (-1);
-
-	/*
-	 * XXX Some GNU programs (like cvs) set optind to 0 instead of
-	 * XXX using optreset.  Work around this braindamage.
-	 */
-	if (optind == 0)
-		optind = optreset = 1;
-
-	/*
-	 * Disable GNU extensions if POSIXLY_CORRECT is set or options
-	 * string begins with a '+'.
-	 *
-	 * CV, 2009-12-14: Check POSIXLY_CORRECT anew if optind == 0 or
-	 *                 optreset != 0 for GNU compatibility.
-	 */
-	if (posixly_correct == -1 || optreset != 0)
-		posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
-	if (*options == '-')
-		flags |= FLAG_ALLARGS;
-	else if (posixly_correct || *options == '+')
-		flags &= ~FLAG_PERMUTE;
-	if (*options == '+' || *options == '-')
-		options++;
-
-	optarg = NULL;
-	if (optreset)
-		nonopt_start = nonopt_end = -1;
-start:
-	if (optreset || !*place) {		/* update scanning pointer */
-		optreset = 0;
-		if (optind >= nargc) {          /* end of argument vector */
-			place = EMSG;
-			if (nonopt_end != -1) {
-				/* do permutation, if we have to */
-				permute_args(nonopt_start, nonopt_end,
-				    optind, nargv);
-				optind -= nonopt_end - nonopt_start;
-			}
-			else if (nonopt_start != -1) {
-				/*
-				 * If we skipped non-options, set optind
-				 * to the first of them.
-				 */
-				optind = nonopt_start;
-			}
-			nonopt_start = nonopt_end = -1;
-			return (-1);
-		}
-		if (*(place = nargv[optind]) != '-' ||
-		    (place[1] == '\0' && strchr(options, '-') == NULL)) {
-			place = EMSG;		/* found non-option */
-			if (flags & FLAG_ALLARGS) {
-				/*
-				 * GNU extension:
-				 * return non-option as argument to option 1
-				 */
-				optarg = nargv[optind++];
-				return (INORDER);
-			}
-			if (!(flags & FLAG_PERMUTE)) {
-				/*
-				 * If no permutation wanted, stop parsing
-				 * at first non-option.
-				 */
-				return (-1);
-			}
-			/* do permutation */
-			if (nonopt_start == -1)
-				nonopt_start = optind;
-			else if (nonopt_end != -1) {
-				permute_args(nonopt_start, nonopt_end,
-				    optind, nargv);
-				nonopt_start = optind -
-				    (nonopt_end - nonopt_start);
-				nonopt_end = -1;
-			}
-			optind++;
-			/* process next argument */
-			goto start;
-		}
-		if (nonopt_start != -1 && nonopt_end == -1)
-			nonopt_end = optind;
-
-		/*
-		 * If we have "-" do nothing, if "--" we are done.
-		 */
-		if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
-			optind++;
-			place = EMSG;
-			/*
-			 * We found an option (--), so if we skipped
-			 * non-options, we have to permute.
-			 */
-			if (nonopt_end != -1) {
-				permute_args(nonopt_start, nonopt_end,
-				    optind, nargv);
-				optind -= nonopt_end - nonopt_start;
-			}
-			nonopt_start = nonopt_end = -1;
-			return (-1);
-		}
-	}
-
-	/*
-	 * Check long options if:
-	 *  1) we were passed some
-	 *  2) the arg is not just "-"
-	 *  3) either the arg starts with -- we are getopt_long_only()
-	 */
-	if (long_options != NULL && place != nargv[optind] &&
-	    (*place == '-' || (flags & FLAG_LONGONLY))) {
-		short_too = 0;
-		if (*place == '-')
-			place++;		/* --foo long option */
-		else if (*place != ':' && strchr(options, *place) != NULL)
-			short_too = 1;		/* could be short option too */
-
-		optchar = parse_long_options(nargv, options, long_options,
-		    idx, short_too);
-		if (optchar != -1) {
-			place = EMSG;
-			return (optchar);
-		}
-	}
-
-	if ((optchar = (int)*place++) == (int)':' ||
-	    (optchar == (int)'-' && *place != '\0') ||
-	    (oli = strchr(options, optchar)) == NULL) {
-		/*
-		 * If the user specified "-" and  '-' isn't listed in
-		 * options, return -1 (non-option) as per POSIX.
-		 * Otherwise, it is an unknown option character (or ':').
-		 */
-		if (optchar == (int)'-' && *place == '\0')
-			return (-1);
-		if (!*place)
-			++optind;
-		if (PRINT_ERROR)
-			warnx(illoptchar, optchar);
-		optopt = optchar;
-		return (BADCH);
-	}
-	if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
-		/* -W long-option */
-		if (*place)			/* no space */
-			/* NOTHING */;
-		else if (++optind >= nargc) {	/* no arg */
-			place = EMSG;
-			if (PRINT_ERROR)
-				warnx(recargchar, optchar);
-			optopt = optchar;
-			return (BADARG);
-		} else				/* white space */
-			place = nargv[optind];
-		optchar = parse_long_options(nargv, options, long_options,
-		    idx, 0);
-		place = EMSG;
-		return (optchar);
-	}
-	if (*++oli != ':') {			/* doesn't take argument */
-		if (!*place)
-			++optind;
-	} else {				/* takes (optional) argument */
-		optarg = NULL;
-		if (*place)			/* no white space */
-			optarg = place;
-		else if (oli[1] != ':') {	/* arg not optional */
-			if (++optind >= nargc) {	/* no arg */
-				place = EMSG;
-				if (PRINT_ERROR)
-					warnx(recargchar, optchar);
-				optopt = optchar;
-				return (BADARG);
-			} else
-				optarg = nargv[optind];
-		}
-		place = EMSG;
-		++optind;
-	}
-	/* dump back option letter */
-	return (optchar);
-}
-
-#ifdef REPLACE_GETOPT
-/*
- * getopt --
- *	Parse argc/argv argument vector.
- *
- * [eventually this will replace the BSD getopt]
- */
-int
-getopt(int nargc, char * const *nargv, const char *options)
-{
-
-	/*
-	 * We don't pass FLAG_PERMUTE to getopt_internal() since
-	 * the BSD getopt(3) (unlike GNU) has never done this.
-	 *
-	 * Furthermore, since many privileged programs call getopt()
-	 * before dropping privileges it makes sense to keep things
-	 * as simple (and bug-free) as possible.
-	 */
-	return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
-}
-#endif /* REPLACE_GETOPT */
-
-/*
- * getopt_long --
- *	Parse argc/argv argument vector.
- */
-int
-getopt_long(int nargc, char * const *nargv, const char *options,
-    const struct option *long_options, int *idx)
-{
-
-	return (getopt_internal(nargc, nargv, options, long_options, idx,
-	    FLAG_PERMUTE));
-}
-
-/*
- * getopt_long_only --
- *	Parse argc/argv argument vector.
- */
-int
-getopt_long_only(int nargc, char * const *nargv, const char *options,
-    const struct option *long_options, int *idx)
-{
-
-	return (getopt_internal(nargc, nargv, options, long_options, idx,
-	    FLAG_PERMUTE|FLAG_LONGONLY));
-}
diff --git a/libsass/posix/getopt.h b/libsass/posix/getopt.h
deleted file mode 100644
--- a/libsass/posix/getopt.h
+++ /dev/null
@@ -1,95 +0,0 @@
-#ifndef __GETOPT_H__
-/**
- * DISCLAIMER
- * This file has no copyright assigned and is placed in the Public Domain.
- * This file is a part of the w64 mingw-runtime package.
- *
- * The w64 mingw-runtime package and its code is distributed in the hope that it 
- * will be useful but WITHOUT ANY WARRANTY.  ALL WARRANTIES, EXPRESSED OR 
- * IMPLIED ARE HEREBY DISCLAIMED.  This includes but is not limited to 
- * warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- */
-
-#define __GETOPT_H__
-
-/* All the headers include this file. */
-#include <crtdefs.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-extern int optind;		/* index of first non-option in argv      */
-extern int optopt;		/* single option character, as parsed     */
-extern int opterr;		/* flag to enable built-in diagnostics... */
-				/* (user may set to zero, to suppress)    */
-
-extern char *optarg;		/* pointer to argument of current option  */
-
-extern int getopt(int nargc, char * const *nargv, const char *options);
-
-#ifdef _BSD_SOURCE
-/*
- * BSD adds the non-standard `optreset' feature, for reinitialisation
- * of `getopt' parsing.  We support this feature, for applications which
- * proclaim their BSD heritage, before including this header; however,
- * to maintain portability, developers are advised to avoid it.
- */
-# define optreset  __mingw_optreset
-extern int optreset;
-#endif
-#ifdef __cplusplus
-}
-#endif
-/*
- * POSIX requires the `getopt' API to be specified in `unistd.h';
- * thus, `unistd.h' includes this header.  However, we do not want
- * to expose the `getopt_long' or `getopt_long_only' APIs, when
- * included in this manner.  Thus, close the standard __GETOPT_H__
- * declarations block, and open an additional __GETOPT_LONG_H__
- * specific block, only when *not* __UNISTD_H_SOURCED__, in which
- * to declare the extended API.
- */
-#endif /* !defined(__GETOPT_H__) */
-
-#if !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__)
-#define __GETOPT_LONG_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct option		/* specification for a long form option...	*/
-{
-  const char *name;		/* option name, without leading hyphens */
-  int         has_arg;		/* does it take an argument?		*/
-  int        *flag;		/* where to save its status, or NULL	*/
-  int         val;		/* its associated status value		*/
-};
-
-enum    		/* permitted values for its `has_arg' field...	*/
-{
-  no_argument = 0,      	/* option never takes an argument	*/
-  required_argument,		/* option always requires an argument	*/
-  optional_argument		/* option may take an argument		*/
-};
-
-extern int getopt_long(int nargc, char * const *nargv, const char *options,
-    const struct option *long_options, int *idx);
-extern int getopt_long_only(int nargc, char * const *nargv, const char *options,
-    const struct option *long_options, int *idx);
-/*
- * Previous MinGW implementation had...
- */
-#ifndef HAVE_DECL_GETOPT
-/*
- * ...for the long form API only; keep this for compatibility.
- */
-# define HAVE_DECL_GETOPT	1
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) */
diff --git a/libsass/prelexer.cpp b/libsass/prelexer.cpp
deleted file mode 100644
--- a/libsass/prelexer.cpp
+++ /dev/null
@@ -1,784 +0,0 @@
-#include <cctype>
-#include <cstddef>
-#include <iostream>
-#include <iomanip>
-#include "util.hpp"
-#include "position.hpp"
-#include "prelexer.hpp"
-#include "constants.hpp"
-
-
-namespace Sass {
-  // using namespace Lexer;
-  using namespace Constants;
-
-  namespace Prelexer {
-
-
-    // Match a line comment (/.*?(?=\n|\r\n?|\Z)/.
-    const char* line_comment(const char* src)
-    {
-      return sequence<
-               exactly <
-                 slash_slash
-               >,
-               non_greedy<
-                 any_char,
-                 end_of_line
-               >
-             >(src);
-    }
-
-    // Match a block comment.
-    const char* block_comment(const char* src)
-    {
-      return sequence<
-               zero_plus < space >,
-               delimited_by<
-                 slash_star,
-                 star_slash,
-                 false
-               >
-             >(src);
-    }
-    /* not use anymore - remove?
-    const char* block_comment_prefix(const char* src) {
-      return exactly<slash_star>(src);
-    }
-    // Match either comment.
-    const char* comment(const char* src) {
-      return line_comment(src);
-    }
-    */
-
-    // Match zero plus white-space or line_comments
-    const char* optional_css_whitespace(const char* src) {
-      return zero_plus< alternatives<spaces, line_comment> >(src);
-    }
-    const char* css_whitespace(const char* src) {
-      return one_plus< alternatives<spaces, line_comment> >(src);
-    }
-    // Match optional_css_whitepace plus block_comments
-    const char* optional_css_comments(const char* src) {
-      return zero_plus< alternatives<spaces, line_comment, block_comment> >(src);
-    }
-    const char* css_comments(const char* src) {
-      return one_plus< alternatives<spaces, line_comment, block_comment> >(src);
-    }
-
-    // Match one backslash escaped char /\\./
-    const char* escape_seq(const char* src)
-    {
-      return sequence<
-        exactly<'\\'>,
-        any_char
-      >(src);
-    }
-
-    // Match identifier start
-    const char* identifier_alpha(const char* src)
-    {
-      return alternatives<
-               alpha,
-               unicode,
-               exactly<'-'>,
-               exactly<'_'>,
-               escape_seq
-             >(src);
-    }
-
-    // Match identifier after start
-    const char* identifier_alnum(const char* src)
-    {
-      return alternatives<
-               alnum,
-               unicode,
-               exactly<'-'>,
-               exactly<'_'>,
-               escape_seq
-             >(src);
-    }
-
-    // Match CSS identifiers.
-    const char* identifier(const char* src)
-    {
-      return sequence<
-               zero_plus< exactly<'-'> >,
-               one_plus < identifier_alpha >,
-               zero_plus < identifier_alnum >
-               // word_boundary not needed
-             >(src);
-    }
-
-    const char* identifier_alnums(const char* src)
-    {
-      return one_plus< identifier_alnum >(src);
-    }
-
-    // Match number prefix ([\+\-]+)
-    const char* number_prefix(const char* src) {
-      return alternatives <
-        exactly < '+' >,
-        sequence <
-          exactly < '-' >,
-          optional_css_whitespace,
-          exactly< '-' >
-        >
-      >(src);
-    }
-
-    // Match interpolant schemas
-    const char* identifier_schema(const char* src) {
-      // follows this pattern: (x*ix*)+ ... well, not quite
-      return sequence< one_plus< sequence< zero_plus< alternatives< identifier, exactly<'-'> > >,
-                                 interpolant,
-                                 zero_plus< alternatives< identifier, number, exactly<'-'> > > > >,
-                       negate< exactly<'%'> > >(src);
-    }
-
-    // interpolants can be recursive/nested
-    const char* interpolant(const char* src) {
-      return recursive_scopes< exactly<hash_lbrace>, exactly<rbrace> >(src);
-    }
-
-    // $re_squote = /'(?:$re_itplnt|\\.|[^'])*'/
-    const char* single_quoted_string(const char* src) {
-      // match a single quoted string, while skipping interpolants
-      return sequence <
-        exactly <'\''>,
-        zero_plus <
-          alternatives <
-            // skip escapes
-            sequence <
-              exactly < '\\' >,
-              exactly < '\r' >,
-              exactly < '\n' >
-            >,
-            escape_seq,
-            // skip interpolants
-            interpolant,
-            // skip non delimiters
-            any_char_but < '\'' >
-          >
-        >,
-        exactly <'\''>
-      >(src);
-    }
-
-    // $re_dquote = /"(?:$re_itp|\\.|[^"])*"/
-    const char* double_quoted_string(const char* src) {
-      // match a single quoted string, while skipping interpolants
-      return sequence <
-        exactly <'"'>,
-        zero_plus <
-          alternatives <
-            // skip escapes
-            sequence <
-              exactly < '\\' >,
-              exactly < '\r' >,
-              exactly < '\n' >
-            >,
-            escape_seq,
-            // skip interpolants
-            interpolant,
-            // skip non delimiters
-            any_char_but < '"' >
-          >
-        >,
-        exactly <'"'>
-      >(src);
-    }
-
-    // $re_quoted = /(?:$re_squote|$re_dquote)/
-    const char* quoted_string(const char* src) {
-      // match a quoted string, while skipping interpolants
-      return alternatives<
-        single_quoted_string,
-        double_quoted_string
-      >(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);
-    }
-
-    /* not used anymore - remove?
-    const char* filename(const char* src) {
-      return one_plus< alternatives< identifier, number, exactly<'.'> > >(src);
-    }
-    */
-
-    // Match CSS '@' keywords.
-    const char* at_keyword(const char* src) {
-      return sequence<exactly<'@'>, identifier>(src);
-    }
-
-    const char* kwd_sel_deep(const char* src) {
-      return word<sel_deep_kwd>(src);
-    }
-
-    const char* kwd_import(const char* src) {
-      return word<import_kwd>(src);
-    }
-
-    const char* kwd_at_root(const char* src) {
-      return word<at_root_kwd>(src);
-    }
-
-    const char* kwd_with_directive(const char* src) {
-      return word<with_kwd>(src);
-    }
-
-    const char* kwd_without_directive(const char* src) {
-      return word<without_kwd>(src);
-    }
-
-    const char* kwd_media(const char* src) {
-      return word<media_kwd>(src);
-    }
-
-    const char* kwd_supports(const char* src) {
-      return word<supports_kwd>(src);
-    }
-
-    const char* kwd_mixin(const char* src) {
-      return word<mixin_kwd>(src);
-    }
-
-    const char* kwd_function(const char* src) {
-      return word<function_kwd>(src);
-    }
-
-    const char* kwd_return_directive(const char* src) {
-      return word<return_kwd>(src);
-    }
-
-    const char* kwd_include(const char* src) {
-      return word<include_kwd>(src);
-    }
-
-    const char* kwd_content(const char* src) {
-      return word<content_kwd>(src);
-    }
-
-    const char* kwd_extend(const char* src) {
-      return word<extend_kwd>(src);
-    }
-
-
-    const char* kwd_if_directive(const char* src) {
-      return word<if_kwd>(src);
-    }
-
-    const char* kwd_else_directive(const char* src) {
-      return word<else_kwd>(src);
-    }
-    const char* elseif_directive(const char* src) {
-      return sequence< exactly< else_kwd >,
-                                optional_css_whitespace,
-                                word< if_after_else_kwd > >(src);
-    }
-
-    const char* kwd_for_directive(const char* src) {
-      return word<for_kwd>(src);
-    }
-
-    const char* kwd_from(const char* src) {
-      return word<from_kwd>(src);
-    }
-
-    const char* kwd_to(const char* src) {
-      return word<to_kwd>(src);
-    }
-
-    const char* kwd_through(const char* src) {
-      return word<through_kwd>(src);
-    }
-
-    const char* kwd_each_directive(const char* src) {
-      return word<each_kwd>(src);
-    }
-
-    const char* kwd_in(const char* src) {
-      return word<in_kwd>(src);
-    }
-
-    const char* kwd_while_directive(const char* src) {
-      return word<while_kwd>(src);
-    }
-
-    const char* name(const char* src) {
-      return one_plus< alternatives< alnum,
-                                     exactly<'-'>,
-                                     exactly<'_'>,
-                                     exactly<'\\'> > >(src);
-    }
-
-    const char* kwd_warn(const char* src) {
-      return word<warn_kwd>(src);
-    }
-
-    const char* kwd_err(const char* src) {
-      return word<error_kwd>(src);
-    }
-
-    const char* kwd_dbg(const char* src) {
-      return word<debug_kwd>(src);
-    }
-
-    /* not used anymore - remove?
-    const char* directive(const char* src) {
-      return sequence< exactly<'@'>, identifier >(src);
-    } */
-
-    const char* kwd_null(const char* src) {
-      return word<null_kwd>(src);
-    }
-
-    // Match CSS type selectors
-    const char* namespace_prefix(const char* src) {
-      return sequence< optional< alternatives< identifier, exactly<'*'> > >,
-                       exactly<'|'> >(src);
-    }
-    const char* type_selector(const char* src) {
-      return sequence< optional<namespace_prefix>, identifier>(src);
-    }
-    const char* hyphens_and_identifier(const char* src) {
-      return sequence< zero_plus< exactly< '-' > >, identifier >(src);
-    }
-    const char* hyphens_and_name(const char* src) {
-      return sequence< zero_plus< exactly< '-' > >, name >(src);
-    }
-    const char* universal(const char* src) {
-      return sequence< optional<namespace_prefix>, exactly<'*'> >(src);
-    }
-    // Match CSS id names.
-    const char* id_name(const char* src) {
-      return sequence<exactly<'#'>, name>(src);
-    }
-    // Match CSS class names.
-    const char* class_name(const char* src) {
-      return sequence<exactly<'.'>, identifier>(src);
-    }
-    // Attribute name in an attribute selector.
-    const char* attribute_name(const char* src) {
-      return alternatives< sequence< optional<namespace_prefix>, identifier>,
-                           identifier >(src);
-    }
-    // match placeholder selectors
-    const char* placeholder(const char* src) {
-      return sequence<exactly<'%'>, identifier>(src);
-    }
-    // Match CSS numeric constants.
-
-    const char* sign(const char* src) {
-      return class_char<sign_chars>(src);
-    }
-    const char* unsigned_number(const char* src) {
-      return alternatives<sequence< zero_plus<digits>,
-                                    exactly<'.'>,
-                                    one_plus<digits> >,
-                          digits>(src);
-    }
-    const char* number(const char* src) {
-      return sequence< optional<sign>, unsigned_number>(src);
-    }
-    const char* coefficient(const char* src) {
-      return alternatives< sequence< optional<sign>, digits >,
-                           sign >(src);
-    }
-    const char* binomial(const char* src) {
-      return sequence< optional<sign>,
-                       optional<digits>,
-                       exactly<'n'>,
-                       zero_plus < space >,
-                       sign,
-                       zero_plus < space >,
-                       digits >(src);
-    }
-    const char* percentage(const char* src) {
-      return sequence< number, exactly<'%'> >(src);
-    }
-    const char* ampersand(const char* src) {
-      return exactly<'&'>(src);
-    }
-
-    /* not used anymore - remove?
-    const char* em(const char* src) {
-      return sequence< number, exactly<em_kwd> >(src);
-    } */
-    const char* dimension(const char* src) {
-      return sequence<number, one_plus< alpha > >(src);
-    }
-    const char* hex(const char* src) {
-      const char* p = sequence< exactly<'#'>, one_plus<xdigit> >(src);
-      ptrdiff_t len = p - src;
-      return (len != 4 && len != 7) ? 0 : p;
-    }
-    const char* hexa(const char* src) {
-      const char* p = sequence< exactly<'#'>, one_plus<xdigit> >(src);
-      ptrdiff_t len = p - src;
-      return (len != 4 && len != 7 && len != 9) ? 0 : p;
-    }
-    const char* hex0(const char* src) {
-      const char* p = sequence< exactly<'0'>, exactly<'x'>, one_plus<xdigit> >(src);
-      ptrdiff_t len = p - src;
-      return (len != 5 && len != 8) ? 0 : p;
-    }
-
-    /* no longer used - remove?
-    const char* rgb_prefix(const char* src) {
-      return word<rgb_kwd>(src);
-    }*/
-    // 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 < '$' >
-        >,
-        zero_plus <
-          alternatives <
-            alnum,
-            exactly <'/'>,
-            class_char < uri_chars >
-          >
-        >
-      >(src);
-    }
-
-    // TODO: rename the following two functions
-    /* no longer used - remove?
-    const char* uri(const char* src) {
-      return sequence< exactly<url_kwd>,
-                       optional<spaces>,
-                       quoted_string,
-                       optional<spaces>,
-                       exactly<')'> >(src);
-    }*/
-    /* no longer used - remove?
-    const char* url_value(const char* src) {
-      return sequence< optional< sequence< identifier, exactly<':'> > >, // optional protocol
-                       one_plus< sequence< zero_plus< exactly<'/'> >, filename > >, // one or more folders and/or trailing filename
-                       optional< exactly<'/'> > >(src);
-    }*/
-    /* no longer used - remove?
-    const char* url_schema(const char* src) {
-      return sequence< optional< sequence< identifier, exactly<':'> > >, // optional protocol
-                       filename_schema >(src); // optional trailing slash
-    }*/
-    // Match CSS "!important" keyword.
-    const char* important(const char* src) {
-      return sequence< exactly<'!'>,
-                       optional_css_whitespace,
-                       word<important_kwd> >(src);
-    }
-    // Match CSS "!optional" keyword.
-    const char* optional(const char* src) {
-      return sequence< exactly<'!'>,
-      optional_css_whitespace,
-      word<optional_kwd> >(src);
-    }
-    // Match Sass "!default" keyword.
-    const char* default_flag(const char* src) {
-      return sequence< exactly<'!'>,
-                       optional_css_whitespace,
-                       word<default_kwd> >(src);
-    }
-    // Match Sass "!global" keyword.
-    const char* global_flag(const char* src) {
-      return sequence< exactly<'!'>,
-                       optional_css_whitespace,
-                       word<global_kwd> >(src);
-    }
-    // Match CSS pseudo-class/element prefixes.
-    const char* pseudo_prefix(const char* src) {
-      return sequence< exactly<':'>, optional< exactly<':'> > >(src);
-    }
-    // Match CSS function call openers.
-    const char* functional_schema(const char* src) {
-      return sequence< identifier_schema, exactly<'('> >(src);
-    }
-    const char* functional(const char* src) {
-      return sequence< identifier, exactly<'('> >(src);
-    }
-    // Match the CSS negation pseudo-class.
-    const char* pseudo_not(const char* src) {
-      return word< pseudo_not_kwd >(src);
-    }
-    // Match CSS 'odd' and 'even' keywords for functional pseudo-classes.
-    const char* even(const char* src) {
-      return word<even_kwd>(src);
-    }
-    const char* odd(const char* src) {
-      return word<odd_kwd>(src);
-    }
-    // Match CSS attribute-matching operators.
-    const char* exact_match(const char* src) { return exactly<'='>(src); }
-    const char* class_match(const char* src) { return exactly<tilde_equal>(src); }
-    const char* dash_match(const char* src) { return exactly<pipe_equal>(src); }
-    const char* prefix_match(const char* src) { return exactly<caret_equal>(src); }
-    const char* suffix_match(const char* src) { return exactly<dollar_equal>(src); }
-    const char* substring_match(const char* src) { return exactly<star_equal>(src); }
-    // Match CSS combinators.
-    /* not used anymore - remove?
-    const char* adjacent_to(const char* src) {
-      return sequence< optional_spaces, exactly<'+'> >(src);
-    }
-    const char* precedes(const char* src) {
-      return sequence< optional_spaces, exactly<'~'> >(src);
-    }
-    const char* parent_of(const char* src) {
-      return sequence< optional_spaces, exactly<'>'> >(src);
-    }
-    const char* ancestor_of(const char* src) {
-      return sequence< spaces, negate< exactly<'{'> > >(src);
-    }*/
-
-    // Match SCSS variable names.
-    const char* variable(const char* src) {
-      return sequence<exactly<'$'>, identifier>(src);
-    }
-
-    // Match Sass boolean keywords.
-    const char* kwd_true(const char* src) {
-      return word<true_kwd>(src);
-    }
-    const char* kwd_false(const char* src) {
-      return word<false_kwd>(src);
-    }
-    const char* kwd_and(const char* src) {
-      return word<and_kwd>(src);
-    }
-    const char* kwd_or(const char* src) {
-      return word<or_kwd>(src);
-    }
-    const char* kwd_not(const char* src) {
-      return word<not_kwd>(src);
-    }
-    const char* kwd_eq(const char* src) {
-      return exactly<eq>(src);
-    }
-    const char* kwd_neq(const char* src) {
-      return exactly<neq>(src);
-    }
-    const char* kwd_gt(const char* src) {
-      return exactly<gt>(src);
-    }
-    const char* kwd_gte(const char* src) {
-      return exactly<gte>(src);
-    }
-    const char* kwd_lt(const char* src) {
-      return exactly<lt>(src);
-    }
-    const char* kwd_lte(const char* src) {
-      return exactly<lte>(src);
-    }
-
-    // match specific IE syntax
-    const char* ie_progid(const char* src) {
-      return sequence <
-        word<progid_kwd>,
-        exactly<':'>,
-        alternatives< identifier_schema, identifier >,
-        zero_plus< sequence<
-          exactly<'.'>,
-          alternatives< identifier_schema, identifier >
-        > >,
-        zero_plus < sequence<
-          exactly<'('>,
-          optional_css_whitespace,
-          optional < sequence<
-            alternatives< variable, identifier_schema, identifier >,
-            optional_css_whitespace,
-            exactly<'='>,
-            optional_css_whitespace,
-            alternatives< variable, identifier_schema, identifier, quoted_string, number, hexa >,
-            zero_plus< sequence<
-              optional_css_whitespace,
-              exactly<','>,
-              optional_css_whitespace,
-              sequence<
-                alternatives< variable, identifier_schema, identifier >,
-                optional_css_whitespace,
-                exactly<'='>,
-                optional_css_whitespace,
-                alternatives< variable, identifier_schema, identifier, quoted_string, number, hexa >
-              >
-            > >
-          > >,
-          optional_css_whitespace,
-          exactly<')'>
-        > >
-      >(src);
-    }
-    const char* ie_expression(const char* src) {
-      return sequence < word<expression_kwd>, exactly<'('>, skip_over_scopes< exactly<'('>, exactly<')'> > >(src);
-    }
-    const char* ie_property(const char* src) {
-      return alternatives < ie_expression, ie_progid >(src);
-    }
-
-    // const char* ie_args(const char* src) {
-    //   return sequence< alternatives< ie_keyword_arg, value_schema, quoted_string, interpolant, number, identifier, delimited_by< '(', ')', true> >,
-    //                    zero_plus< sequence< optional_css_whitespace, exactly<','>, optional_css_whitespace, alternatives< ie_keyword_arg, value_schema, quoted_string, interpolant, number, identifier, delimited_by<'(', ')', true> > > > >(src);
-    // }
-
-    const char* ie_keyword_arg_property(const char* src) {
-      return alternatives <
-          variable,
-          identifier_schema,
-          identifier
-        >(src);
-    }
-    const char* ie_keyword_arg_value(const char* src) {
-      return alternatives <
-          variable,
-          identifier_schema,
-          identifier,
-          quoted_string,
-          number,
-          hexa,
-          sequence <
-            exactly < '(' >,
-            skip_over_scopes <
-              exactly < '(' >,
-              exactly < ')' >
-            >
-          >
-        >(src);
-    }
-
-    const char* ie_keyword_arg(const char* src) {
-      return sequence <
-        ie_keyword_arg_property,
-        optional_css_whitespace,
-        exactly<'='>,
-        optional_css_whitespace,
-        ie_keyword_arg_value
-      >(src);
-    }
-
-    // Path matching functions.
-    /* not used anymore - remove?
-    const char* folder(const char* src) {
-      return sequence< zero_plus< any_char_except<'/'> >,
-                       exactly<'/'> >(src);
-    }
-    const char* folders(const char* src) {
-      return zero_plus< folder >(src);
-    }*/
-    /* not used anymore - remove?
-    const char* chunk(const char* src) {
-      char inside_str = 0;
-      const char* p = src;
-      size_t depth = 0;
-      while (true) {
-        if (!*p) {
-          return 0;
-        }
-        else if (!inside_str && (*p == '"' || *p == '\'')) {
-          inside_str = *p;
-        }
-        else if (*p == inside_str && *(p-1) != '\\') {
-          inside_str = 0;
-        }
-        else if (*p == '(' && !inside_str) {
-          ++depth;
-        }
-        else if (*p == ')' && !inside_str) {
-          if (depth == 0) return p;
-          else            --depth;
-        }
-        ++p;
-      }
-      // unreachable
-      return 0;
-    }
-    */
-
-    // follow the CSS spec more closely and see if this helps us scan URLs correctly
-    /* not used anymore - remove?
-    const char* NL(const char* src) {
-      return alternatives< exactly<'\n'>,
-                           sequence< exactly<'\r'>, exactly<'\n'> >,
-                           exactly<'\r'>,
-                           exactly<'\f'> >(src);
-    }*/
-
-    /* not used anymore - remove?
-    const char* H(const char* src) {
-      return std::isxdigit(*src) ? src+1 : 0;
-    }*/
-
-    /* not used anymore - remove?
-    const char* unicode(const char* src) {
-      return sequence< exactly<'\\'>,
-                       between<H, 1, 6>,
-                       optional< class_char<url_space_chars> > >(src);
-    }*/
-
-    /* not used anymore - remove?
-    const char* ESCAPE(const char* src) {
-      return alternatives< unicode, class_char<escape_chars> >(src);
-    }*/
-
-    const char* static_string(const char* src) {
-      const char* pos = src;
-      const char * s = quoted_string(pos);
-      Token t(pos, s);
-      const unsigned int p = count_interval< interpolant >(t.begin, t.end);
-      return (p == 0) ? t.end : 0;
-    }
-
-    const char* static_component(const char* src) {
-      return alternatives< identifier,
-                           static_string,
-                           percentage,
-                           hex,
-                           number,
-                           sequence< exactly<'!'>, word<important_kwd> >
-                          >(src);
-    }
-
-    const char* static_value(const char* src) {
-      return sequence< sequence<
-                         static_component,
-                         zero_plus< identifier >
-                       >,
-                       zero_plus < sequence<
-                                   alternatives<
-                                     sequence< optional_spaces, alternatives<
-                                       exactly < '/' >,
-                                       exactly < ',' >,
-                                       exactly < ' ' >
-                                     >, optional_spaces >,
-                                     spaces
-                                   >,
-                                   static_component
-                       > >,
-                       optional_css_whitespace,
-                       alternatives< exactly<';'>, exactly<'}'> >
-                      >(src);
-    }
-
-    const char* parenthese_scope(const char* src) {
-      return sequence <
-        exactly < '(' >,
-        skip_over_scopes <
-          exactly < '(' >,
-          exactly < ')' >
-        >
-      >(src);
-    }
-
-  }
-}
diff --git a/libsass/prelexer.hpp b/libsass/prelexer.hpp
deleted file mode 100644
--- a/libsass/prelexer.hpp
+++ /dev/null
@@ -1,378 +0,0 @@
-#ifndef SASS_PRELEXER_H
-#define SASS_PRELEXER_H
-
-#include <cstring>
-#include "lexer.hpp"
-
-namespace Sass {
-  // using namespace Lexer;
-  namespace Prelexer {
-
-    //####################################
-    // KEYWORD "REGEX" MATCHERS
-    //####################################
-
-    // Match Sass boolean keywords.
-    const char* kwd_true(const char* src);
-    const char* kwd_false(const char* src);
-    const char* kwd_and(const char* src);
-    const char* kwd_or(const char* src);
-    const char* kwd_not(const char* src);
-    const char* kwd_eq(const char* src);
-    const char* kwd_neq(const char* src);
-    const char* kwd_gt(const char* src);
-    const char* kwd_gte(const char* src);
-    const char* kwd_lt(const char* src);
-    const char* kwd_lte(const char* src);
-
-    // Match standard control chars
-    const char* kwd_at(const char* src);
-    const char* kwd_dot(const char* src);
-    const char* kwd_comma(const char* src);
-    const char* kwd_colon(const char* src);
-    const char* kwd_slash(const char* src);
-    const char* kwd_star(const char* src);
-    const char* kwd_plus(const char* src);
-    const char* kwd_minus(const char* src);
-
-    //####################################
-    // SPECIAL "REGEX" CONSTRUCTS
-    //####################################
-
-    // Match a sequence of characters delimited by the supplied chars.
-    template <char beg, char end, bool esc>
-    const char* delimited_by(const char* src) {
-      src = exactly<beg>(src);
-      if (!src) return 0;
-      const char* stop;
-      while (1) {
-        if (!*src) return 0;
-        stop = exactly<end>(src);
-        if (stop && (!esc || *(src - 1) != '\\')) return stop;
-        src = stop ? stop : src + 1;
-      }
-    }
-
-    // skip to delimiter (mx) inside given range
-    // this will savely skip over all quoted strings
-    // recursive skip stuff delimited by start/stop
-    // first start/opener must be consumed already!
-    template<prelexer start, prelexer stop>
-    const char* skip_over_scopes(const char* src, const char* end) {
-
-      size_t level = 0;
-      bool in_squote = false;
-      bool in_dquote = false;
-      // bool in_braces = false;
-
-      while (*src) {
-
-        // check for abort condition
-        if (end && src >= end) break;
-
-        // has escaped sequence?
-        if (*src == '\\') {
-          ++ src; // skip this (and next)
-        }
-        else if (*src == '"') {
-          in_dquote = ! in_dquote;
-        }
-        else if (*src == '\'') {
-          in_squote = ! in_squote;
-        }
-        else if (in_dquote || in_squote) {
-          // take everything literally
-        }
-
-        // find another opener inside?
-        else if (const char* pos = start(src)) {
-          ++ level; // increase counter
-          src = pos - 1; // advance position
-        }
-
-        // look for the closer (maybe final, maybe not)
-        else if (const char* final = stop(src)) {
-          // only close one level?
-          if (level > 0) -- level;
-          // return position at end of stop
-          // delimiter may be multiple chars
-          else return final;
-          // advance position
-          src = final - 1;
-        }
-
-        // next
-        ++ src;
-      }
-
-      return 0;
-    }
-
-    // skip to a skip delimited by parentheses
-    // uses smart `skip_over_scopes` internally
-    const char* parenthese_scope(const char* src);
-
-    // skip to delimiter (mx) inside given range
-    // this will savely skip over all quoted strings
-    // recursive skip stuff delimited by start/stop
-    // first start/opener must be consumed already!
-    template<prelexer start, prelexer stop>
-    const char* skip_over_scopes(const char* src) {
-      return skip_over_scopes<start, stop>(src, 0);
-    }
-
-    // Match a sequence of characters delimited by the supplied chars.
-    template <prelexer start, prelexer stop>
-    const char* recursive_scopes(const char* src) {
-      // parse opener
-      src = start(src);
-      // abort if not found
-      if (!src) return 0;
-      // parse the rest until final closer
-      return skip_over_scopes<start, stop>(src);
-    }
-
-    // Match a sequence of characters delimited by the supplied strings.
-    template <const char* beg, const char* end, bool esc>
-    const char* delimited_by(const char* src) {
-      src = exactly<beg>(src);
-      if (!src) return 0;
-      const char* stop;
-      while (1) {
-        if (!*src) return 0;
-        stop = exactly<end>(src);
-        if (stop && (!esc || *(src - 1) != '\\')) return stop;
-        src = stop ? stop : src + 1;
-      }
-    }
-
-    // Tries to match a certain number of times (between the supplied interval).
-    template<prelexer mx, size_t lo, size_t hi>
-    const char* between(const char* src) {
-      for (size_t i = 0; i < lo; ++i) {
-        src = mx(src);
-        if (!src) return 0;
-      }
-      for (size_t i = lo; i <= hi; ++i) {
-        const char* new_src = mx(src);
-        if (!new_src) return src;
-        src = new_src;
-      }
-      return 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.
-    const char* double_quoted_string(const char* src);
-    const char* single_quoted_string(const char* src);
-    const char* quoted_string(const char* src);
-    // Match interpolants.
-    const char* interpolant(const char* src);
-    // Match number prefix ([\+\-]+)
-    const char* number_prefix(const char* src);
-
-    // Match zero plus white-space or line_comments
-    const char* optional_css_whitespace(const char* src);
-    const char* css_whitespace(const char* src);
-    // Match optional_css_whitepace plus block_comments
-    const char* optional_css_comments(const char* src);
-    const char* css_comments(const char* src);
-
-    // Match one backslash escaped char
-    const char* escape_seq(const char* src);
-
-    // Match CSS css variables.
-    const char* custom_property_name(const char* src);
-    // Match a CSS identifier.
-    const char* identifier(const char* src);
-    const char* identifier_alpha(const char* src);
-    const char* identifier_alnum(const char* src);
-    const char* identifier_alnums(const char* src);
-    // Match selector names.
-    // const char* sel_ident(const char* src);
-    const char* kwd_sel_deep(const char* src);
-
-    // Match interpolant schemas
-    const char* identifier_schema(const char* src);
-    const char* value_schema(const char* src);
-    // const char* filename(const char* src);
-    // const char* filename_schema(const char* src);
-    // const char* url_schema(const char* src);
-    // const char* url_value(const char* src);
-    const char* vendor_prefix(const char* src);
-    // Match CSS '@' keywords.
-    const char* at_keyword(const char* src);
-    const char* kwd_import(const char* src);
-    const char* kwd_at_root(const char* src);
-    const char* kwd_with_directive(const char* src);
-    const char* kwd_without_directive(const char* src);
-    const char* kwd_media(const char* src);
-    const char* kwd_supports(const char* src);
-    // const char* keyframes(const char* src);
-    // const char* keyf(const char* src);
-    const char* kwd_mixin(const char* src);
-    const char* kwd_function(const char* src);
-    const char* kwd_return_directive(const char* src);
-    const char* kwd_include(const char* src);
-    const char* kwd_content(const char* src);
-    const char* kwd_extend(const char* src);
-
-    const char* kwd_if_directive(const char* src);
-    const char* kwd_else_directive(const char* src);
-    const char* elseif_directive(const char* src);
-
-    const char* kwd_for_directive(const char* src);
-    const char* kwd_from(const char* src);
-    const char* kwd_to(const char* src);
-    const char* kwd_through(const char* src);
-
-    const char* kwd_each_directive(const char* src);
-    const char* kwd_in(const char* src);
-
-    const char* kwd_while_directive(const char* src);
-
-    const char* kwd_warn(const char* src);
-    const char* kwd_err(const char* src);
-    const char* kwd_dbg(const char* src);
-
-    const char* kwd_null(const char* src);
-
-    // Match CSS type selectors
-    const char* namespace_prefix(const char* src);
-    const char* type_selector(const char* src);
-    const char* hyphens_and_identifier(const char* src);
-    const char* hyphens_and_name(const char* src);
-    const char* universal(const char* src);
-    // Match CSS id names.
-    const char* id_name(const char* src);
-    // Match CSS class names.
-    const char* class_name(const char* src);
-    // Attribute name in an attribute selector
-    const char* attribute_name(const char* src);
-    // Match placeholder selectors.
-    const char* placeholder(const char* src);
-    // Match CSS numeric constants.
-    const char* sign(const char* src);
-    const char* unsigned_number(const char* src);
-    const char* number(const char* src);
-    const char* coefficient(const char* src);
-    const char* binomial(const char* src);
-    const char* percentage(const char* src);
-    const char* ampersand(const char* src);
-    const char* dimension(const char* src);
-    const char* hex(const char* src);
-    const char* hexa(const char* src);
-    const char* hex0(const char* src);
-    // const char* rgb_prefix(const char* src);
-    // Match CSS uri specifiers.
-    const char* uri_prefix(const char* src);
-    const char* uri_value(const char* src);
-    // Match CSS "!important" keyword.
-    const char* important(const char* src);
-    // Match CSS "!optional" keyword.
-    const char* optional(const char* src);
-    // Match Sass "!default" keyword.
-    const char* default_flag(const char* src);
-    const char* global_flag(const char* src);
-    // Match CSS pseudo-class/element prefixes
-    const char* pseudo_prefix(const char* src);
-    // Match CSS function call openers.
-    const char* functional(const char* src);
-    const char* functional_schema(const char* src);
-    const char* pseudo_not(const char* src);
-    // Match CSS 'odd' and 'even' keywords for functional pseudo-classes.
-    const char* even(const char* src);
-    const char* odd(const char* src);
-    // Match CSS attribute-matching operators.
-    const char* exact_match(const char* src);
-    const char* class_match(const char* src);
-    const char* dash_match(const char* src);
-    const char* prefix_match(const char* src);
-    const char* suffix_match(const char* src);
-    const char* substring_match(const char* src);
-    // Match CSS combinators.
-    // const char* adjacent_to(const char* src);
-    // const char* precedes(const char* src);
-    // const char* parent_of(const char* src);
-    // const char* ancestor_of(const char* src);
-
-    // Match SCSS variable names.
-    const char* variable(const char* src);
-
-    // IE stuff
-    const char* ie_progid(const char* src);
-    const char* ie_expression(const char* src);
-    const char* ie_property(const char* src);
-    const char* ie_keyword_arg(const char* src);
-    const char* ie_keyword_arg_value(const char* src);
-    const char* ie_keyword_arg_property(const char* src);
-
-    // match urls
-    const char* url(const char* src);
-
-    // Path matching functions.
-    // const char* folder(const char* src);
-    // const char* folders(const char* src);
-
-
-    const char* static_string(const char* src);
-    const char* static_component(const char* src);
-    const char* static_value(const char* src);
-
-    // Utility functions for finding and counting characters in a string.
-    template<char c>
-    const char* find_first(const char* src) {
-      while (*src && *src != c) ++src;
-      return *src ? src : 0;
-    }
-    template<prelexer mx>
-    const char* find_first(const char* src) {
-      while (*src && !mx(src)) ++src;
-      return *src ? src : 0;
-    }
-    template<prelexer mx>
-    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 (mx(beg)) return beg;
-        ++beg;
-      }
-      return 0;
-    }
-    template <prelexer mx>
-    unsigned int count_interval(const char* beg, const char* end) {
-      unsigned int counter = 0;
-      bool esc = false;
-      while (beg < end && *beg) {
-        const char* p;
-        if (esc) {
-          esc = false;
-          ++beg;
-        } else if (*beg == '\\') {
-          esc = true;
-          ++beg;
-        } else if ((p = mx(beg))) {
-          ++counter;
-          beg = p;
-        }
-        else {
-          ++beg;
-        }
-      }
-      return counter;
-    }
-
-  }
-}
-
-#endif
diff --git a/libsass/remove_placeholders.cpp b/libsass/remove_placeholders.cpp
deleted file mode 100644
--- a/libsass/remove_placeholders.cpp
+++ /dev/null
@@ -1,59 +0,0 @@
-#include "remove_placeholders.hpp"
-#include "context.hpp"
-#include "inspect.hpp"
-#include "to_string.hpp"
-#include <iostream>
-
-namespace Sass {
-
-    Remove_Placeholders::Remove_Placeholders(Context& ctx)
-    : ctx(ctx)
-    { }
-
-    template<typename T>
-    void Remove_Placeholders::clean_selector_list(T r) {
-
-        // Create a new selector group without placeholders
-        Selector_List* sl = static_cast<Selector_List*>(r->selector());
-
-        if (sl) {
-            Selector_List* new_sl = new (ctx.mem) Selector_List(sl->pstate());
-
-            for (size_t i = 0, L = sl->length(); i < L; ++i) {
-                if (!(*sl)[i]->has_placeholder()) {
-                    *new_sl << (*sl)[i];
-                }
-            }
-
-            // Set the new placeholder selector list
-            r->selector(new_sl);
-        }
-
-        // Iterate into child blocks
-        Block* b = r->block();
-
-        for (size_t i = 0, L = b->length(); i < L; ++i) {
-            Statement* stm = (*b)[i];
-            stm->perform(this);
-        }
-    }
-
-    void Remove_Placeholders::operator()(Block* b) {
-        for (size_t i = 0, L = b->length(); i < L; ++i) {
-            (*b)[i]->perform(this);
-        }
-    }
-
-    void Remove_Placeholders::operator()(Ruleset* r) {
-        clean_selector_list(r);
-    }
-
-    void Remove_Placeholders::operator()(Media_Block* m) {
-        clean_selector_list(m);
-    }
-
-    void Remove_Placeholders::operator()(At_Rule* a) {
-        if (a->block()) a->block()->perform(this);
-    }
-
-}
diff --git a/libsass/remove_placeholders.hpp b/libsass/remove_placeholders.hpp
deleted file mode 100644
--- a/libsass/remove_placeholders.hpp
+++ /dev/null
@@ -1,43 +0,0 @@
-#ifndef SASS_REMOVE_PLACEHOLDERS_H
-#define SASS_REMOVE_PLACEHOLDERS_H
-
-#pragma once
-
-#include <iostream>
-
-#include "ast.hpp"
-#include "operation.hpp"
-
-namespace Sass {
-
-    using namespace std;
-
-    class Context;
-
-    class Remove_Placeholders : public Operation_CRTP<void, Remove_Placeholders> {
-
-        Context&          ctx;
-
-        void fallback_impl(AST_Node* n) {};
-
-    public:
-        Remove_Placeholders(Context&);
-        virtual ~Remove_Placeholders() { }
-
-        using Operation<void>::operator();
-
-        void operator()(Block*);
-        void operator()(Ruleset*);
-        void operator()(Media_Block*);
-        void operator()(At_Rule*);
-
-        template <typename T>
-        void clean_selector_list(T r);
-
-        template <typename U>
-        void fallback(U x) { return fallback_impl(x); }
-    };
-
-}
-
-#endif
diff --git a/libsass/sass.cpp b/libsass/sass.cpp
deleted file mode 100644
--- a/libsass/sass.cpp
+++ /dev/null
@@ -1,43 +0,0 @@
-#include <cstdlib>
-#include <cstring>
-#include <vector>
-#include <sstream>
-
-#include "sass.h"
-#include "file.hpp"
-#include "util.hpp"
-
-extern "C" {
-  using namespace std;
-  using namespace Sass;
-  using namespace File;
-
-  // caller must free the returned memory
-  char* ADDCALL sass_string_quote (const char *str, const char quote_mark)
-  {
-    string quoted = quote(str, quote_mark);
-    return sass_strdup(quoted.c_str());
-  }
-
-  // caller must free the returned memory
-  char* ADDCALL sass_string_unquote (const char *str)
-  {
-    string unquoted = unquote(str);
-    return sass_strdup(unquoted.c_str());
-  }
-
-  // Make sure to free the returned value!
-  // Incs array has to be null terminated!
-  char* ADDCALL sass_resolve_file (const char* file, const char* paths[])
-  {
-    string resolved(find_file(file, paths));
-    return sass_strdup(resolved.c_str());
-  }
-
-  // Get compiled libsass version
-  const char* ADDCALL libsass_version(void)
-  {
-    return LIBSASS_VERSION;
-  }
-
-}
diff --git a/libsass/sass.h b/libsass/sass.h
deleted file mode 100644
--- a/libsass/sass.h
+++ /dev/null
@@ -1,68 +0,0 @@
-#ifndef SASS_H
-#define SASS_H
-
-#include <stddef.h>
-#include <stdbool.h>
-
-#ifdef __GNUC__
-  #define DEPRECATED(func) func __attribute__ ((deprecated))
-#elif defined(_MSC_VER)
-  #define DEPRECATED(func) __declspec(deprecated) func
-#else
-  #pragma message("WARNING: You need to implement DEPRECATED for this compiler")
-  #define DEPRECATED(func) func
-#endif
-
-#ifdef _WIN32
-
-  /* You should define ADD_EXPORTS *only* when building the DLL. */
-  #ifdef ADD_EXPORTS
-    #define ADDAPI __declspec(dllexport)
-	#define ADDCALL __cdecl
-  #else
-    #define ADDAPI
-	#define ADDCALL
-  #endif
-
-#else /* _WIN32 not defined. */
-
-  /* Define with no value on non-Windows OSes. */
-  #define ADDAPI
-  #define ADDCALL
-
-#endif
-
-// include API headers
-#include "sass_version.h"
-#include "sass_values.h"
-#include "sass_functions.h"
-
-/* Make sure functions are exported with C linkage under C++ compilers. */
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-// Different render styles
-enum Sass_Output_Style {
-  SASS_STYLE_NESTED,
-  SASS_STYLE_EXPANDED,
-  SASS_STYLE_COMPACT,
-  SASS_STYLE_COMPRESSED
-};
-
-// 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);
-
-// 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
-ADDAPI const char* ADDCALL libsass_version(void);
-
-#ifdef __cplusplus
-} // __cplusplus defined.
-#endif
-
-#endif
diff --git a/libsass/sass2scss.cpp b/libsass/sass2scss.cpp
deleted file mode 100644
--- a/libsass/sass2scss.cpp
+++ /dev/null
@@ -1,835 +0,0 @@
-// include library
-#include <stack>
-#include <string>
-#include <cstring>
-#include <cstdlib>
-#include <sstream>
-#include <iostream>
-#include <stdio.h>
-
-///*
-//
-// src comments: comments in sass syntax (staring with //)
-// css comments: multiline comments in css syntax (starting with /*)
-//
-// KEEP_COMMENT: keep src comments in the resulting css code
-// STRIP_COMMENT: strip out all comments (either src or css)
-// CONVERT_COMMENT: convert all src comments to css comments
-//
-//*/
-
-// our own header
-#include "sass2scss.h"
-
-// using std::string
-using namespace std;
-
-// add namespace for c++
-namespace Sass
-{
-
-	// return the actual prettify value from options
-	#define PRETTIFY(converter) (converter.options - (converter.options & 248))
-	// query the options integer to check if the option is enables
-	#define KEEP_COMMENT(converter) ((converter.options & SASS2SCSS_KEEP_COMMENT) == SASS2SCSS_KEEP_COMMENT)
-	#define STRIP_COMMENT(converter) ((converter.options & SASS2SCSS_STRIP_COMMENT) == SASS2SCSS_STRIP_COMMENT)
-	#define CONVERT_COMMENT(converter) ((converter.options & SASS2SCSS_CONVERT_COMMENT) == SASS2SCSS_CONVERT_COMMENT)
-
-	// some makros to access the indentation stack
-	#define INDENT(converter) (converter.indents.top())
-
-	// some makros to query comment parser status
-	#define IS_PARSING(converter) (converter.comment == "")
-	#define IS_COMMENT(converter) (converter.comment != "")
-	#define IS_SRC_COMMENT(converter) (converter.comment == "//" && ! CONVERT_COMMENT(converter))
-	#define IS_CSS_COMMENT(converter) (converter.comment == "/*" || (converter.comment == "//" && CONVERT_COMMENT(converter)))
-
-	// pretty printer helper function
-	static string closer (const converter& converter)
-	{
-		return PRETTIFY(converter) == 0 ? " }" :
-		     PRETTIFY(converter) <= 1 ? " }" :
-		       "\n" + INDENT(converter) + "}";
-	}
-
-	// pretty printer helper function
-	static string opener (const converter& converter)
-	{
-		return PRETTIFY(converter) == 0 ? " { " :
-		     PRETTIFY(converter) <= 2 ? " {" :
-		       "\n" + INDENT(converter) + "{";
-	}
-
-	// check if the given string is a pseudo selector
-	// needed to differentiate from sass property syntax
-	static bool isPseudoSelector (string& sel)
-	{
-
-		size_t len = sel.length();
-		if (len < 1) return false;
-		size_t pos = sel.find_first_not_of("abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ", 1);
-		if (pos != string::npos) sel.erase(pos, string::npos);
-		size_t i = sel.length();
-		while (i -- > 0) { sel.at(i) = tolower(sel.at(i)); }
-
-		// CSS Level 1 - Recommendation
-		if (sel == ":link") return true;
-		if (sel == ":visited") return true;
-		if (sel == ":active") return true;
-
-		// CSS Level 2 (Revision 1) - Recommendation
-		if (sel == ":lang") return true;
-		if (sel == ":first-child") return true;
-		if (sel == ":hover") return true;
-		if (sel == ":focus") return true;
-		// disabled - also valid properties
-		// if (sel == ":left") return true;
-		// if (sel == ":right") return true;
-		if (sel == ":first") return true;
-
-		// Selectors Level 3 - Recommendation
-		if (sel == ":target") return true;
-		if (sel == ":root") return true;
-		if (sel == ":nth-child") return true;
-		if (sel == ":nth-last-of-child") return true;
-		if (sel == ":nth-of-type") return true;
-		if (sel == ":nth-last-of-type") return true;
-		if (sel == ":last-child") return true;
-		if (sel == ":first-of-type") return true;
-		if (sel == ":last-of-type") return true;
-		if (sel == ":only-child") return true;
-		if (sel == ":only-of-type") return true;
-		if (sel == ":empty") return true;
-		if (sel == ":not") return true;
-
-		// CSS Basic User Interface Module Level 3 - Working Draft
-		if (sel == ":default") return true;
-		if (sel == ":valid") return true;
-		if (sel == ":invalid") return true;
-		if (sel == ":in-range") return true;
-		if (sel == ":out-of-range") return true;
-		if (sel == ":required") return true;
-		if (sel == ":optional") return true;
-		if (sel == ":read-only") return true;
-		if (sel == ":read-write") return true;
-		if (sel == ":dir") return true;
-		if (sel == ":enabled") return true;
-		if (sel == ":disabled") return true;
-		if (sel == ":checked") return true;
-		if (sel == ":indeterminate") return true;
-		if (sel == ":nth-last-child") return true;
-
-		// Selectors Level 4 - Working Draft
-		if (sel == ":any-link") return true;
-		if (sel == ":local-link") return true;
-		if (sel == ":scope") return true;
-		if (sel == ":active-drop-target") return true;
-		if (sel == ":valid-drop-target") return true;
-		if (sel == ":invalid-drop-target") return true;
-		if (sel == ":current") return true;
-		if (sel == ":past") return true;
-		if (sel == ":future") return true;
-		if (sel == ":placeholder-shown") return true;
-		if (sel == ":user-error") return true;
-		if (sel == ":blank") return true;
-		if (sel == ":nth-match") return true;
-		if (sel == ":nth-last-match") return true;
-		if (sel == ":nth-column") return true;
-		if (sel == ":nth-last-column") return true;
-		if (sel == ":matches") return true;
-
-		// Fullscreen API - Living Standard
-		if (sel == ":fullscreen") return true;
-
-		// not a pseudo selector
-		return false;
-
-	}
-
-	// check if there is some char data
-	// will ignore everything in comments
-	static bool hasCharData (string& sass)
-	{
-
-		size_t col_pos = 0;
-
-		while (true)
-		{
-
-			// try to find some meaningfull char
-			col_pos = sass.find_first_not_of(" \t\n\v\f\r", col_pos);
-
-			// there was no meaningfull char found
-			if (col_pos == string::npos) return false;
-
-			// found a multiline comment opener
-			if (sass.substr(col_pos, 2) == "/*")
-			{
-				// find the multiline comment closer
-				col_pos = sass.find("*/", col_pos);
-				// maybe we did not find the closer here
-				if (col_pos == string::npos) return false;
-				// skip closer
-				col_pos += 2;
-			}
-			else
-			{
-				return true;
-			}
-
-		}
-
-	}
-	// EO hasCharData
-
-	// find src comment opener
-	// correctly skips quoted strings
-	static size_t findCommentOpener (string& sass)
-	{
-
-		size_t col_pos = 0;
-		bool apoed = false;
-		bool quoted = false;
-		bool comment = false;
-		size_t brackets = 0;
-
-		while (col_pos != string::npos)
-		{
-
-			// process all interesting chars
-			col_pos = sass.find_first_of("\"\'/\\*()", col_pos);
-
-			// assertion for valid result
-			if (col_pos != string::npos)
-			{
-				char character = sass.at(col_pos);
-
-				if (character == '(')
-				{
-					if (!quoted && !apoed) brackets ++;
-				}
-				else if (character == ')')
-				{
-					if (!quoted && !apoed) brackets --;
-				}
-				else if (character == '\"')
-				{
-					// invert quote bool
-					if (!apoed && !comment) quoted = !quoted;
-				}
-				else if (character == '\'')
-				{
-					// invert quote bool
-					if (!quoted && !comment) apoed = !apoed;
-				}
-				else if (col_pos > 0 && character == '/')
-				{
-					if (sass.at(col_pos - 1) == '*')
-					{
-						comment = false;
-					}
-					// next needs to be a slash too
-					else if (sass.at(col_pos - 1) == '/')
-					{
-						// only found if not in single or double quote, bracket or comment
-						if (!quoted && !apoed && !comment && brackets == 0) return col_pos - 1;
-					}
-				}
-				else if (character == '\\')
-				{
-					// skip next char if in quote
-					if (quoted || apoed) col_pos ++;
-				}
-				// this might be a comment opener
-				else if (col_pos > 0 && character == '*')
-				{
-					// opening a multiline comment
-					if (sass.at(col_pos - 1) == '/')
-					{
-						// we are now in a comment
-						if (!quoted && !apoed) comment = true;
-					}
-				}
-
-				// skip char
-				col_pos ++;
-
-			}
-
-		}
-		// EO while
-
-		return col_pos;
-
-	}
-	// EO findCommentOpener
-
-	// remove multiline comments from sass string
-	// correctly skips quoted strings
-	static string removeMultilineComment (string &sass)
-	{
-
-		string clean = "";
-		size_t col_pos = 0;
-		size_t open_pos = 0;
-		size_t close_pos = 0;
-		bool apoed = false;
-		bool quoted = false;
-		bool comment = false;
-
-		// process sass til string end
-		while (col_pos != string::npos)
-		{
-
-			// process all interesting chars
-			col_pos = sass.find_first_of("\"\'/\\*", col_pos);
-
-			// assertion for valid result
-			if (col_pos != string::npos)
-			{
-				char character = sass.at(col_pos);
-
-				// found quoted string delimiter
-				if (character == '\"')
-				{
-					if (!apoed && !comment) quoted = !quoted;
-				}
-				else if (character == '\'')
-				{
-					if (!quoted && !comment) apoed = !apoed;
-				}
-				// found possible comment closer
-				else if (character == '/')
-				{
-					// look back to see if it is actually a closer
-					if (comment && col_pos > 0 && sass.at(col_pos - 1) == '*')
-					{
-						close_pos = col_pos + 1; comment = false;
-					}
-				}
-				else if (character == '\\')
-				{
-					// skip escaped char
-					if (quoted || apoed) col_pos ++;
-				}
-				// this might be a comment opener
-				else if (character == '*')
-				{
-					// look back to see if it is actually an opener
-					if (!quoted && !apoed && col_pos > 0 && sass.at(col_pos - 1) == '/')
-					{
-						comment = true; open_pos = col_pos - 1;
-						clean += sass.substr(close_pos, open_pos - close_pos);
-					}
-				}
-
-				// skip char
-				col_pos ++;
-
-			}
-
-		}
-		// EO while
-
-		// add final parts (add half open comment text)
-		if (comment) clean += sass.substr(open_pos);
-		else clean += sass.substr(close_pos);
-
-		// return string
-		return clean;
-
-	}
-	// EO removeMultilineComment
-
-	// right trim a given string
-	string rtrim(const string &sass)
-	{
-		string trimmed = sass;
-		size_t pos_ws = trimmed.find_last_not_of(" \t\n\v\f\r");
-		if (pos_ws != string::npos)
-		{ trimmed.erase(pos_ws + 1); }
-		else { trimmed.clear(); }
-		return trimmed;
-	}
-	// EO rtrim
-
-	// flush whitespace and print additional text, but
-	// only print additional chars and buffer whitespace
-	string flush (string& sass, converter& converter)
-	{
-
-		// return flushed
-		string scss = "";
-
-		// print whitespace buffer
-		scss += PRETTIFY(converter) > 0 ?
-		        converter.whitespace : "";
-		// reset whitespace buffer
-		converter.whitespace = "";
-
-		// remove possible newlines from string
-		size_t pos_right = sass.find_last_not_of("\n\r");
-		if (pos_right == string::npos) return scss;
-
-		// get the linefeeds from the string
-		string lfs = sass.substr(pos_right + 1);
-		sass = sass.substr(0, pos_right + 1);
-
-		// find some source comment opener
-		size_t comment_pos = findCommentOpener(sass);
-		// check if there was a source comment
-		if (comment_pos != string::npos)
-		{
-			// convert comment (but only outside other coments)
-			if (CONVERT_COMMENT(converter) && !IS_COMMENT(converter))
-			{
-				// convert to multiline comment
-				sass.at(comment_pos + 1) = '*';
-				// add comment node to the whitespace
-				sass += " */";
-			}
-			// not at line start
-			if (comment_pos > 0)
-			{
-				// also include whitespace before the actual comment opener
-				size_t ws_pos = sass.find_last_not_of(SASS2SCSS_FIND_WHITESPACE, comment_pos - 1);
-				comment_pos = ws_pos == string::npos ? 0 : ws_pos + 1;
-			}
-			if (!STRIP_COMMENT(converter))
-			{
-				// add comment node to the whitespace
-				converter.whitespace += sass.substr(comment_pos);
-			}
-			else
-			{
-				// sass = removeMultilineComments(sass);
-			}
-			// update the actual sass code
-			sass = sass.substr(0, comment_pos);
-		}
-
-		// add newline as getline discharged it
-		converter.whitespace += lfs + "\n";
-
-		// maybe remove any leading whitespace
-		if (PRETTIFY(converter) == 0)
-		{
-			// remove leading whitespace and update string
-			size_t pos_left = sass.find_first_not_of(SASS2SCSS_FIND_WHITESPACE);
-			if (pos_left != string::npos) sass = sass.substr(pos_left);
-		}
-
-		// add flushed data
-		scss += sass;
-
-		// return string
-		return scss;
-
-	}
-	// EO flush
-
-	// process a line of the sass text
-	string process (string& sass, converter& converter)
-	{
-
-		// resulting string
-		string scss = "";
-
-		// strip multi line comments
-		if (STRIP_COMMENT(converter))
-		{
-			sass = removeMultilineComment(sass);
-		}
-
-		// right trim input
-		sass = rtrim(sass);
-
-		// get postion of first meaningfull character in string
-		size_t pos_left = sass.find_first_not_of(SASS2SCSS_FIND_WHITESPACE);
-
-		// special case for final run
-		if (converter.end_of_file) pos_left = 0;
-
-		// maybe has only whitespace
-		if (pos_left == string::npos)
-		{
-			// just add complete whitespace
-			converter.whitespace += sass + "\n";
-		}
-		// have meaningfull first char
-		else
-		{
-
-			// extract and store indentation string
-			string indent = sass.substr(0, pos_left);
-
-			// check if current line starts a comment
-			string open = sass.substr(pos_left, 2);
-
-			// line has less or same indentation
-			// finalize previous open parser context
-			if (indent.length() <= INDENT(converter).length())
-			{
-
-				// close multilinie comment
-				if (IS_CSS_COMMENT(converter))
-				{
-					// check if comments will be stripped anyway
-					if (!STRIP_COMMENT(converter)) scss += " */";
-				}
-				// close src comment comment
-				else if (IS_SRC_COMMENT(converter))
-				{
-					// add a newline to avoid closer on same line
-					// this would put the bracket in the comment node
-					// no longer needed since we parse them correctly
-					// if (KEEP_COMMENT(converter)) scss += "\n";
-				}
-				// close css properties
-				else if (converter.property)
-				{
-					// add closer unless in concat mode
-					if (!converter.comma)
-					{
-						// if there was no colon we have a selector
-						// looks like there were no inner properties
-						if (converter.selector) scss += " {}";
-						// add final semicolon
-						else if (!converter.semicolon) scss += ";";
-					}
-				}
-
-				// reset comment state
-				converter.comment = "";
-
-			}
-
-			// make sure we close every "higher" block
-			while (indent.length() < INDENT(converter).length())
-			{
-				// pop stacked context
-				converter.indents.pop();
-				// print close bracket
-				if (IS_PARSING(converter))
-				{ scss += closer(converter); }
-				else { scss += " */"; }
-				// reset comment state
-				converter.comment = "";
-			}
-
-			// reset converter state
-			converter.selector = false;
-
-			// check if we have sass property syntax
-			if (sass.substr(pos_left, 1) == ":" && sass.substr(pos_left, 2) != "::")
-			{
-
-				// default to a selector
-				// change back if property found
-				converter.selector = true;
-				// get postion of first whitespace char
-				size_t pos_wspace = sass.find_first_of(SASS2SCSS_FIND_WHITESPACE, pos_left);
-				// assertion check for valid result
-				if (pos_wspace != string::npos)
-				{
-					// get the possible pseudo selector
-					string pseudo = sass.substr(pos_left, pos_wspace - pos_left);
-					// get position of the first real property value char
-					// pseudo selectors get this far, but have no actual value
-					size_t pos_value =  sass.find_first_not_of(SASS2SCSS_FIND_WHITESPACE, pos_wspace);
-					// assertion check for valid result
-					if (pos_value != string::npos)
-					{
-						// only process if not (fallowed by a semicolon or is a pseudo selector)
-						if (!(sass.at(pos_value) == ':' || isPseudoSelector(pseudo)))
-						{
-							// create new string by interchanging the colon sign for property and value
-							sass = indent + sass.substr(pos_left + 1, pos_wspace - pos_left - 1) + ":" + sass.substr(pos_wspace);
-							// try to find a colon in the current line, but only ...
-							size_t pos_colon = sass.find_first_not_of(":", pos_left);
-							// assertion for valid result
-							if (pos_colon != string::npos)
-							{
-								// ... after the first word (skip begining colons)
-								pos_colon = sass.find_first_of(":", pos_colon);
-								// it is a selector if there was no colon found
-								converter.selector = pos_colon == string::npos;
-							}
-						}
-					}
-				}
-
-			}
-
-			// terminate some statements immediately
-			else if (
-				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 = 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)
-			{ 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); }
-
-			// add quotes for import if needed
-			else if (sass.substr(pos_left, 7) == "@import")
-			{
-				// get positions for the actual import url
-				size_t pos_import = sass.find_first_of(SASS2SCSS_FIND_WHITESPACE, pos_left + 7);
-				size_t pos_quote = sass.find_first_not_of(SASS2SCSS_FIND_WHITESPACE, pos_import);
-				// leave proper urls untouched
-				if (sass.substr(pos_quote, 4) != "url(")
-				{
-					// check if the url appears to be already quoted
-					if (sass.substr(pos_quote, 1) != "\"" && sass.substr(pos_quote, 1) != "\'")
-					{
-						// get position of the last char on the line
-						size_t pos_end = sass.find_last_not_of(SASS2SCSS_FIND_WHITESPACE);
-						// assertion check for valid result
-						if (pos_end != string::npos)
-						{
-							// add quotes around the full line after the import statement
-							sass = sass.substr(0, pos_quote) + "\"" + sass.substr(pos_quote, pos_end - pos_quote + 1) + "\"";
-						}
-					}
-				}
-
-			}
-			else if (
-				sass.substr(pos_left, 7) != "@return" &&
-				sass.substr(pos_left, 7) != "@extend" &&
-				sass.substr(pos_left, 8) != "@content"
-			) {
-
-				// try to find a colon in the current line, but only ...
-				size_t pos_colon = sass.find_first_not_of(":", pos_left);
-				// assertion for valid result
-				if (pos_colon != string::npos)
-				{
-					// ... after the first word (skip begining colons)
-					pos_colon = sass.find_first_of(":", pos_colon);
-					// it is a selector if there was no colon found
-					converter.selector = pos_colon == string::npos;
-				}
-
-			}
-
-			// current line has more indentation
-			if (indent.length() >= INDENT(converter).length())
-			{
-				// not in comment mode
-				if (IS_PARSING(converter))
-				{
-					// has meaningfull chars
-					if (hasCharData(sass))
-					{
-						// is probably a property
-						// also true for selectors
-						converter.property = true;
-					}
-				}
-			}
-			// current line has more indentation
-			if (indent.length() > INDENT(converter).length())
-			{
-				// not in comment mode
-				if (IS_PARSING(converter))
-				{
-					// had meaningfull chars
-					if (converter.property)
-					{
-						// print block opener
-						scss += opener(converter);
-						// push new stack context
-						converter.indents.push("");
-						// store block indentation
-						INDENT(converter) = indent;
-					}
-				}
-				// is and will be a src comment
-				else if (!IS_CSS_COMMENT(converter))
-				{
-					// scss does not allow multiline src comments
-					// therefore add forward slashes to all lines
-					sass.at(INDENT(converter).length()+0) = '/';
-					// there is an edge case here if indentation
-					// is minimal (will overwrite the fist char)
-					sass.at(INDENT(converter).length()+1) = '/';
-					// could code around that, but I dont' think
-					// this will ever be the cause for any trouble
-				}
-			}
-
-			// line is opening a new comment
-			if (open == "/*" || open == "//")
-			{
-				// reset the property state
-				converter.property = false;
-				// close previous comment
-				if (IS_CSS_COMMENT(converter) && open != "")
-				{
-					if (!STRIP_COMMENT(converter) && !CONVERT_COMMENT(converter)) scss += " */";
-				}
-				// force single line comments
-				// into a correct css comment
-				if (CONVERT_COMMENT(converter))
-				{
-					if (IS_PARSING(converter))
-					{ sass.at(pos_left + 1) = '*'; }
-				}
-				// set comment flag
-				converter.comment = open;
-
-			}
-
-			// flush data only under certain conditions
-			if (!(
-				// strip css and src comments if option is set
-				(IS_COMMENT(converter) && STRIP_COMMENT(converter)) ||
-				// strip src comment even if strip option is not set
-				// but only if the keep src comment option is not set
-				(IS_SRC_COMMENT(converter) && ! KEEP_COMMENT(converter))
-			))
-			{
-				// flush data and buffer whitespace
-				scss += flush(sass, converter);
-			}
-
-			// get postion of last meaningfull char
-			size_t pos_right = sass.find_last_not_of(SASS2SCSS_FIND_WHITESPACE);
-
-			// check for invalid result
-			if (pos_right != string::npos)
-			{
-
-				// get the last meaningfull char
-				string close = sass.substr(pos_right, 1);
-
-				// check if next line should be concatenated (list mode)
-				converter.comma = IS_PARSING(converter) && close == ",";
-				converter.semicolon = IS_PARSING(converter) && close == ";";
-
-				// check if we have more than
-				// one meaningfull char
-				if (pos_right > 0)
-				{
-
-					// get the last two chars from string
-					string close = sass.substr(pos_right - 1, 2);
-					// update parser status for expicitly closed comment
-					if (close == "*/") converter.comment = "";
-
-				}
-
-			}
-			// EO have meaningfull chars from end
-
-		}
-		// EO have meaningfull chars from start
-
-		// return scss
-		return scss;
-
-	}
-	// EO process
-
-	// read line with either CR, LF or CR LF format
-	// http://stackoverflow.com/a/6089413/1550314
-	static std::istream& safeGetline(std::istream& is, std::string& t)
-	{
-		t.clear();
-
-		// The characters in the stream are read one-by-one using a std::streambuf.
-		// That is faster than reading them one-by-one using the std::istream.
-		// Code that uses streambuf this way must be guarded by a sentry object.
-		// The sentry object performs various tasks,
-		// such as thread synchronization and updating the stream state.
-
-		std::istream::sentry se(is, true);
-		std::streambuf* sb = is.rdbuf();
-
-		for(;;) {
-			int c = sb->sbumpc();
-			switch (c) {
-				case '\n':
-					return is;
-				case '\r':
-					if(sb->sgetc() == '\n')
-						sb->sbumpc();
-					return is;
-				case EOF:
-					// Also handle the case when the last line has no line ending
-					if(t.empty())
-						is.setstate(std::ios::eofbit);
-					return is;
-				default:
-					t += (char)c;
-			}
-		}
-	}
-
-	// the main converter function for c++
-	char* sass2scss (const string sass, const int options)
-	{
-
-		// local variables
-		string line;
-		string scss = "";
-		stringstream stream(sass);
-
-		// create converter variable
-		converter converter;
-		// initialise all options
-		converter.comma = false;
-		converter.property = false;
-		converter.selector = false;
-		converter.semicolon = false;
-		converter.end_of_file = false;
-		converter.comment = "";
-		converter.whitespace = "";
-		converter.indents.push("");
-		converter.options = options;
-
-		// read line by line and process them
-		while(safeGetline(stream, line) && !stream.eof())
-		{ scss += process(line, converter); }
-
-		// create mutable string
-		string closer = "";
-		// set the end of file flag
-		converter.end_of_file = true;
-		// process to close all open blocks
-		scss += process(closer, converter);
-
-		// allocate new memory on the heap
-		// caller has to free it after use
-		char * cstr = (char*) malloc (scss.length() + 1);
-		// create a copy of the string
-		strcpy (cstr, scss.c_str());
-		// return pointer
-		return &cstr[0];
-
-	}
-	// EO sass2scss
-
-}
-// EO namespace
-
-// implement for c
-extern "C"
-{
-
-	char* ADDCALL sass2scss (const char* sass, const int options)
-	{
-		return Sass::sass2scss(sass, options);
-	}
-
-	// Get compiled sass2scss version
-	const char* ADDCALL sass2scss_version(void) {
-		return SASS2SCSS_VERSION;
-	}
-
-}
diff --git a/libsass/sass2scss.h b/libsass/sass2scss.h
deleted file mode 100644
--- a/libsass/sass2scss.h
+++ /dev/null
@@ -1,115 +0,0 @@
-#ifndef SASS2SCSS_H
-#define SASS2SCSS_H
-
-#ifdef _WIN32
-
-  /* You should define ADD_EXPORTS *only* when building the DLL. */
-  #ifdef ADD_EXPORTS
-    #define ADDAPI __declspec(dllexport)
-	#define ADDCALL __cdecl
-  #else
-    #define ADDAPI
-	#define ADDCALL
-  #endif
-
-#else /* _WIN32 not defined. */
-
-  /* Define with no value on non-Windows OSes. */
-  #define ADDAPI
-  #define ADDCALL
-
-#endif
-
-#ifdef __cplusplus
-
-#include <stack>
-#include <string>
-#include <cstring>
-#include <sstream>
-#include <iostream>
-
-#ifndef SASS2SCSS_VERSION
-#define SASS2SCSS_VERSION "1.0.3"
-#endif
-
-// using std::string
-using namespace std;
-
-// add namespace for c++
-namespace Sass
-{
-
-	// pretty print options
-	const int SASS2SCSS_PRETTIFY_0 = 0;
-	const int SASS2SCSS_PRETTIFY_1 = 1;
-	const int SASS2SCSS_PRETTIFY_2 = 2;
-	const int SASS2SCSS_PRETTIFY_3 = 3;
-
-	// remove one-line comment
-	const int SASS2SCSS_KEEP_COMMENT    =  32;
-	// remove multi-line comments
-	const int SASS2SCSS_STRIP_COMMENT   =  64;
-	// convert one-line to multi-line
-	const int SASS2SCSS_CONVERT_COMMENT = 128;
-
-	// String for finding something interesting
-	const string SASS2SCSS_FIND_WHITESPACE = " \t\n\v\f\r";
-
-	// converter struct
-	// holding all states
-	struct converter
-	{
-		// bit options
-		int options;
-		// is selector
-		bool selector;
-		// concat lists
-		bool comma;
-		// has property
-		bool property;
-		// has semicolon
-		bool semicolon;
-		// comment context
-		string comment;
-		// flag end of file
-		bool end_of_file;
-		// whitespace buffer
-		string whitespace;
-		// context/block stack
-		stack<string> indents;
-	};
-
-	// function only available in c++ code
-	char* sass2scss (const string sass, const int options);
-
-}
-// EO namespace
-
-// declare for c
-extern "C" {
-#endif
-
-	// prettyfy print options
-	#define SASS2SCSS_PRETTIFY_0   0
-	#define SASS2SCSS_PRETTIFY_1   1
-	#define SASS2SCSS_PRETTIFY_2   2
-	#define SASS2SCSS_PRETTIFY_3   3
-
-	// keep one-line comments
-	#define SASS2SCSS_KEEP_COMMENT     32
-	// remove multi-line comments
-	#define SASS2SCSS_STRIP_COMMENT    64
-	// convert one-line to multi-line
-	#define SASS2SCSS_CONVERT_COMMENT  128
-
-	// available to c and c++ code
-	ADDAPI char* ADDCALL sass2scss (const char* sass, const int options);
-
-	// Get compiled sass2scss version
-	ADDAPI const char* ADDCALL sass2scss_version(void);
-
-#ifdef __cplusplus
-} // __cplusplus defined.
-#endif
-
-#endif
diff --git a/libsass/sass_context.cpp b/libsass/sass_context.cpp
deleted file mode 100644
--- a/libsass/sass_context.cpp
+++ /dev/null
@@ -1,894 +0,0 @@
-#ifdef _WIN32
-#include <io.h>
-#define LFEED "\n"
-#else
-#include <unistd.h>
-#define LFEED "\n"
-#endif
-
-#include <cstring>
-#include <stdexcept>
-#include "file.hpp"
-#include "json.hpp"
-#include "util.hpp"
-#include "context.hpp"
-#include "sass_values.h"
-#include "sass_context.h"
-#include "ast_fwd_decl.hpp"
-#include "error_handling.hpp"
-
-extern "C" {
-  using namespace std;
-  using namespace Sass;
-
-  // 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;
-
-    // embed sourceMappingUrl as data uri
-    bool source_map_embed;
-
-    // embed include contents in maps
-    bool source_map_contents;
-
-    // Disable sourceMappingUrl in css output
-    bool omit_source_map_url;
-
-    // Treat source_string as sass (as opposed to scss)
-    bool is_indented_syntax_src;
-
-    // The input path is used for source map
-    // generation. It can be used to define
-    // something with string compilation or to
-    // overload the input file path. It is
-    // set to "stdin" for data contexts and
-    // to the input file on file contexts.
-    char* input_path;
-
-    // The output path is used for source map
-    // generation. Libsass will not write to
-    // this file, it is just used to create
-    // 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?
-    char* include_path;
-    char* plugin_path;
-
-    // Include paths (linked string list)
-    struct string_list* include_paths;
-    // Plugin paths (linked string list)
-    struct string_list* plugin_paths;
-
-    // Path to source map file
-    // Enables source map generation
-    // Used to create sourceMappingUrl
-    char* source_map_file;
-
-    // Directly inserted in source maps
-    char* source_map_root;
-
-    // Custom functions that can be called from sccs code
-    Sass_Function_List c_functions;
-
-    // List of custom importers
-    Sass_Importer_List c_importers;
-
-    // List of custom headers
-    Sass_Importer_List c_headers;
-
-  };
-
-  // base for all contexts
-  struct Sass_Context : Sass_Options
-  {
-
-    // store context type info
-    enum Sass_Input_Style type;
-
-    // generated output data
-    char* output_string;
-
-    // generated source map json
-    char* source_map_string;
-
-    // error status
-    int error_status;
-    char* error_json;
-    char* error_text;
-    char* error_message;
-    // error position
-    char* error_file;
-    size_t error_line;
-    size_t error_column;
-    const char* error_src;
-
-    // report imported files
-    char** included_files;
-
-  };
-
-  // struct for file compilation
-  struct Sass_File_Context : Sass_Context {
-
-    // no additional fields required
-    // input_path is already on options
-
-  };
-
-  // struct for data compilation
-  struct Sass_Data_Context : Sass_Context {
-
-    // provided source string
-    char* source_string;
-
-  };
-
-  // link c and cpp context
-  struct Sass_Compiler {
-    // progress status
-    Sass_Compiler_State state;
-    // original c context
-    Sass_Context* c_ctx;
-    // Sass::Context
-    Context* cpp_ctx;
-    // Sass::Block
-    Block* root;
-  };
-
-  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) \
-    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) \
-    { free(options->option); options->option = option ? sass_strdup(option) : 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; }
-
-  // helper for safe access to c_ctx
-  static const char* safe_str (const char* str) {
-    return str == NULL ? "" : str;
-  }
-
-  static void copy_strings(const std::vector<std::string>& strings, char*** array) {
-    int num = static_cast<int>(strings.size());
-    char** arr = (char**) malloc(sizeof(char*) * (num + 1));
-    if (arr == 0) throw(bad_alloc());
-
-    for(int i = 0; i < num; i++) {
-      arr[i] = (char*) malloc(sizeof(char) * (strings[i].size() + 1));
-      if (arr[i] == 0) throw(bad_alloc());
-      std::copy(strings[i].begin(), strings[i].end(), arr[i]);
-      arr[i][strings[i].size()] = '\0';
-    }
-
-    arr[num] = 0;
-    *array = arr;
-  }
-
-  static void free_string_array(char ** arr) {
-    if(!arr)
-        return;
-
-    char **it = arr;
-    while (it && (*it)) {
-      free(*it);
-      ++it;
-    }
-
-    free(arr);
-  }
-
-  static int handle_errors(Sass_Context* c_ctx) {
-    try {
-     throw;
-    }
-    catch (Sass_Error& e) {
-      stringstream msg_stream;
-      string cwd(Sass::File::get_cwd());
-      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.c_str()));
-      json_append_member(json_err, "line", json_mknumber(e.pstate.line+1));
-      json_append_member(json_err, "column", json_mknumber(e.pstate.column+1));
-      json_append_member(json_err, "message", json_mkstring(e.message.c_str()));
-      string rel_path(Sass::File::resolve_relative_path(e.pstate.path, cwd, cwd));
-
-      string msg_prefix("Error: ");
-      bool got_newline = false;
-      msg_stream << msg_prefix;
-      for (char chr : e.message) {
-        if (chr == '\n') {
-          got_newline = true;
-        } else if (got_newline) {
-          msg_stream << string(msg_prefix.size(), ' ');
-          got_newline = false;
-        }
-        msg_stream << chr;
-      }
-      if (!got_newline) msg_stream << "\n";
-      msg_stream << string(msg_prefix.size(), ' ');
-      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 != string::npos && e.pstate.column != 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;
-        }
-        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 ++;
-        }
-        size_t max_left = 42; size_t max_right = 78;
-        size_t move_in = e.pstate.column > max_left ? e.pstate.column - max_left : 0;
-        size_t shorten = (line_end - line_beg) - move_in > max_right ?
-                         (line_end - line_beg) - move_in - max_right : 0;
-        msg_stream << ">> " << string(line_beg + move_in, line_end - shorten) << "\n";
-        msg_stream << "   " << string(e.pstate.column - move_in, '-') << "^\n";
-      }
-
-      c_ctx->error_json = json_stringify(json_err, "  ");;
-      c_ctx->error_message = sass_strdup(msg_stream.str().c_str());
-      c_ctx->error_text = strdup(e.message.c_str());
-      c_ctx->error_status = 1;
-      c_ctx->error_file = sass_strdup(e.pstate.path.c_str());
-      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;
-      json_delete(json_err);
-    }
-    catch(bad_alloc& ba) {
-      stringstream msg_stream;
-      JsonNode* json_err = json_mkobject();
-      msg_stream << "Unable to allocate memory: " << ba.what() << 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 = strdup(ba.what());
-      c_ctx->error_status = 2;
-      c_ctx->output_string = 0;
-      c_ctx->source_map_string = 0;
-      json_delete(json_err);
-    }
-    catch (std::exception& e) {
-      stringstream msg_stream;
-      JsonNode* json_err = json_mkobject();
-      msg_stream << "Error: " << e.what() << 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 = strdup(e.what());
-      c_ctx->error_status = 3;
-      c_ctx->output_string = 0;
-      c_ctx->source_map_string = 0;
-      json_delete(json_err);
-    }
-    catch (string& e) {
-      stringstream msg_stream;
-      JsonNode* json_err = json_mkobject();
-      msg_stream << "Error: " << e << 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 = strdup(e.c_str());
-      c_ctx->error_status = 4;
-      c_ctx->output_string = 0;
-      c_ctx->source_map_string = 0;
-      json_delete(json_err);
-    }
-    catch (...) {
-      stringstream msg_stream;
-      JsonNode* json_err = json_mkobject();
-      msg_stream << "Unknown error occurred" << 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 = strdup("unknown");
-      c_ctx->error_status = 5;
-      c_ctx->output_string = 0;
-      c_ctx->source_map_string = 0;
-      json_delete(json_err);
-    }
-    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::Data cpp_opt) throw()
-  {
-    try {
-
-      // get input/output path from options
-      string input_path = safe_str(c_ctx->input_path);
-      string output_path = safe_str(c_ctx->output_path);
-      // maybe we can extract an output path from input path
-      if (output_path == "" && input_path != "") {
-        int lastindex = static_cast<int>(input_path.find_last_of("."));
-        output_path = (lastindex > -1 ? input_path.substr(0, lastindex) : input_path) + ".css";
-      }
-
-      // 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(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;
-      }
-
-      // 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(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;
-      }
-
-      // transfer the options to c++
-      cpp_opt.c_compiler(0)
-             .c_options(c_ctx)
-             .input_path(input_path)
-             .output_path(output_path)
-             .output_style((Output_Style) c_ctx->output_style)
-             .is_indented_syntax_src(c_ctx->is_indented_syntax_src)
-             .source_comments(c_ctx->source_comments)
-             .source_map_file(safe_str(c_ctx->source_map_file))
-             .source_map_root(safe_str(c_ctx->source_map_root))
-             .source_map_embed(c_ctx->source_map_embed)
-             .source_map_contents(c_ctx->source_map_contents)
-             .omit_source_map_url(c_ctx->omit_source_map_url)
-             .include_paths_c_str(c_ctx->include_path)
-             .plugin_paths_c_str(c_ctx->plugin_path)
-             // .include_paths_array(include_paths)
-             // .plugin_paths_array(plugin_paths)
-             .include_paths(vector<string>())
-             .plugin_paths(vector<string>())
-             .precision(c_ctx->precision)
-             .linefeed(c_ctx->linefeed)
-             .indent(c_ctx->indent);
-
-      // create new c++ Context
-      Context* cpp_ctx = new Context(cpp_opt);
-      // free intermediate data
-      free(include_paths);
-      free(plugin_paths);
-
-      // register our custom functions
-      if (c_ctx->c_functions) {
-        auto this_func_data = c_ctx->c_functions;
-        while (this_func_data && *this_func_data) {
-          cpp_ctx->add_c_function(*this_func_data);
-          ++this_func_data;
-        }
-      }
-
-      // register our custom headers
-      if (c_ctx->c_headers) {
-        auto this_head_data = c_ctx->c_headers;
-        while (this_head_data && *this_head_data) {
-          cpp_ctx->add_c_header(*this_head_data);
-          ++this_head_data;
-        }
-      }
-
-      // register our custom importers
-      if (c_ctx->c_importers) {
-        auto this_imp_data = c_ctx->c_importers;
-        while (this_imp_data && *this_imp_data) {
-          cpp_ctx->add_c_importer(*this_imp_data);
-          ++this_imp_data;
-        }
-      }
-
-      // reset error status
-      c_ctx->error_json = 0;
-      c_ctx->error_text = 0;
-      c_ctx->error_message = 0;
-      c_ctx->error_status = 0;
-      // reset error position
-      c_ctx->error_src = 0;
-      c_ctx->error_file = 0;
-      c_ctx->error_line = string::npos;
-      c_ctx->error_column = string::npos;
-
-      // allocate a new compiler instance
-      Sass_Compiler* compiler = (struct Sass_Compiler*) calloc(1, sizeof(struct Sass_Compiler));
-      compiler->state = SASS_COMPILER_CREATED;
-
-      // store in sass compiler
-      compiler->c_ctx = c_ctx;
-      compiler->cpp_ctx = cpp_ctx;
-      cpp_ctx->c_compiler = compiler;
-
-      // use to parse block
-      return compiler;
-
-    }
-    // pass errors to generic error handler
-    catch (...) { handle_errors(c_ctx); }
-
-    // error
-    return 0;
-
-  }
-
-  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
-      string input_path = safe_str(c_ctx->input_path);
-      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
-      size_t skip = 0;
-
-      // dispatch to the correct render function
-      if (c_ctx->type == SASS_CONTEXT_FILE) {
-        root = cpp_ctx->parse_file();
-      } else if (c_ctx->type == SASS_CONTEXT_DATA) {
-        root = cpp_ctx->parse_string();
-        skip = 1; // skip first entry of includes
-      }
-
-      // skip all prefixed files?
-      skip += cpp_ctx->head_imports;
-
-      // copy the included files on to the context (dont forget to free)
-      if (root) copy_strings(cpp_ctx->get_included_files(skip), &c_ctx->included_files);
-
-      // 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::Data cpp_opt)
-  {
-
-    // prepare sass compiler with context and options
-    Sass_Compiler* compiler = sass_prepare_context(c_ctx, cpp_opt);
-
-    try {
-      // call each compiler step
-      sass_compiler_parse(compiler);
-      sass_compiler_execute(compiler);
-    }
-    // pass errors to generic error handler
-    catch (...) { handle_errors(c_ctx); }
-
-    sass_delete_compiler(compiler);
-
-    return c_ctx->error_status;
-  }
-
-  inline void init_options (struct Sass_Options* options)
-  {
-    options->precision = 5;
-    options->indent = "  ";
-    options->linefeed = LFEED;
-  }
-
-  Sass_Options* ADDCALL sass_make_options (void)
-  {
-    struct Sass_Options* options = (struct Sass_Options*) calloc(1, sizeof(struct Sass_Options));
-    if (options == 0) { cerr << "Error allocating memory for options" << endl; return 0; }
-    init_options(options);
-    return options;
-  }
-
-  Sass_File_Context* ADDCALL sass_make_file_context(const char* input_path)
-  {
-    struct Sass_File_Context* ctx = (struct Sass_File_Context*) calloc(1, sizeof(struct Sass_File_Context));
-    if (ctx == 0) { cerr << "Error allocating memory for file context" << endl; return 0; }
-    ctx->type = SASS_CONTEXT_FILE;
-    init_options(ctx);
-    try {
-      if (input_path == 0) { throw(runtime_error("File context created without an input path")); }
-      if (*input_path == 0) { throw(runtime_error("File context created with empty input path")); }
-      sass_option_set_input_path(ctx, input_path);
-    } catch (...) {
-      handle_errors(ctx);
-    }
-    return ctx;
-  }
-
-  Sass_Data_Context* ADDCALL sass_make_data_context(char* source_string)
-  {
-    struct Sass_Data_Context* ctx = (struct Sass_Data_Context*) calloc(1, sizeof(struct Sass_Data_Context));
-    if (ctx == 0) { cerr << "Error allocating memory for data context" << endl; return 0; }
-    ctx->type = SASS_CONTEXT_DATA;
-    init_options(ctx);
-    try {
-      if (source_string == 0) { throw(runtime_error("Data context created without a source string")); }
-      if (*source_string == 0) { throw(runtime_error("Data context created with empty source string")); }
-      ctx->source_string = source_string;
-    } catch (...) {
-      handle_errors(ctx);
-    }
-    return ctx;
-  }
-
-  struct Sass_Compiler* ADDCALL sass_make_file_compiler (struct Sass_File_Context* c_ctx)
-  {
-    if (c_ctx == 0) return 0;
-    Context::Data cpp_opt = Context::Data();
-    cpp_opt.entry_point(c_ctx->input_path);
-    return sass_prepare_context(c_ctx, cpp_opt);
-  }
-
-  struct Sass_Compiler* ADDCALL sass_make_data_compiler (struct Sass_Data_Context* c_ctx)
-  {
-    if (c_ctx == 0) return 0;
-    Context::Data cpp_opt = Context::Data();
-    cpp_opt.source_c_str(c_ctx->source_string);
-    return sass_prepare_context(c_ctx, cpp_opt);
-  }
-
-  int ADDCALL sass_compile_data_context(Sass_Data_Context* data_ctx)
-  {
-    if (data_ctx == 0) return 1;
-    Sass_Context* c_ctx = data_ctx;
-    if (c_ctx->error_status)
-      return c_ctx->error_status;
-    Context::Data cpp_opt = Context::Data();
-    try {
-      if (data_ctx->source_string == 0) { throw(runtime_error("Data context has no source string")); }
-      if (*data_ctx->source_string == 0) { throw(runtime_error("Data context has empty source string")); }
-      cpp_opt.source_c_str(data_ctx->source_string);
-    }
-    catch (...) { return handle_errors(c_ctx) | 1; }
-    return sass_compile_context(c_ctx, cpp_opt);
-  }
-
-  int ADDCALL sass_compile_file_context(Sass_File_Context* file_ctx)
-  {
-    if (file_ctx == 0) return 1;
-    Sass_Context* c_ctx = file_ctx;
-    if (c_ctx->error_status)
-      return c_ctx->error_status;
-    Context::Data cpp_opt = Context::Data();
-    try {
-      if (file_ctx->input_path == 0) { throw(runtime_error("File context has no input path")); }
-      if (*file_ctx->input_path == 0) { throw(runtime_error("File context has empty input path")); }
-      cpp_opt.entry_point(file_ctx->input_path);
-    }
-    catch (...) { return handle_errors(c_ctx) | 1; }
-    return sass_compile_context(c_ctx, cpp_opt);
-  }
-
-  int ADDCALL sass_compiler_parse(struct Sass_Compiler* compiler)
-  {
-    if (compiler == 0) return 1;
-    if (compiler->state == SASS_COMPILER_PARSED) return 0;
-    if (compiler->state != SASS_COMPILER_CREATED) return -1;
-    if (compiler->c_ctx == NULL) return 1;
-    if (compiler->cpp_ctx == NULL) return 1;
-    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);
-    // success
-    return 0;
-  }
-
-  int ADDCALL sass_compiler_execute(struct Sass_Compiler* compiler)
-  {
-    if (compiler == 0) return 1;
-    if (compiler->state == SASS_COMPILER_EXECUTED) return 0;
-    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->c_ctx->error_status)
-      return compiler->c_ctx->error_status;
-    compiler->state = SASS_COMPILER_EXECUTED;
-    Context* cpp_ctx = (Context*) compiler->cpp_ctx;
-    Block* root = (Block*) compiler->root;
-    // compile the parsed root block
-    try { compiler->c_ctx->output_string = cpp_ctx->compile_block(root); }
-    // pass catched errors to generic error handler
-    catch (...) { return handle_errors(compiler->c_ctx) | 1; }
-    // generate source map json and store on context
-    compiler->c_ctx->source_map_string = cpp_ctx->generate_source_map();
-    // success
-    return 0;
-  }
-
-  // helper function, not exported, only accessible locally
-  static void sass_clear_options (struct Sass_Options* options)
-  {
-    if (options == 0) return;
-    // Deallocate custom functions
-    if (options->c_functions) {
-      Sass_Function_List this_func_data = options->c_functions;
-      while (this_func_data && *this_func_data) {
-        free(*this_func_data);
-        ++this_func_data;
-      }
-    }
-    // Deallocate custom headers
-    if (options->c_headers) {
-      Sass_Importer_List this_head_data = options->c_headers;
-      while (this_head_data && *this_head_data) {
-        free(*this_head_data);
-        ++this_head_data;
-      }
-    }
-    // Deallocate custom importers
-    if (options->c_importers) {
-      Sass_Importer_List this_imp_data = options->c_importers;
-      while (this_imp_data && *this_imp_data) {
-        free(*this_imp_data);
-        ++this_imp_data;
-      }
-    }
-    // Deallocate inc paths
-    if (options->plugin_paths) {
-      struct string_list* cur;
-      struct string_list* next;
-      cur = options->plugin_paths;
-      while (cur) {
-        next = cur->next;
-        free(cur->string);
-        free(cur);
-        cur = next;
-      }
-    }
-    // Deallocate inc paths
-    if (options->include_paths) {
-      struct string_list* cur;
-      struct string_list* next;
-      cur = options->include_paths;
-      while (cur) {
-        next = cur->next;
-        free(cur->string);
-        free(cur);
-        cur = next;
-      }
-    }
-    // Free custom functions
-    free(options->c_functions);
-    // Free custom importers
-    free(options->c_importers);
-    free(options->c_headers);
-    // Reset our pointers
-    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
-  // sass_free_context is also defined in old sass_interface
-  static void sass_clear_context (struct Sass_Context* ctx)
-  {
-    if (ctx == 0) return;
-    // release the allocated memory (mostly via sass_strdup)
-    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->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;
-    ctx->source_map_string = 0;
-    ctx->error_message = 0;
-    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;
-    // now clear the options
-    sass_clear_options(ctx);
-  }
-
-  void ADDCALL sass_delete_compiler (struct Sass_Compiler* compiler)
-  {
-    if (compiler == 0) return;
-    Context* cpp_ctx = (Context*) compiler->cpp_ctx;
-    compiler->cpp_ctx = 0;
-    delete cpp_ctx;
-    free(compiler);
-  }
-
-  // Deallocate all associated memory with contexts
-  void ADDCALL sass_delete_file_context (struct Sass_File_Context* ctx) { sass_clear_context(ctx); free(ctx); }
-  void ADDCALL sass_delete_data_context (struct Sass_Data_Context* ctx) { sass_clear_context(ctx); free(ctx); }
-
-  // Getters for sass context from specific implementations
-  struct Sass_Context* ADDCALL sass_file_context_get_context(struct Sass_File_Context* ctx) { return ctx; }
-  struct Sass_Context* ADDCALL sass_data_context_get_context(struct Sass_Data_Context* ctx) { return ctx; }
-
-  // Getters for context options from Sass_Context
-  struct Sass_Options* ADDCALL sass_context_get_options(struct Sass_Context* ctx) { return ctx; }
-  struct Sass_Options* ADDCALL sass_file_context_get_options(struct Sass_File_Context* ctx) { return ctx; }
-  struct Sass_Options* ADDCALL sass_data_context_get_options(struct Sass_Data_Context* ctx) { return ctx; }
-  void ADDCALL sass_file_context_set_options (struct Sass_File_Context* ctx, struct Sass_Options* opt) { copy_options(ctx, opt); }
-  void ADDCALL sass_data_context_set_options (struct Sass_Data_Context* ctx, struct Sass_Options* opt) { copy_options(ctx, opt); }
-
-  // Getters for Sass_Compiler options (get conected sass context)
-  enum Sass_Compiler_State ADDCALL sass_compiler_get_state(struct Sass_Compiler* compiler) { return compiler->state; }
-  struct Sass_Context* ADDCALL sass_compiler_get_context(struct Sass_Compiler* compiler) { return compiler->c_ctx; }
-  // Getters for Sass_Compiler options (query import stack)
-  size_t ADDCALL sass_compiler_get_import_stack_size(struct Sass_Compiler* compiler) { return compiler->cpp_ctx->import_stack.size(); }
-  Sass_Import_Entry ADDCALL sass_compiler_get_last_import(struct Sass_Compiler* compiler) { return compiler->cpp_ctx->import_stack.back(); }
-  Sass_Import_Entry ADDCALL sass_compiler_get_import_entry(struct Sass_Compiler* compiler, size_t idx) { return compiler->cpp_ctx->import_stack[idx]; }
-
-  // Calculate the size of the stored null terminated array
-  size_t ADDCALL sass_context_get_included_files_size (struct Sass_Context* ctx)
-  { size_t l = 0; auto i = ctx->included_files; while (i && *i) { ++i; ++l; } return l; }
-
-  // Create getter and setters for options
-  IMPLEMENT_SASS_OPTION_ACCESSOR(int, precision);
-  IMPLEMENT_SASS_OPTION_ACCESSOR(enum Sass_Output_Style, output_style);
-  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, omit_source_map_url);
-  IMPLEMENT_SASS_OPTION_ACCESSOR(bool, is_indented_syntax_src);
-  IMPLEMENT_SASS_OPTION_ACCESSOR(Sass_Function_List, c_functions);
-  IMPLEMENT_SASS_OPTION_ACCESSOR(Sass_Importer_List, c_importers);
-  IMPLEMENT_SASS_OPTION_ACCESSOR(Sass_Importer_List, c_headers);
-  IMPLEMENT_SASS_OPTION_ACCESSOR(const char*, indent);
-  IMPLEMENT_SASS_OPTION_ACCESSOR(const char*, linefeed);
-  IMPLEMENT_SASS_OPTION_STRING_ACCESSOR(const char*, input_path);
-  IMPLEMENT_SASS_OPTION_STRING_ACCESSOR(const char*, output_path);
-  IMPLEMENT_SASS_OPTION_STRING_ACCESSOR(const char*, plugin_path);
-  IMPLEMENT_SASS_OPTION_STRING_ACCESSOR(const char*, include_path);
-  IMPLEMENT_SASS_OPTION_STRING_ACCESSOR(const char*, source_map_file);
-  IMPLEMENT_SASS_OPTION_STRING_ACCESSOR(const char*, source_map_root);
-
-  // Create getter and setters for context
-  IMPLEMENT_SASS_CONTEXT_GETTER(int, error_status);
-  IMPLEMENT_SASS_CONTEXT_GETTER(const char*, error_json);
-  IMPLEMENT_SASS_CONTEXT_GETTER(const char*, error_message);
-  IMPLEMENT_SASS_CONTEXT_GETTER(const char*, error_text);
-  IMPLEMENT_SASS_CONTEXT_GETTER(const char*, error_file);
-  IMPLEMENT_SASS_CONTEXT_GETTER(size_t, error_line);
-  IMPLEMENT_SASS_CONTEXT_GETTER(size_t, error_column);
-  IMPLEMENT_SASS_CONTEXT_GETTER(const char*, error_src);
-  IMPLEMENT_SASS_CONTEXT_GETTER(const char*, output_string);
-  IMPLEMENT_SASS_CONTEXT_GETTER(const char*, source_map_string);
-  IMPLEMENT_SASS_CONTEXT_GETTER(char**, included_files);
-
-  // Take ownership of memory (value on context is set to 0)
-  IMPLEMENT_SASS_CONTEXT_TAKER(char*, error_json);
-  IMPLEMENT_SASS_CONTEXT_TAKER(char*, error_message);
-  IMPLEMENT_SASS_CONTEXT_TAKER(char*, error_text);
-  IMPLEMENT_SASS_CONTEXT_TAKER(char*, error_file);
-  IMPLEMENT_SASS_CONTEXT_TAKER(char*, output_string);
-  IMPLEMENT_SASS_CONTEXT_TAKER(char*, source_map_string);
-  IMPLEMENT_SASS_CONTEXT_TAKER(char**, included_files);
-
-  // Push function for include paths (no manipulation support for now)
-  void ADDCALL sass_option_push_include_path(struct Sass_Options* options, const char* path)
-  {
-
-    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;
-    struct string_list* last = options->include_paths;
-    if (!options->include_paths) {
-      options->include_paths = include_path;
-    } else {
-      while (last->next)
-        last = last->next;
-      last->next = include_path;
-    }
-
-  }
-
-  // Push function for plugin paths (no manipulation support for now)
-  void ADDCALL sass_option_push_plugin_path(struct Sass_Options* options, const char* path)
-  {
-
-    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;
-    struct string_list* last = options->plugin_paths;
-    if (!options->plugin_paths) {
-      options->plugin_paths = plugin_path;
-    } else {
-      while (last->next)
-        last = last->next;
-      last->next = plugin_path;
-    }
-
-  }
-
-}
diff --git a/libsass/sass_context.h b/libsass/sass_context.h
deleted file mode 100644
--- a/libsass/sass_context.h
+++ /dev/null
@@ -1,149 +0,0 @@
-#ifndef SASS_C_CONTEXT_H
-#define SASS_C_CONTEXT_H
-
-#include <stddef.h>
-#include <stdbool.h>
-#include "sass.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-// Forward declaration
-struct Sass_Compiler;
-
-// Forward declaration
-struct Sass_Options; // base struct
-struct Sass_Context; // : Sass_Options
-struct Sass_File_Context; // : Sass_Context
-struct Sass_Data_Context; // : Sass_Context
-
-// Compiler states
-enum Sass_Compiler_State {
-  SASS_COMPILER_CREATED,
-  SASS_COMPILER_PARSED,
-  SASS_COMPILER_EXECUTED
-};
-
-// Create and initialize an option struct
-ADDAPI struct Sass_Options* ADDCALL sass_make_options (void);
-// Create and initialize a specific context
-ADDAPI struct Sass_File_Context* ADDCALL sass_make_file_context (const char* input_path);
-ADDAPI struct Sass_Data_Context* ADDCALL sass_make_data_context (char* source_string);
-
-// Call the compilation step for the specific context
-ADDAPI int ADDCALL sass_compile_file_context (struct Sass_File_Context* ctx);
-ADDAPI int ADDCALL sass_compile_data_context (struct Sass_Data_Context* ctx);
-
-// Create a sass compiler instance for more control
-ADDAPI struct Sass_Compiler* ADDCALL sass_make_file_compiler (struct Sass_File_Context* file_ctx);
-ADDAPI struct Sass_Compiler* ADDCALL sass_make_data_compiler (struct Sass_Data_Context* data_ctx);
-
-// Execute the different compilation steps individually
-// Usefull if you only want to query the included files
-ADDAPI int ADDCALL sass_compiler_parse(struct Sass_Compiler* compiler);
-ADDAPI int ADDCALL sass_compiler_execute(struct Sass_Compiler* compiler);
-
-// 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);
-
-// Release all memory allocated and also ourself
-ADDAPI void ADDCALL sass_delete_file_context (struct Sass_File_Context* ctx);
-ADDAPI void ADDCALL sass_delete_data_context (struct Sass_Data_Context* ctx);
-
-// Getters for context from specific implementation
-ADDAPI struct Sass_Context* ADDCALL sass_file_context_get_context (struct Sass_File_Context* file_ctx);
-ADDAPI struct Sass_Context* ADDCALL sass_data_context_get_context (struct Sass_Data_Context* data_ctx);
-
-// Getters for Context_Options from Sass_Context
-ADDAPI struct Sass_Options* ADDCALL sass_context_get_options (struct Sass_Context* ctx);
-ADDAPI struct Sass_Options* ADDCALL sass_file_context_get_options (struct Sass_File_Context* file_ctx);
-ADDAPI struct Sass_Options* ADDCALL sass_data_context_get_options (struct Sass_Data_Context* data_ctx);
-ADDAPI void ADDCALL sass_file_context_set_options (struct Sass_File_Context* file_ctx, struct Sass_Options* opt);
-ADDAPI void ADDCALL sass_data_context_set_options (struct Sass_Data_Context* data_ctx, struct Sass_Options* opt);
-
-
-// Getters for Context_Option values
-ADDAPI int ADDCALL sass_option_get_precision (struct Sass_Options* options);
-ADDAPI enum Sass_Output_Style ADDCALL sass_option_get_output_style (struct Sass_Options* options);
-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_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);
-ADDAPI const char* ADDCALL sass_option_get_linefeed (struct Sass_Options* options);
-ADDAPI const char* ADDCALL sass_option_get_input_path (struct Sass_Options* options);
-ADDAPI const char* ADDCALL sass_option_get_output_path (struct Sass_Options* options);
-ADDAPI const char* ADDCALL sass_option_get_plugin_path (struct Sass_Options* options);
-ADDAPI const char* ADDCALL sass_option_get_include_path (struct Sass_Options* options);
-ADDAPI const char* ADDCALL sass_option_get_source_map_file (struct Sass_Options* options);
-ADDAPI const char* ADDCALL sass_option_get_source_map_root (struct Sass_Options* options);
-ADDAPI Sass_Importer_List ADDCALL sass_option_get_c_headers (struct Sass_Options* options);
-ADDAPI Sass_Importer_List ADDCALL sass_option_get_c_importers (struct Sass_Options* options);
-ADDAPI Sass_Function_List ADDCALL sass_option_get_c_functions (struct Sass_Options* options);
-
-// Setters for Context_Option values
-ADDAPI void ADDCALL sass_option_set_precision (struct Sass_Options* options, int precision);
-ADDAPI void ADDCALL sass_option_set_output_style (struct Sass_Options* options, enum Sass_Output_Style output_style);
-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_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);
-ADDAPI void ADDCALL sass_option_set_linefeed (struct Sass_Options* options, const char* linefeed);
-ADDAPI void ADDCALL sass_option_set_input_path (struct Sass_Options* options, const char* input_path);
-ADDAPI void ADDCALL sass_option_set_output_path (struct Sass_Options* options, const char* output_path);
-ADDAPI void ADDCALL sass_option_set_plugin_path (struct Sass_Options* options, const char* plugin_path);
-ADDAPI void ADDCALL sass_option_set_include_path (struct Sass_Options* options, const char* include_path);
-ADDAPI void ADDCALL sass_option_set_source_map_file (struct Sass_Options* options, const char* source_map_file);
-ADDAPI void ADDCALL sass_option_set_source_map_root (struct Sass_Options* options, const char* source_map_root);
-ADDAPI void ADDCALL sass_option_set_c_headers (struct Sass_Options* options, Sass_Importer_List c_headers);
-ADDAPI void ADDCALL sass_option_set_c_importers (struct Sass_Options* options, Sass_Importer_List c_importers);
-ADDAPI void ADDCALL sass_option_set_c_functions (struct Sass_Options* options, Sass_Function_List c_functions);
-
-
-// Getters for Sass_Context values
-ADDAPI const char* ADDCALL sass_context_get_output_string (struct Sass_Context* ctx);
-ADDAPI int ADDCALL sass_context_get_error_status (struct Sass_Context* ctx);
-ADDAPI const char* ADDCALL sass_context_get_error_json (struct Sass_Context* ctx);
-ADDAPI const char* ADDCALL sass_context_get_error_text (struct Sass_Context* ctx);
-ADDAPI const char* ADDCALL sass_context_get_error_message (struct Sass_Context* ctx);
-ADDAPI const char* ADDCALL sass_context_get_error_file (struct Sass_Context* ctx);
-ADDAPI const char* ADDCALL sass_context_get_error_src (struct Sass_Context* ctx);
-ADDAPI size_t ADDCALL sass_context_get_error_line (struct Sass_Context* ctx);
-ADDAPI size_t ADDCALL sass_context_get_error_column (struct Sass_Context* ctx);
-ADDAPI const char* ADDCALL sass_context_get_source_map_string (struct Sass_Context* ctx);
-ADDAPI char** ADDCALL sass_context_get_included_files (struct Sass_Context* ctx);
-
-// Calculate the size of the stored null terminated array
-ADDAPI size_t ADDCALL sass_context_get_included_files_size (struct Sass_Context* ctx);
-
-// Take ownership of memory (value on context is set to 0)
-ADDAPI char* ADDCALL sass_context_take_error_json (struct Sass_Context* ctx);
-ADDAPI char* ADDCALL sass_context_take_error_text (struct Sass_Context* ctx);
-ADDAPI char* ADDCALL sass_context_take_error_message (struct Sass_Context* ctx);
-ADDAPI char* ADDCALL sass_context_take_error_file (struct Sass_Context* ctx);
-ADDAPI char* ADDCALL sass_context_take_output_string (struct Sass_Context* ctx);
-ADDAPI char* ADDCALL sass_context_take_source_map_string (struct Sass_Context* ctx);
-ADDAPI char** ADDCALL sass_context_take_included_files (struct Sass_Context* ctx);
-
-// Getters for Sass_Compiler options
-ADDAPI enum Sass_Compiler_State ADDCALL sass_compiler_get_state(struct Sass_Compiler* compiler);
-ADDAPI struct Sass_Context* ADDCALL sass_compiler_get_context(struct Sass_Compiler* compiler);
-ADDAPI size_t ADDCALL sass_compiler_get_import_stack_size(struct Sass_Compiler* compiler);
-ADDAPI Sass_Import_Entry ADDCALL sass_compiler_get_last_import(struct Sass_Compiler* compiler);
-ADDAPI Sass_Import_Entry ADDCALL sass_compiler_get_import_entry(struct Sass_Compiler* compiler, size_t idx);
-
-// Push function for paths (no manipulation support for now)
-ADDAPI void ADDCALL sass_option_push_plugin_path (struct Sass_Options* options, const char* path);
-ADDAPI void ADDCALL sass_option_push_include_path (struct Sass_Options* options, const char* path);
-
-#ifdef __cplusplus
-} // __cplusplus defined.
-#endif
-
-#endif
diff --git a/libsass/sass_functions.cpp b/libsass/sass_functions.cpp
deleted file mode 100644
--- a/libsass/sass_functions.cpp
+++ /dev/null
@@ -1,173 +0,0 @@
-#ifdef _WIN32
-#include <io.h>
-#else
-#include <unistd.h>
-#endif
-
-#include <cstring>
-#include "util.hpp"
-#include "context.hpp"
-#include "sass_functions.h"
-
-extern "C" {
-  using namespace std;
-  using namespace Sass;
-
-  // Struct to hold custom function callback
-  struct Sass_Function {
-    const char*      signature;
-    Sass_Function_Fn function;
-    void*            cookie;
-  };
-
-  Sass_Function_List ADDCALL sass_make_function_list(size_t length)
-  {
-    return (Sass_Function_List) calloc(length + 1, sizeof(Sass_Function_Entry));
-  }
-
-  Sass_Function_Entry ADDCALL sass_make_function(const char* signature, Sass_Function_Fn function, void* cookie)
-  {
-    Sass_Function_Entry cb = (Sass_Function_Entry) calloc(1, sizeof(Sass_Function));
-    if (cb == 0) return 0;
-    cb->signature = signature;
-    cb->function = function;
-    cb->cookie = cookie;
-    return cb;
-  }
-
-  // Setters and getters for callbacks on function lists
-  Sass_Function_Entry ADDCALL sass_function_get_list_entry(Sass_Function_List list, size_t pos) { return list[pos]; }
-  void sass_function_set_list_entry(Sass_Function_List list, size_t pos, Sass_Function_Entry cb) { list[pos] = cb; }
-
-  const char* ADDCALL sass_function_get_signature(Sass_Function_Entry cb) { return cb->signature; }
-  Sass_Function_Fn ADDCALL sass_function_get_function(Sass_Function_Entry cb) { return cb->function; }
-  void* ADDCALL sass_function_get_cookie(Sass_Function_Entry cb) { return cb->cookie; }
-
-  // External import entry
-  struct Sass_Import {
-    char* path;
-    char* base;
-    char* source;
-    char* srcmap;
-    // error handling
-    char* error;
-    size_t line;
-    size_t column;
-  };
-
-  // Struct to hold importer callback
-  struct Sass_Importer {
-    Sass_Importer_Fn importer;
-    double           priority;
-    void*            cookie;
-  };
-
-  Sass_Importer_Entry ADDCALL sass_make_importer(Sass_Importer_Fn importer, double priority, void* cookie)
-  {
-    Sass_Importer_Entry cb = (Sass_Importer_Entry) calloc(1, sizeof(Sass_Importer));
-    if (cb == 0) return 0;
-    cb->importer = importer;
-    cb->priority = priority;
-    cb->cookie = cookie;
-    return cb;
-  }
-
-  Sass_Importer_Fn ADDCALL sass_importer_get_function(Sass_Importer_Entry cb) { return cb->importer; }
-  double ADDCALL sass_importer_get_priority (Sass_Importer_Entry cb) { return cb->priority; }
-  void* ADDCALL sass_importer_get_cookie(Sass_Importer_Entry cb) { return cb->cookie; }
-
-  // Just in case we have some stray import structs
-  void ADDCALL sass_delete_importer (Sass_Importer_Entry cb)
-  {
-    free(cb);
-  }
-
-  // Creator for sass custom importer function list
-  Sass_Importer_List ADDCALL sass_make_importer_list(size_t length)
-  {
-    return (Sass_Importer_List) calloc(length + 1, sizeof(Sass_Importer_Entry));
-  }
-
-  // Creator for sass custom importer return argument list
-  Sass_Import_List ADDCALL sass_make_import_list(size_t length)
-  {
-    return (Sass_Import**) calloc(length + 1, sizeof(Sass_Import*));
-  }
-
-  // Creator for a single import entry returned by the custom importer inside the list
-  // We take ownership of the memory for source and srcmap (freed when context is destroyd)
-  Sass_Import_Entry ADDCALL sass_make_import(const char* path, const char* base, char* source, char* srcmap)
-  {
-    Sass_Import* v = (Sass_Import*) calloc(1, sizeof(Sass_Import));
-    if (v == 0) return 0;
-    v->path = path ? sass_strdup(path) : 0;
-    v->base = base ? sass_strdup(base) : 0;
-    v->source = source;
-    v->srcmap = srcmap;
-    v->error = 0;
-    v->line = -1;
-    v->column = -1;
-    return v;
-  }
-
-  // Older style, but somehow still valid - keep around or deprecate?
-  Sass_Import_Entry ADDCALL sass_make_import_entry(const char* path, char* source, char* srcmap)
-  {
-    return sass_make_import(path, path, source, srcmap);
-  }
-
-  // Upgrade a normal import entry to throw an error (original path can be re-used by error reporting)
-  Sass_Import_Entry ADDCALL sass_import_set_error(Sass_Import_Entry import, const char* error, size_t line, size_t col)
-  {
-    if (import == 0) return 0;
-    if (import->error) free(import->error);
-    import->error = error ? strdup(error) : 0;
-    import->line = line ? line : -1;
-    import->column = col ? col : -1;
-    return import;
-  }
-
-  // Setters and getters for entries on the import list
-  void ADDCALL sass_import_set_list_entry(Sass_Import_List list, size_t idx, Sass_Import_Entry entry) { list[idx] = entry; }
-  Sass_Import_Entry ADDCALL sass_import_get_list_entry(Sass_Import_List list, size_t idx) { return list[idx]; }
-
-  // Deallocator for the allocated memory
-  void ADDCALL sass_delete_import_list(Sass_Import_List list)
-  {
-    Sass_Import_List it = list;
-    if (list == 0) return;
-    while(*list) {
-      sass_delete_import(*list);
-      ++list;
-    }
-    free(it);
-  }
-
-  // Just in case we have some stray import structs
-  void ADDCALL sass_delete_import(Sass_Import_Entry import)
-  {
-    free(import->path);
-    free(import->base);
-    free(import->source);
-    free(import->srcmap);
-    free(import->error);
-    free(import);
-  }
-
-  // Getter for import entry
-  const char* ADDCALL sass_import_get_path(Sass_Import_Entry entry) { return entry->path; }
-  const char* ADDCALL sass_import_get_base(Sass_Import_Entry entry) { return entry->base; }
-  const char* ADDCALL sass_import_get_source(Sass_Import_Entry entry) { return entry->source; }
-  const char* ADDCALL sass_import_get_srcmap(Sass_Import_Entry entry) { return entry->srcmap; }
-
-  // Getter for import error entry
-  size_t ADDCALL sass_import_get_error_line(Sass_Import_Entry entry) { return entry->line; }
-  size_t ADDCALL sass_import_get_error_column(Sass_Import_Entry entry) { return entry->column; }
-  const char* ADDCALL sass_import_get_error_message(Sass_Import_Entry entry) { return entry->error; }
-
-  // Explicit functions to take ownership of the memory
-  // Resets our own property since we do not know if it is still alive
-  char* ADDCALL sass_import_take_source(Sass_Import_Entry entry) { char* ptr = entry->source; entry->source = 0; return ptr; }
-  char* ADDCALL sass_import_take_srcmap(Sass_Import_Entry entry) { char* ptr = entry->srcmap; entry->srcmap = 0; return ptr; }
-
-}
diff --git a/libsass/sass_functions.h b/libsass/sass_functions.h
deleted file mode 100644
--- a/libsass/sass_functions.h
+++ /dev/null
@@ -1,108 +0,0 @@
-#ifndef SASS_C_FUNCTIONS_H
-#define SASS_C_FUNCTIONS_H
-
-#include <stddef.h>
-#include <stdbool.h>
-#include "sass.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-// Forward declaration
-struct Sass_Import;
-struct Sass_Options;
-struct Sass_Compiler;
-struct Sass_Importer;
-struct Sass_Function;
-
-// Typedef helpers for import lists
-typedef struct Sass_Import (*Sass_Import_Entry);
-typedef struct Sass_Import* (*Sass_Import_List);
-// Typedef helpers for custom importer lists
-typedef struct Sass_Importer (*Sass_Importer_Entry);
-typedef struct Sass_Importer* (*Sass_Importer_List);
-// Typedef defining importer signature and return type
-typedef Sass_Import_List (*Sass_Importer_Fn)
-  (const char* url, Sass_Importer_Entry cb, struct Sass_Compiler* compiler);
-
-// Typedef helpers for custom functions lists
-typedef struct Sass_Function (*Sass_Function_Entry);
-typedef struct Sass_Function* (*Sass_Function_List);
-// Typedef defining function signature and return type
-typedef union Sass_Value* (*Sass_Function_Fn)
-  (const union Sass_Value*, Sass_Function_Entry cb, struct Sass_Options* options);
-
-
-// Creator for sass custom importer return argument list
-ADDAPI Sass_Importer_List ADDCALL sass_make_importer_list (size_t length);
-ADDAPI Sass_Importer_Entry ADDCALL sass_importer_get_list_entry (Sass_Importer_List list, size_t idx);
-ADDAPI void ADDCALL sass_importer_set_list_entry (Sass_Importer_List list, size_t idx, Sass_Importer_Entry entry);
-
-
-// Creators for custom importer callback (with some additional pointer)
-// The pointer is mostly used to store the callback into the actual binding
-ADDAPI Sass_Importer_Entry ADDCALL sass_make_importer (Sass_Importer_Fn importer, double priority, void* cookie);
-
-// Getters for import function descriptors
-ADDAPI Sass_Importer_Fn ADDCALL sass_importer_get_function (Sass_Importer_Entry cb);
-ADDAPI double ADDCALL sass_importer_get_priority (Sass_Importer_Entry cb);
-ADDAPI void* ADDCALL sass_importer_get_cookie (Sass_Importer_Entry cb);
-
-// Deallocator for associated memory
-ADDAPI void ADDCALL sass_delete_importer (Sass_Importer_Entry cb);
-
-// Creator for sass custom importer return argument list
-ADDAPI Sass_Import_List ADDCALL sass_make_import_list (size_t length);
-// Creator for a single import entry returned by the custom importer inside the list
-ADDAPI Sass_Import_Entry ADDCALL sass_make_import_entry (const char* path, char* source, char* srcmap);
-ADDAPI Sass_Import_Entry ADDCALL sass_make_import (const char* path, const char* base, char* source, char* srcmap);
-// set error message to abort import and to print out a message (path from existing object is used in output)
-ADDAPI Sass_Import_Entry ADDCALL sass_import_set_error(Sass_Import_Entry import, const char* message, size_t line, size_t col);
-
-// Setters to insert an entry into the import list (you may also use [] access directly)
-// Since we are dealing with pointers they should have a guaranteed and fixed size
-ADDAPI void ADDCALL sass_import_set_list_entry (Sass_Import_List list, size_t idx, Sass_Import_Entry entry);
-ADDAPI Sass_Import_Entry ADDCALL sass_import_get_list_entry (Sass_Import_List list, size_t idx);
-
-// Getters for import entry
-ADDAPI const char* ADDCALL sass_import_get_path (Sass_Import_Entry);
-ADDAPI const char* ADDCALL sass_import_get_base (Sass_Import_Entry);
-ADDAPI const char* ADDCALL sass_import_get_source (Sass_Import_Entry);
-ADDAPI const char* ADDCALL sass_import_get_srcmap (Sass_Import_Entry);
-// Explicit functions to take ownership of these items
-// The property on our struct will be reset to NULL
-ADDAPI char* ADDCALL sass_import_take_source (Sass_Import_Entry);
-ADDAPI char* ADDCALL sass_import_take_srcmap (Sass_Import_Entry);
-// Getters from import error entry
-ADDAPI size_t ADDCALL sass_import_get_error_line (Sass_Import_Entry);
-ADDAPI size_t ADDCALL sass_import_get_error_column (Sass_Import_Entry);
-ADDAPI const char* ADDCALL sass_import_get_error_message (Sass_Import_Entry);
-
-// Deallocator for associated memory (incl. entries)
-ADDAPI void ADDCALL sass_delete_import_list (Sass_Import_List);
-// Just in case we have some stray import structs
-ADDAPI void ADDCALL sass_delete_import (Sass_Import_Entry);
-
-
-
-// Creators for sass function list and function descriptors
-ADDAPI Sass_Function_List ADDCALL sass_make_function_list (size_t length);
-ADDAPI Sass_Function_Entry ADDCALL sass_make_function (const char* signature, Sass_Function_Fn cb, void* cookie);
-
-// Setters and getters for callbacks on function lists
-ADDAPI Sass_Function_Entry ADDCALL sass_function_get_list_entry(Sass_Function_List list, size_t pos);
-ADDAPI void ADDCALL sass_function_set_list_entry(Sass_Function_List list, size_t pos, Sass_Function_Entry cb);
-
-// Getters for custom function descriptors
-ADDAPI const char* ADDCALL sass_function_get_signature (Sass_Function_Entry cb);
-ADDAPI Sass_Function_Fn ADDCALL sass_function_get_function (Sass_Function_Entry cb);
-ADDAPI void* ADDCALL sass_function_get_cookie (Sass_Function_Entry cb);
-
-
-#ifdef __cplusplus
-} // __cplusplus defined.
-#endif
-
-#endif
diff --git a/libsass/sass_interface.cpp b/libsass/sass_interface.cpp
deleted file mode 100644
--- a/libsass/sass_interface.cpp
+++ /dev/null
@@ -1,287 +0,0 @@
-#ifdef _WIN32
-#include <io.h>
-#define LFEED "\n"
-#else
-#include <unistd.h>
-#define LFEED "\n"
-#endif
-
-#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_interface.h"
-
-
-extern "C" {
-  using namespace std;
-
-  sass_context* sass_new_context()
-  { return (sass_context*) calloc(1, sizeof(sass_context)); }
-
-  // helper for safe access to c_ctx
-  static const char* safe_str (const char* str) {
-    return str == NULL ? "" : str;
-  }
-
-  static void copy_strings(const std::vector<std::string>& strings, char*** array, int skip = 0) {
-    int num = static_cast<int>(strings.size());
-    char** arr = (char**) malloc(sizeof(char*) * (num + 1));
-
-    for(int i = skip; i < num; i++) {
-      arr[i-skip] = (char*) malloc(sizeof(char) * (strings[i].size() + 1));
-      std::copy(strings[i].begin(), strings[i].end(), arr[i-skip]);
-      arr[i-skip][strings[i].size()] = '\0';
-    }
-
-    arr[num-skip] = 0;
-    *array = arr;
-  }
-
-  static void free_string_array(char ** arr) {
-    if(!arr)
-        return;
-
-    char **it = arr;
-    while (it && (*it)) {
-      free(*it);
-      ++it;
-    }
-
-    free(arr);
-  }
-
-  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);
-
-    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);
-
-    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)
-  {
-    free_string_array(ctx->included_files);
-    free(ctx);
-  }
-
-  int sass_compile(sass_context* c_ctx)
-  {
-    using namespace Sass;
-    try {
-      string input_path = safe_str(c_ctx->input_path);
-      int lastindex = static_cast<int>(input_path.find_last_of("."));
-      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;
-      }
-      Context cpp_ctx(
-        Context::Data().source_c_str(c_ctx->source_string)
-                       .output_path(output_path)
-                       .output_style((Output_Style) c_ctx->options.output_style)
-                       .is_indented_syntax_src(c_ctx->options.is_indented_syntax_src)
-                       .source_comments(c_ctx->options.source_comments)
-                       .source_map_file(safe_str(c_ctx->options.source_map_file))
-                       .source_map_root(safe_str(c_ctx->options.source_map_root))
-                       .source_map_embed(c_ctx->options.source_map_embed)
-                       .source_map_contents(c_ctx->options.source_map_contents)
-                       .omit_source_map_url(c_ctx->options.omit_source_map_url)
-                       .include_paths_c_str(c_ctx->options.include_paths)
-                       .plugin_paths_c_str(c_ctx->options.plugin_paths)
-                       // .include_paths_array(0)
-                       // .plugin_paths_array(0)
-                       .include_paths(vector<string>())
-                       .plugin_paths(vector<string>())
-                       .precision(c_ctx->options.precision ? c_ctx->options.precision : 5)
-                       .indent(c_ctx->options.indent ? c_ctx->options.indent : "  ")
-                       .linefeed(c_ctx->options.linefeed ? c_ctx->options.linefeed : LFEED)
-      );
-      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;
-        }
-      }
-      c_ctx->output_string = cpp_ctx.compile_string();
-      c_ctx->source_map_string = cpp_ctx.generate_source_map();
-      c_ctx->error_message = 0;
-      c_ctx->error_status = 0;
-
-      copy_strings(cpp_ctx.get_included_files(1), &c_ctx->included_files, 1);
-    }
-    catch (Sass_Error& e) {
-      stringstream msg_stream;
-      msg_stream << e.pstate.path << ":" << e.pstate.line << ": " << e.message << 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(bad_alloc& ba) {
-      stringstream msg_stream;
-      msg_stream << "Unable to allocate memory: " << ba.what() << 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) {
-      stringstream msg_stream;
-      msg_stream << "Error: " << e.what() << 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 (string& e) {
-      stringstream msg_stream;
-      msg_stream << "Error: " << e << 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
-      stringstream msg_stream;
-      msg_stream << "Unknown error occurred" << 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 {
-      string input_path = safe_str(c_ctx->input_path);
-      int lastindex = static_cast<int>(input_path.find_last_of("."));
-      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;
-      }
-      Context cpp_ctx(
-        Context::Data().entry_point(input_path)
-                       .output_path(output_path)
-                       .output_style((Output_Style) c_ctx->options.output_style)
-                       .is_indented_syntax_src(c_ctx->options.is_indented_syntax_src)
-                       .source_comments(c_ctx->options.source_comments)
-                       .source_map_file(safe_str(c_ctx->options.source_map_file))
-                       .source_map_root(safe_str(c_ctx->options.source_map_root))
-                       .source_map_embed(c_ctx->options.source_map_embed)
-                       .source_map_contents(c_ctx->options.source_map_contents)
-                       .omit_source_map_url(c_ctx->options.omit_source_map_url)
-                       .include_paths_c_str(c_ctx->options.include_paths)
-                       .plugin_paths_c_str(c_ctx->options.plugin_paths)
-                       // .include_paths_array(0)
-                       // .plugin_paths_array(0)
-                       .include_paths(vector<string>())
-                       .plugin_paths(vector<string>())
-                       .precision(c_ctx->options.precision ? c_ctx->options.precision : 5)
-                       .indent(c_ctx->options.indent ? c_ctx->options.indent : "  ")
-                       .linefeed(c_ctx->options.linefeed ? c_ctx->options.linefeed : LFEED)
-      );
-      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;
-        }
-      }
-      c_ctx->output_string = cpp_ctx.compile_file();
-      c_ctx->source_map_string = cpp_ctx.generate_source_map();
-      c_ctx->error_message = 0;
-      c_ctx->error_status = 0;
-
-      copy_strings(cpp_ctx.get_included_files(), &c_ctx->included_files);
-    }
-    catch (Sass_Error& e) {
-      stringstream msg_stream;
-      msg_stream << e.pstate.path << ":" << e.pstate.line << ": " << e.message << 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(bad_alloc& ba) {
-      stringstream msg_stream;
-      msg_stream << "Unable to allocate memory: " << ba.what() << 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) {
-      stringstream msg_stream;
-      msg_stream << "Error: " << e.what() << 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 (string& e) {
-      stringstream msg_stream;
-      msg_stream << "Error: " << e << 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
-      stringstream msg_stream;
-      msg_stream << "Unknown error occurred" << 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/sass_interface.h b/libsass/sass_interface.h
deleted file mode 100644
--- a/libsass/sass_interface.h
+++ /dev/null
@@ -1,102 +0,0 @@
-#ifndef SASS_C_INTERFACE_H
-#define SASS_C_INTERFACE_H
-
-#include <stddef.h>
-#include <stdbool.h>
-#include "sass.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;
-  const 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/sass_util.cpp b/libsass/sass_util.cpp
deleted file mode 100644
--- a/libsass/sass_util.cpp
+++ /dev/null
@@ -1,132 +0,0 @@
-#include "node.hpp"
-#include "to_string.hpp"
-
-namespace Sass {
-
-
-  /*
-		This is the equivalent of ruby's Sass::Util.paths.
-
-    # Return an array of all possible paths through the given arrays.
-    #
-    # @param arrs [NodeCollection<NodeCollection<Node>>]
-    # @return [NodeCollection<NodeCollection<Node>>]
-    #
-    # @example
-    #   paths([[1, 2], [3, 4], [5]]) #=>
-    #     # [[1, 3, 5],
-    #     #  [2, 3, 5],
-    #     #  [1, 4, 5],
-    #     #  [2, 4, 5]]
-
-   The following is the modified version of the ruby code that was more portable to C++. You
-   should be able to drop it into ruby 3.2.19 and get the same results from ruby sass.
-
-    def paths(arrs)
-     	// I changed the inject and maps to an iterative approach to make it easier to implement in C++
-      loopStart = [[]]
-
-      for arr in arrs do
-        permutations = []
-        for e in arr do
-          for path in loopStart do
-            permutations.push(path + [e])
-          end
-        end
-        loopStart = permutations
-      end
-    end
-	*/
-  Node paths(const Node& arrs, Context& ctx) {
-    To_String to_string(&ctx);
-
-    Node loopStart = Node::createCollection();
-    loopStart.collection()->push_back(Node::createCollection());
-
-    for (NodeDeque::iterator arrsIter = arrs.collection()->begin(), arrsEndIter = arrs.collection()->end();
-    	arrsIter != arrsEndIter; ++arrsIter) {
-
-      Node& arr = *arrsIter;
-
-      Node permutations = Node::createCollection();
-
-      for (NodeDeque::iterator arrIter = arr.collection()->begin(), arrIterEnd = arr.collection()->end();
-      	arrIter != arrIterEnd; ++arrIter) {
-
-        Node& e = *arrIter;
-
-        for (NodeDeque::iterator loopStartIter = loopStart.collection()->begin(), loopStartIterEnd = loopStart.collection()->end();
-          loopStartIter != loopStartIterEnd; ++loopStartIter) {
-
-          Node& path = *loopStartIter;
-
-          Node newPermutation = Node::createCollection();
-          newPermutation.plus(path);
-          newPermutation.collection()->push_back(e);
-
-          permutations.collection()->push_back(newPermutation);
-        }
-      }
-
-      loopStart = permutations;
-    }
-
-    return loopStart;
-  }
-
-
-	/*
-  This is the equivalent of ruby sass' Sass::Util.flatten and [].flatten.
-  Sass::Util.flatten requires the number of levels to flatten, while
-  [].flatten doesn't and will flatten the entire array. This function
-  supports both.
-
-  # Flattens the first `n` nested arrays. If n == -1, all arrays will be flattened
-  #
-  # @param arr [NodeCollection] The array to flatten
-  # @param n [int] The number of levels to flatten
-  # @return [NodeCollection] The flattened array
-
-  The following is the modified version of the ruby code that was more portable to C++. You
-  should be able to drop it into ruby 3.2.19 and get the same results from ruby sass.
-
-  def flatten(arr, n = -1)
-    if n != -1 and n == 0 then
-      return arr
-    end
-
-    flattened = []
-
-    for e in arr do
-      if e.is_a?(Array) then
-        flattened.concat(flatten(e, n - 1))
-      else
-        flattened << e
-      end
-    end
-
-    return flattened
-  end
-  */
-  Node flatten(const Node& arr, Context& ctx, int n = -1) {
-    if (n != -1 && n == 0) {
-      return arr;
-    }
-
-    Node flattened = Node::createCollection();
-
-    for (NodeDeque::iterator iter = arr.collection()->begin(), iterEnd = arr.collection()->end();
-    	iter != iterEnd; iter++) {
-    	Node& e = *iter;
-
-      if (e.isCollection()) {
-      	Node recurseFlattened = flatten(e, ctx, n - 1);
-        flattened.collection()->insert(flattened.collection()->end(), recurseFlattened.collection()->begin(), recurseFlattened.collection()->end());
-      } else {
-      	flattened.collection()->push_back(e);
-      }
-    }
-
-    return flattened;
-  }
-}
diff --git a/libsass/sass_util.hpp b/libsass/sass_util.hpp
deleted file mode 100644
--- a/libsass/sass_util.hpp
+++ /dev/null
@@ -1,260 +0,0 @@
-#ifndef SASS_SASS_UTIL_H
-#define SASS_SASS_UTIL_H
-
-#include <deque>
-#include <iostream>
-
-#include "ast.hpp"
-#include "node.hpp"
-#include "debug.hpp"
-
-namespace Sass {
-
-
-  using namespace std;
-
-
-  /*
-   This is for ports of functions in the Sass:Util module.
-   */
-
-
-  /*
-    # Return a Node collection of all possible paths through the given Node collection of Node collections.
-    #
-    # @param arrs [NodeCollection<NodeCollection<Node>>]
-    # @return [NodeCollection<NodeCollection<Node>>]
-    #
-    # @example
-    #   paths([[1, 2], [3, 4], [5]]) #=>
-    #     # [[1, 3, 5],
-    #     #  [2, 3, 5],
-    #     #  [1, 4, 5],
-    #     #  [2, 4, 5]]
-  */
-  Node paths(const Node& arrs, Context& ctx);
-
-
-  /*
-  This class is a default implementation of a Node comparator that can be passed to the lcs function below.
-  It uses operator== for equality comparision. It then returns one if the Nodes are equal.
-  */
-  class DefaultLcsComparator {
-  public:
-    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) {
-        out = one;
-        return true;
-      }
-
-      return false;
-    }
-  };
-
-
-  typedef vector<vector<int> > LCSTable;
-
-
-  /*
-  This is the equivalent of ruby's Sass::Util.lcs_backtrace.
-
-  # Computes a single longest common subsequence for arrays x and y.
-  # Algorithm from http://en.wikipedia.org/wiki/Longest_common_subsequence_problem#Reading_out_an_LCS
-  */
-  template<typename ComparatorType>
-  Node lcs_backtrace(const LCSTable& c, const Node& x, const Node& y, int i, int j, const ComparatorType& comparator) {
-    DEBUG_PRINTLN(LCS, "LCSBACK: X=" << x << " Y=" << y << " I=" << i << " J=" << j)
-
-    if (i == 0 || j == 0) {
-      DEBUG_PRINTLN(LCS, "RETURNING EMPTY")
-      return Node::createCollection();
-    }
-
-    NodeDeque& xChildren = *(x.collection());
-    NodeDeque& yChildren = *(y.collection());
-
-    Node compareOut = Node::createNil();
-    if (comparator(xChildren[i], yChildren[j], compareOut)) {
-      DEBUG_PRINTLN(LCS, "RETURNING AFTER ELEM COMPARE")
-      Node result = lcs_backtrace(c, x, y, i - 1, j - 1, comparator);
-      result.collection()->push_back(compareOut);
-      return result;
-    }
-
-    if (c[i][j - 1] > c[i - 1][j]) {
-      DEBUG_PRINTLN(LCS, "RETURNING AFTER TABLE COMPARE")
-      return lcs_backtrace(c, x, y, i, j - 1, comparator);
-    }
-
-    DEBUG_PRINTLN(LCS, "FINAL RETURN")
-    return lcs_backtrace(c, x, y, i - 1, j, comparator);
-  }
-
-
-  /*
-  This is the equivalent of ruby's Sass::Util.lcs_table.
-
-  # Calculates the memoization table for the Least Common Subsequence algorithm.
-  # Algorithm from http://en.wikipedia.org/wiki/Longest_common_subsequence_problem#Computing_the_length_of_the_LCS
-  */
-  template<typename ComparatorType>
-  void lcs_table(const Node& x, const Node& y, const ComparatorType& comparator, LCSTable& out) {
-    DEBUG_PRINTLN(LCS, "LCSTABLE: X=" << x << " Y=" << y)
-
-    NodeDeque& xChildren = *(x.collection());
-    NodeDeque& yChildren = *(y.collection());
-
-    LCSTable c(xChildren.size(), vector<int>(yChildren.size()));
-
-    // These shouldn't be necessary since the vector will be initialized to 0 already.
-    // x.size.times {|i| c[i][0] = 0}
-    // y.size.times {|j| c[0][j] = 0}
-
-    for (size_t i = 1; i < xChildren.size(); i++) {
-      for (size_t j = 1; j < yChildren.size(); j++) {
-        Node compareOut = Node::createNil();
-
-        if (comparator(xChildren[i], yChildren[j], compareOut)) {
-          c[i][j] = c[i - 1][j - 1] + 1;
-        } else {
-          c[i][j] = max(c[i][j - 1], c[i - 1][j]);
-        }
-      }
-    }
-
-    out = c;
-  }
-
-
-  /*
-  This is the equivalent of ruby's Sass::Util.lcs.
-
-  # Computes a single longest common subsequence for `x` and `y`.
-  # If there are more than one longest common subsequences,
-  # the one returned is that which starts first in `x`.
-
-  # @param x [NodeCollection]
-  # @param y [NodeCollection]
-  # @comparator An equality check between elements of `x` and `y`.
-  # @return [NodeCollection] The LCS
-
-  http://en.wikipedia.org/wiki/Longest_common_subsequence_problem
-  */
-  template<typename ComparatorType>
-  Node lcs(Node& x, Node& y, const ComparatorType& comparator, Context& ctx) {
-    DEBUG_PRINTLN(LCS, "LCS: X=" << x << " Y=" << y)
-
-    Node newX = Node::createCollection();
-    newX.collection()->push_back(Node::createNil());
-    newX.plus(x);
-
-    Node newY = Node::createCollection();
-    newY.collection()->push_back(Node::createNil());
-    newY.plus(y);
-
-    LCSTable table;
-    lcs_table(newX, newY, comparator, table);
-
-    return lcs_backtrace(table, newX, newY, static_cast<int>(newX.collection()->size()) - 1, static_cast<int>(newY.collection()->size()) - 1, comparator);
-  }
-
-
-  /*
-  This is the equivalent of ruby sass' Sass::Util.flatten and [].flatten.
-  Sass::Util.flatten requires the number of levels to flatten, while
-  [].flatten doesn't and will flatten the entire array. This function
-  supports both.
-
-  # Flattens the first `n` nested arrays. If n == -1, all arrays will be flattened
-  #
-  # @param arr [NodeCollection] The array to flatten
-  # @param n [int] The number of levels to flatten
-  # @return [NodeCollection] The flattened array
-  */
-  Node flatten(const Node& arr, Context& ctx, int n = -1);
-
-
-  /*
-  This is the equivalent of ruby's Sass::Util.group_by_to_a.
-
-  # Performs the equivalent of `enum.group_by.to_a`, but with a guaranteed
-  # order. Unlike [#hash_to_a], the resulting order isn't sorted key order;
-  # instead, it's the same order as `#group_by` has under Ruby 1.9 (key
-  # appearance order).
-  #
-  # @param enum [Enumerable]
-  # @return [Array<[Object, Array]>] An array of pairs.
-
-  TODO: update @param and @return once I know what those are.
-
-  The following is the modified version of the ruby code that was more portable to C++. You
-  should be able to drop it into ruby 3.2.19 and get the same results from ruby sass.
-
-    def group_by_to_a(enum, &block)
-      order = {}
-
-      arr = []
-
-      grouped = {}
-
-      for e in enum do
-        key = block[e]
-        unless order.include?(key)
-          order[key] = order.size
-        end
-
-        if not grouped.has_key?(key) then
-          grouped[key] = [e]
-        else
-          grouped[key].push(e)
-        end
-      end
-
-      grouped.each do |key, vals|
-        arr[order[key]] = [key, vals]
-      end
-
-      arr
-    end
-
-  */
-  template<typename EnumType, typename KeyType, typename KeyFunctorType>
-  void group_by_to_a(vector<EnumType>& enumeration, KeyFunctorType& keyFunc, vector<pair<KeyType, vector<EnumType> > >& arr /*out*/) {
-
-    map<unsigned int, KeyType> order;
-
-    map<KeyType, vector<EnumType> > grouped;
-
-    for (typename 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()) {
-        order.insert(make_pair(order.size(), key));
-
-        vector<EnumType> newCollection;
-        newCollection.push_back(e);
-        grouped.insert(make_pair(key, newCollection));
-      } else {
-        vector<EnumType>& collection = grouped.at(key);
-        collection.push_back(e);
-      }
-    }
-
-    for (unsigned int index = 0; index < order.size(); index++) {
-      KeyType& key = order.at(index);
-      vector<EnumType>& values = grouped.at(key);
-
-      pair<KeyType, vector<EnumType> > grouping = make_pair(key, values);
-
-      arr.push_back(grouping);
-    }
-  }
-
-
-}
-
-#endif
diff --git a/libsass/sass_values.cpp b/libsass/sass_values.cpp
deleted file mode 100644
--- a/libsass/sass_values.cpp
+++ /dev/null
@@ -1,354 +0,0 @@
-#ifdef _WIN32
-#include <io.h>
-#else
-#include <unistd.h>
-#endif
-
-#include <cstdlib>
-#include <cstring>
-#include "util.hpp"
-#include "sass_values.h"
-
-extern "C" {
-  using namespace std;
-  using namespace Sass;
-
-  struct Sass_Unknown {
-    enum Sass_Tag tag;
-  };
-
-  struct Sass_Boolean {
-    enum Sass_Tag tag;
-    bool          value;
-  };
-
-  struct Sass_Number {
-    enum Sass_Tag tag;
-    double        value;
-    char*         unit;
-  };
-
-  struct Sass_Color {
-    enum Sass_Tag tag;
-    double        r;
-    double        g;
-    double        b;
-    double        a;
-  };
-
-  struct Sass_String {
-    enum Sass_Tag tag;
-    bool          quoted;
-    char*         value;
-  };
-
-  struct Sass_List {
-    enum Sass_Tag       tag;
-    enum Sass_Separator separator;
-    size_t              length;
-    // null terminated "array"
-    union Sass_Value**  values;
-  };
-
-  struct Sass_Map {
-    enum Sass_Tag        tag;
-    size_t               length;
-    struct Sass_MapPair* pairs;
-  };
-
-  struct Sass_Null {
-    enum Sass_Tag tag;
-  };
-
-  struct Sass_Error {
-    enum Sass_Tag tag;
-    char*         message;
-  };
-
-  struct Sass_Warning {
-    enum Sass_Tag tag;
-    char*         message;
-  };
-
-  union Sass_Value {
-    struct Sass_Unknown unknown;
-    struct Sass_Boolean boolean;
-    struct Sass_Number  number;
-    struct Sass_Color   color;
-    struct Sass_String  string;
-    struct Sass_List    list;
-    struct Sass_Map     map;
-    struct Sass_Null    null;
-    struct Sass_Error   error;
-    struct Sass_Warning   warning;
-  };
-
-  struct Sass_MapPair {
-    union Sass_Value* key;
-    union Sass_Value* value;
-  };
-
-  // Return the sass tag for a generic sass value
-  enum Sass_Tag ADDCALL sass_value_get_tag(const union Sass_Value* v) { return v->unknown.tag; }
-
-  // Check value for specified type
-  bool ADDCALL sass_value_is_null(const union Sass_Value* v) { return v->unknown.tag == SASS_NULL; }
-  bool ADDCALL sass_value_is_number(const union Sass_Value* v) { return v->unknown.tag == SASS_NUMBER; }
-  bool ADDCALL sass_value_is_string(const union Sass_Value* v) { return v->unknown.tag == SASS_STRING; }
-  bool ADDCALL sass_value_is_boolean(const union Sass_Value* v) { return v->unknown.tag == SASS_BOOLEAN; }
-  bool ADDCALL sass_value_is_color(const union Sass_Value* v) { return v->unknown.tag == SASS_COLOR; }
-  bool ADDCALL sass_value_is_list(const union Sass_Value* v) { return v->unknown.tag == SASS_LIST; }
-  bool ADDCALL sass_value_is_map(const union Sass_Value* v) { return v->unknown.tag == SASS_MAP; }
-  bool ADDCALL sass_value_is_error(const union Sass_Value* v) { return v->unknown.tag == SASS_ERROR; }
-  bool ADDCALL sass_value_is_warning(const union Sass_Value* v) { return v->unknown.tag == SASS_WARNING; }
-
-  // Getters and setters for Sass_Number
-  double ADDCALL sass_number_get_value(const union Sass_Value* v) { return v->number.value; }
-  void ADDCALL sass_number_set_value(union Sass_Value* v, double value) { v->number.value = value; }
-  const char* ADDCALL sass_number_get_unit(const union Sass_Value* v) { return v->number.unit; }
-  void ADDCALL sass_number_set_unit(union Sass_Value* v, char* unit) { v->number.unit = unit; }
-
-  // Getters and setters for Sass_String
-  const char* ADDCALL sass_string_get_value(const union Sass_Value* v) { return v->string.value; }
-  void ADDCALL sass_string_set_value(union Sass_Value* v, char* value) { v->string.value = value; }
-  bool ADDCALL sass_string_is_quoted(const union Sass_Value* v) { return v->string.quoted; }
-  void ADDCALL sass_string_set_quoted(union Sass_Value* v, bool quoted) { v->string.quoted = quoted; }
-
-  // Getters and setters for Sass_Boolean
-  bool ADDCALL sass_boolean_get_value(const union Sass_Value* v) { return v->boolean.value; }
-  void ADDCALL sass_boolean_set_value(union Sass_Value* v, bool value) { v->boolean.value = value; }
-
-  // Getters and setters for Sass_Color
-  double ADDCALL sass_color_get_r(const union Sass_Value* v) { return v->color.r; }
-  void ADDCALL sass_color_set_r(union Sass_Value* v, double r) { v->color.r = r; }
-  double ADDCALL sass_color_get_g(const union Sass_Value* v) { return v->color.g; }
-  void ADDCALL sass_color_set_g(union Sass_Value* v, double g) { v->color.g = g; }
-  double ADDCALL sass_color_get_b(const union Sass_Value* v) { return v->color.b; }
-  void ADDCALL sass_color_set_b(union Sass_Value* v, double b) { v->color.b = b; }
-  double ADDCALL sass_color_get_a(const union Sass_Value* v) { return v->color.a; }
-  void ADDCALL sass_color_set_a(union Sass_Value* v, double a) { v->color.a = a; }
-
-  // Getters and setters for Sass_List
-  size_t ADDCALL sass_list_get_length(const union Sass_Value* v) { return v->list.length; }
-  enum Sass_Separator ADDCALL sass_list_get_separator(const union Sass_Value* v) { return v->list.separator; }
-  void ADDCALL sass_list_set_separator(union Sass_Value* v, enum Sass_Separator separator) { v->list.separator = separator; }
-  // Getters and setters for Sass_List values
-  union Sass_Value* ADDCALL sass_list_get_value(const union Sass_Value* v, size_t i) { return v->list.values[i]; }
-  void ADDCALL sass_list_set_value(union Sass_Value* v, size_t i, union Sass_Value* value) { v->list.values[i] = value; }
-
-  // Getters and setters for Sass_Map
-  size_t ADDCALL sass_map_get_length(const union Sass_Value* v) { return v->map.length; }
-  // Getters and setters for Sass_List keys and values
-  union Sass_Value* ADDCALL sass_map_get_key(const union Sass_Value* v, size_t i) { return v->map.pairs[i].key; }
-  union Sass_Value* ADDCALL sass_map_get_value(const union Sass_Value* v, size_t i) { return v->map.pairs[i].value; }
-  void ADDCALL sass_map_set_key(union Sass_Value* v, size_t i, union Sass_Value* key) { v->map.pairs[i].key = key; }
-  void ADDCALL sass_map_set_value(union Sass_Value* v, size_t i, union Sass_Value* val) { v->map.pairs[i].value = val; }
-
-  // Getters and setters for Sass_Error
-  char* ADDCALL sass_error_get_message(const union Sass_Value* v) { return v->error.message; };
-  void ADDCALL sass_error_set_message(union Sass_Value* v, char* msg) { v->error.message = msg; };
-
-  // Getters and setters for Sass_Warning
-  char* ADDCALL sass_warning_get_message(const union Sass_Value* v) { return v->warning.message; };
-  void ADDCALL sass_warning_set_message(union Sass_Value* v, char* msg) { v->warning.message = msg; };
-
-  // Creator functions for all value types
-
-  union Sass_Value* ADDCALL sass_make_boolean(bool val)
-  {
-    Sass_Value* v = (Sass_Value*) calloc(1, sizeof(Sass_Value));
-    if (v == 0) return 0;
-    v->boolean.tag = SASS_BOOLEAN;
-    v->boolean.value = val;
-    return v;
-  }
-
-  union Sass_Value* ADDCALL sass_make_number(double val, const char* unit)
-  {
-    Sass_Value* v = (Sass_Value*) calloc(1, sizeof(Sass_Value));
-    if (v == 0) return 0;
-    v->number.tag = SASS_NUMBER;
-    v->number.value = val;
-    v->number.unit = unit ? sass_strdup(unit) : 0;
-    if (v->number.unit == 0) { free(v); return 0; }
-    return v;
-  }
-
-  union Sass_Value* ADDCALL sass_make_color(double r, double g, double b, double a)
-  {
-    Sass_Value* v = (Sass_Value*) calloc(1, sizeof(Sass_Value));
-    if (v == 0) return 0;
-    v->color.tag = SASS_COLOR;
-    v->color.r = r;
-    v->color.g = g;
-    v->color.b = b;
-    v->color.a = a;
-    return v;
-  }
-
-  union Sass_Value* ADDCALL sass_make_string(const char* val)
-  {
-    Sass_Value* v = (Sass_Value*) calloc(1, sizeof(Sass_Value));
-    if (v == 0) return 0;
-    v->string.quoted = false;
-    v->string.tag = SASS_STRING;
-    v->string.value = val ? sass_strdup(val) : 0;
-    if (v->string.value == 0) { free(v); return 0; }
-    return v;
-  }
-
-  union Sass_Value* ADDCALL sass_make_qstring(const char* val)
-  {
-    Sass_Value* v = (Sass_Value*) calloc(1, sizeof(Sass_Value));
-    if (v == 0) return 0;
-    v->string.quoted = true;
-    v->string.tag = SASS_STRING;
-    v->string.value = val ? sass_strdup(val) : 0;
-    if (v->string.value == 0) { free(v); return 0; }
-    return v;
-  }
-
-  union Sass_Value* ADDCALL sass_make_list(size_t len, enum Sass_Separator sep)
-  {
-    Sass_Value* v = (Sass_Value*) calloc(1, sizeof(Sass_Value));
-    if (v == 0) return 0;
-    v->list.tag = SASS_LIST;
-    v->list.length = len;
-    v->list.separator = sep;
-    v->list.values = (union Sass_Value**) calloc(len, sizeof(union Sass_Value));
-    if (v->list.values == 0) { free(v); return 0; }
-    return v;
-  }
-
-  union Sass_Value* ADDCALL sass_make_map(size_t len)
-  {
-    Sass_Value* v = (Sass_Value*) calloc(1, sizeof(Sass_Value));
-    if (v == 0) return 0;
-    v->map.tag = SASS_MAP;
-    v->map.length = len;
-    v->map.pairs = (struct Sass_MapPair*) calloc(len, sizeof(struct Sass_MapPair));
-    if (v->map.pairs == 0) { free(v); return 0; }
-    return v;
-  }
-
-  union Sass_Value* ADDCALL sass_make_null(void)
-  {
-    Sass_Value* v = (Sass_Value*) calloc(1, sizeof(Sass_Value));
-    if (v == 0) return 0;
-    v->null.tag = SASS_NULL;
-    return v;
-  }
-
-  union Sass_Value* ADDCALL sass_make_error(const char* msg)
-  {
-    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;
-    if (v->error.message == 0) { free(v); return 0; }
-    return v;
-  }
-
-  union Sass_Value* ADDCALL sass_make_warning(const char* msg)
-  {
-    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;
-    if (v->warning.message == 0) { free(v); return 0; }
-    return v;
-  }
-
-  // will free all associated sass values
-  void ADDCALL sass_delete_value(union Sass_Value* val) {
-
-    size_t i;
-    if (val == 0) return;
-    switch(val->unknown.tag) {
-        case SASS_NULL: {
-        }   break;
-        case SASS_BOOLEAN: {
-        }   break;
-        case SASS_NUMBER: {
-                free(val->number.unit);
-        }   break;
-        case SASS_COLOR: {
-        }   break;
-        case SASS_STRING: {
-                free(val->string.value);
-        }   break;
-        case SASS_LIST: {
-                for (i=0; i<val->list.length; i++) {
-                    sass_delete_value(val->list.values[i]);
-                }
-                free(val->list.values);
-        }   break;
-        case SASS_MAP: {
-                for (i=0; i<val->map.length; i++) {
-                    sass_delete_value(val->map.pairs[i].key);
-                    sass_delete_value(val->map.pairs[i].value);
-                }
-                free(val->map.pairs);
-        }   break;
-        case SASS_ERROR: {
-                free(val->error.message);
-        }   break;
-        case SASS_WARNING: {
-                free(val->error.message);
-        }   break;
-    }
-
-    free(val);
-
-    }
-
-  // Make a deep cloned copy of the given sass value
-  union Sass_Value* ADDCALL sass_clone_value (const union Sass_Value* val)
-  {
-
-    size_t i;
-    if (val == 0) return 0;
-    switch(val->unknown.tag) {
-        case SASS_NULL: {
-                return sass_make_null();
-        }   break;
-        case SASS_BOOLEAN: {
-                return sass_make_boolean(val->boolean.value);
-        }   break;
-        case SASS_NUMBER: {
-                return sass_make_number(val->number.value, val->number.unit);
-        }   break;
-        case SASS_COLOR: {
-                return sass_make_color(val->color.r, val->color.g, val->color.b, val->color.a);
-        }   break;
-        case SASS_STRING: {
-                return sass_make_string(val->string.value);
-        }   break;
-        case SASS_LIST: {
-                union Sass_Value* list = sass_make_list(val->list.length, val->list.separator);
-                for (i = 0; i < list->list.length; i++) {
-                    list->list.values[i] = sass_clone_value(val->list.values[i]);
-                }
-                return list;
-        }   break;
-        case SASS_MAP: {
-                union Sass_Value* map = sass_make_map(val->map.length);
-                for (i = 0; i < val->map.length; i++) {
-                    map->map.pairs[i].key = sass_clone_value(val->map.pairs[i].key);
-                    map->map.pairs[i].value = sass_clone_value(val->map.pairs[i].value);
-                }
-                return map;
-        }   break;
-        case SASS_ERROR: {
-                return sass_make_error(val->error.message);
-        }   break;
-        case SASS_WARNING: {
-                return sass_make_warning(val->warning.message);
-        }   break;
-    }
-
-    return 0;
-
-  }
-
-}
diff --git a/libsass/sass_values.h b/libsass/sass_values.h
deleted file mode 100644
--- a/libsass/sass_values.h
+++ /dev/null
@@ -1,127 +0,0 @@
-#ifndef SASS_C_VALUES_H
-#define SASS_C_VALUES_H
-
-#include <stddef.h>
-#include <stdbool.h>
-#include "sass.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-// Forward declaration
-union Sass_Value;
-
-// Type for Sass values
-enum Sass_Tag {
-  SASS_BOOLEAN,
-  SASS_NUMBER,
-  SASS_COLOR,
-  SASS_STRING,
-  SASS_LIST,
-  SASS_MAP,
-  SASS_NULL,
-  SASS_ERROR,
-  SASS_WARNING
-};
-
-// Tags for denoting Sass list separators
-enum Sass_Separator {
-  SASS_COMMA,
-  SASS_SPACE
-};
-
-// 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);
-
-// Check value to be of a specific type
-// Can also be used before accessing properties!
-ADDAPI bool ADDCALL sass_value_is_null (const union Sass_Value* v);
-ADDAPI bool ADDCALL sass_value_is_number (const union Sass_Value* v);
-ADDAPI bool ADDCALL sass_value_is_string (const union Sass_Value* v);
-ADDAPI bool ADDCALL sass_value_is_boolean (const union Sass_Value* v);
-ADDAPI bool ADDCALL sass_value_is_color (const union Sass_Value* v);
-ADDAPI bool ADDCALL sass_value_is_list (const union Sass_Value* v);
-ADDAPI bool ADDCALL sass_value_is_map (const union Sass_Value* v);
-ADDAPI bool ADDCALL sass_value_is_error (const union Sass_Value* v);
-ADDAPI bool ADDCALL sass_value_is_warning (const union Sass_Value* v);
-
-// Getters and setters for Sass_Number
-ADDAPI double ADDCALL sass_number_get_value (const union Sass_Value* v);
-ADDAPI void ADDCALL sass_number_set_value (union Sass_Value* v, double value);
-ADDAPI const char* ADDCALL sass_number_get_unit (const union Sass_Value* v);
-ADDAPI void ADDCALL sass_number_set_unit (union Sass_Value* v, char* unit);
-
-// Getters and setters for Sass_String
-ADDAPI const char* ADDCALL sass_string_get_value (const union Sass_Value* v);
-ADDAPI void ADDCALL sass_string_set_value (union Sass_Value* v, char* value);
-ADDAPI bool ADDCALL sass_string_is_quoted(const union Sass_Value* v);
-ADDAPI void ADDCALL sass_string_set_quoted(union Sass_Value* v, bool quoted);
-
-// Getters and setters for Sass_Boolean
-ADDAPI bool ADDCALL sass_boolean_get_value (const union Sass_Value* v);
-ADDAPI void ADDCALL sass_boolean_set_value (union Sass_Value* v, bool value);
-
-// Getters and setters for Sass_Color
-ADDAPI double ADDCALL sass_color_get_r (const union Sass_Value* v);
-ADDAPI void ADDCALL sass_color_set_r (union Sass_Value* v, double r);
-ADDAPI double ADDCALL sass_color_get_g (const union Sass_Value* v);
-ADDAPI void ADDCALL sass_color_set_g (union Sass_Value* v, double g);
-ADDAPI double ADDCALL sass_color_get_b (const union Sass_Value* v);
-ADDAPI void ADDCALL sass_color_set_b (union Sass_Value* v, double b);
-ADDAPI double ADDCALL sass_color_get_a (const union Sass_Value* v);
-ADDAPI void ADDCALL sass_color_set_a (union Sass_Value* v, double a);
-
-// Getter for the number of items in list
-ADDAPI size_t ADDCALL sass_list_get_length (const union Sass_Value* v);
-// Getters and setters for Sass_List
-ADDAPI enum Sass_Separator ADDCALL sass_list_get_separator (const union Sass_Value* v);
-ADDAPI void ADDCALL sass_list_set_separator (union Sass_Value* v, enum Sass_Separator value);
-// Getters and setters for Sass_List values
-ADDAPI union Sass_Value* ADDCALL sass_list_get_value (const union Sass_Value* v, size_t i);
-ADDAPI void ADDCALL sass_list_set_value (union Sass_Value* v, size_t i, union Sass_Value* value);
-
-// Getter for the number of items in map
-ADDAPI size_t ADDCALL sass_map_get_length (const union Sass_Value* v);
-// Getters and setters for Sass_Map keys and values
-ADDAPI union Sass_Value* ADDCALL sass_map_get_key (const union Sass_Value* v, size_t i);
-ADDAPI void ADDCALL sass_map_set_key (union Sass_Value* v, size_t i, union Sass_Value*);
-ADDAPI union Sass_Value* ADDCALL sass_map_get_value (const union Sass_Value* v, size_t i);
-ADDAPI void ADDCALL sass_map_set_value (union Sass_Value* v, size_t i, union Sass_Value*);
-
-// Getters and setters for Sass_Error
-ADDAPI char* ADDCALL sass_error_get_message (const union Sass_Value* v);
-ADDAPI void ADDCALL sass_error_set_message (union Sass_Value* v, char* msg);
-
-// 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);
-
-
-#ifdef __cplusplus
-} // __cplusplus defined.
-#endif
-
-#endif
diff --git a/libsass/sass_version.h b/libsass/sass_version.h
deleted file mode 100644
--- a/libsass/sass_version.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef SASS_VERSION_H
-#define SASS_VERSION_H
-
-#ifndef LIBSASS_VERSION
-#define LIBSASS_VERSION "[NA]"
-#endif
-
-#endif
diff --git a/libsass/source_map.cpp b/libsass/source_map.cpp
deleted file mode 100644
--- a/libsass/source_map.cpp
+++ /dev/null
@@ -1,184 +0,0 @@
-#include <string>
-#include <sstream>
-#include <iostream>
-#include <cstddef>
-#include <iomanip>
-
-#include "ast.hpp"
-#include "json.hpp"
-#include "context.hpp"
-#include "position.hpp"
-#include "source_map.hpp"
-
-namespace Sass {
-  using std::ptrdiff_t;
-  SourceMap::SourceMap() : current_position(0, 0, 0), file("stdin") { }
-  SourceMap::SourceMap(const string& file) : current_position(0, 0, 0), file(file) { }
-
-  string SourceMap::generate_source_map(Context &ctx) {
-
-    const bool include_sources = ctx.source_map_contents;
-    const vector<string> includes = ctx.include_links;
-    const vector<const char*> sources = ctx.sources;
-
-    JsonNode* json_srcmap = json_mkobject();
-
-    json_append_member(json_srcmap, "version", json_mknumber(3));
-
-    // 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 = includes[source_index[i]].c_str();
-      JsonNode *json_include = json_mkstring(include);
-      json_append_element(json_includes, json_include);
-    }
-    json_append_member(json_srcmap, "sources", json_includes);
-
-    JsonNode *json_contents = json_mkarray();
-    if (include_sources) {
-      for (size_t i = 0; i < source_index.size(); ++i) {
-        const char *content = sources[source_index[i]];
-        JsonNode *json_content = json_mkstring(content);
-        json_append_element(json_contents, json_content);
-      }
-    }
-    json_append_member(json_srcmap, "sourcesContent", json_contents);
-
-    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);
-
-    char *str = json_stringify(json_srcmap, "\t");
-    string result = string(str);
-    free(str);
-    json_delete(json_srcmap);
-    return result;
-  }
-
-  string SourceMap::serialize_mappings() {
-    string result = "";
-
-    size_t previous_generated_line = 0;
-    size_t previous_generated_column = 0;
-    size_t previous_original_line = 0;
-    size_t previous_original_column = 0;
-    size_t previous_original_file = 0;
-    for (size_t i = 0; i < mappings.size(); ++i) {
-      const size_t generated_line = mappings[i].generated_position.line;
-      const size_t generated_column = mappings[i].generated_position.column;
-      const size_t original_line = mappings[i].original_position.line;
-      const size_t original_column = mappings[i].original_position.column;
-      const size_t original_file = mappings[i].original_position.file;
-
-      if (generated_line != previous_generated_line) {
-        previous_generated_column = 0;
-        if (generated_line > previous_generated_line) {
-          result += std::string(generated_line - previous_generated_line, ';');
-          previous_generated_line = generated_line;
-        }
-      }
-      else if (i > 0) {
-        result += ",";
-      }
-
-      // generated column
-      result += base64vlq.encode(static_cast<int>(generated_column) - static_cast<int>(previous_generated_column));
-      previous_generated_column = generated_column;
-      // file
-      result += base64vlq.encode(static_cast<int>(original_file) - static_cast<int>(previous_original_file));
-      previous_original_file = original_file;
-      // source line
-      result += base64vlq.encode(static_cast<int>(original_line) - static_cast<int>(previous_original_line));
-      previous_original_line = original_line;
-      // source column
-      result += base64vlq.encode(static_cast<int>(original_column) - static_cast<int>(previous_original_column));
-      previous_original_column = original_column;
-    }
-
-    return result;
-  }
-
-  void SourceMap::prepend(const OutputBuffer& out)
-  {
-    Offset size(out.smap.current_position);
-    for (Mapping mapping : out.smap.mappings) {
-      if (mapping.generated_position.line > size.line) {
-        throw(runtime_error("prepend sourcemap has illegal line"));
-      }
-      if (mapping.generated_position.line == size.line) {
-        if (mapping.generated_position.column > size.column) {
-          throw(runtime_error("prepend sourcemap has illegal column"));
-        }
-      }
-    }
-    // will adjust the offset
-    prepend(Offset(out.buffer));
-    // now add the new mappings
-    VECTOR_UNSHIFT(mappings, out.smap.mappings);
-  }
-
-  void SourceMap::append(const OutputBuffer& out)
-  {
-    append(Offset(out.buffer));
-  }
-
-  void SourceMap::prepend(const Offset& offset)
-  {
-    if (offset.line != 0 || offset.column != 0) {
-      for (Mapping& mapping : mappings) {
-        // move stuff on the first old line
-        if (mapping.generated_position.line == 0) {
-          mapping.generated_position.column += offset.column;
-        }
-        // make place for the new lines
-        mapping.generated_position.line += offset.line;
-      }
-    }
-    if (current_position.line == 0) {
-      current_position.column += offset.column;
-    }
-    current_position.line += offset.line;
-  }
-
-  void SourceMap::append(const Offset& offset)
-  {
-    current_position += offset;
-  }
-
-  void SourceMap::add_open_mapping(AST_Node* node)
-  {
-    mappings.push_back(Mapping(node->pstate(), current_position));
-  }
-
-  void SourceMap::add_close_mapping(AST_Node* node)
-  {
-    mappings.push_back(Mapping(node->pstate() + node->pstate().offset, current_position));
-  }
-
-  ParserState SourceMap::remap(const ParserState& pstate) {
-    for (size_t i = 0; i < mappings.size(); ++i) {
-      if (
-        mappings[i].generated_position.file == pstate.file &&
-        mappings[i].generated_position.line == pstate.line &&
-        mappings[i].generated_position.column == pstate.column
-      ) return ParserState(pstate.path, pstate.src, mappings[i].original_position, pstate.offset);
-    }
-    return ParserState(pstate.path, pstate.src, Position(-1, -1, -1), Offset(0, 0));
-
-  }
-
-}
diff --git a/libsass/source_map.hpp b/libsass/source_map.hpp
deleted file mode 100644
--- a/libsass/source_map.hpp
+++ /dev/null
@@ -1,65 +0,0 @@
-#ifndef SASS_SOURCE_MAP_H
-#define SASS_SOURCE_MAP_H
-
-#include <vector>
-
-#include "ast_fwd_decl.hpp"
-#include "base64vlq.hpp"
-#include "position.hpp"
-#include "mapping.hpp"
-
-#define VECTOR_PUSH(vec, ins) vec.insert(vec.end(), ins.begin(), ins.end())
-#define VECTOR_UNSHIFT(vec, ins) vec.insert(vec.begin(), ins.begin(), ins.end())
-
-namespace Sass {
-  using std::vector;
-
-  class Context;
-  class OutputBuffer;
-
-  class SourceMap {
-
-  public:
-    vector<size_t> source_index;
-    SourceMap();
-    SourceMap(const string& file);
-
-    void setFile(const string& str) {
-      file = str;
-    }
-    void append(const Offset& offset);
-    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);
-
-    string generate_source_map(Context &ctx);
-    ParserState remap(const ParserState& pstate);
-
-  private:
-
-    string serialize_mappings();
-
-    vector<Mapping> mappings;
-    Position current_position;
-public:
-    string file;
-private:
-    Base64VLQ base64vlq;
-  };
-
-  class OutputBuffer {
-    public:
-      OutputBuffer(void)
-      : buffer(""),
-        smap()
-      { }
-    public:
-      string buffer;
-      SourceMap smap;
-  };
-
-}
-
-#endif
diff --git a/libsass/src/GNUmakefile.am b/libsass/src/GNUmakefile.am
new file mode 100644
--- /dev/null
+++ b/libsass/src/GNUmakefile.am
@@ -0,0 +1,54 @@
+ACLOCAL_AMFLAGS = ${ACLOCAL_FLAGS} -I m4 -I script
+
+AM_COPT = -Wall -O2
+AM_COVLDFLAGS =
+
+if ENABLE_COVERAGE
+	AM_COPT = -O0 --coverage
+	AM_COVLDFLAGS += -lgcov
+endif
+
+AM_CPPFLAGS = -I$(top_srcdir)/include
+AM_CFLAGS   = $(AM_COPT)
+AM_CXXFLAGS = $(AM_COPT)
+AM_LDFLAGS  = $(AM_COPT) $(AM_COVLDFLAGS)
+
+if COMPILER_IS_MINGW32
+  AM_CXXFLAGS += -std=gnu++0x
+else
+  AM_CXXFLAGS += -std=c++0x
+endif
+
+EXTRA_DIST = \
+	COPYING \
+	INSTALL \
+	LICENSE \
+	Readme.md
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = support/libsass.pc
+
+lib_LTLIBRARIES = libsass.la
+
+include $(top_srcdir)/Makefile.conf
+
+libsass_la_SOURCES = ${CSOURCES} ${SOURCES}
+
+libsass_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined -version-info 0:9:0
+
+if ENABLE_TESTS
+if ENABLE_COVERAGE
+nodist_EXTRA_libsass_la_SOURCES = non-existent-file-to-force-CXX-linking.cxx
+endif
+endif
+
+include_HEADERS = $(top_srcdir)/include/sass.h \
+                  $(top_srcdir)/include/sass2scss.h
+
+sass_includedir = $(includedir)/sass
+
+sass_include_HEADERS = $(top_srcdir)/include/sass/base.h \
+                       $(top_srcdir)/include/sass/values.h \
+                       $(top_srcdir)/include/sass/version.h \
+                       $(top_srcdir)/include/sass/context.h \
+                       $(top_srcdir)/include/sass/functions.h
diff --git a/libsass/src/ast.cpp b/libsass/src/ast.cpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/ast.cpp
@@ -0,0 +1,2134 @@
+#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];
+    }
+  }
+
+}
+
diff --git a/libsass/src/ast.hpp b/libsass/src/ast.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/ast.hpp
@@ -0,0 +1,2347 @@
+#ifndef SASS_AST_H
+#define SASS_AST_H
+
+#include <set>
+#include <deque>
+#include <vector>
+#include <string>
+#include <sstream>
+#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); } };
+
+}
+
+#ifdef __clang__
+
+#pragma clang diagnostic pop
+
+#endif
+
+#endif
diff --git a/libsass/src/ast_def_macros.hpp b/libsass/src/ast_def_macros.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/ast_def_macros.hpp
@@ -0,0 +1,55 @@
+#ifndef SASS_AST_DEF_MACROS_H
+#define SASS_AST_DEF_MACROS_H
+
+// Helper class to switch a flag and revert once we go out of scope
+template <class T>
+class LocalOption {
+  private:
+    T* var; // pointer to original variable
+    T orig; // copy of the original option
+  public:
+    LocalOption(T& var)
+    {
+      this->var = &var;
+      this->orig = var;
+    }
+    LocalOption(T& var, T orig)
+    {
+      this->var = &var;
+      this->orig = var;
+      *(this->var) = orig;
+    }
+    ~LocalOption() {
+      *(this->var) = this->orig;
+    }
+};
+
+#define LOCAL_FLAG(name,opt) LocalOption<bool> flag_##name(name, opt)
+
+#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 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); }
+
+#define ADD_PROPERTY(type, name)\
+protected:\
+  type name##_;\
+public:\
+  type name() const        { return name##_; }\
+  type name(type name##__) { return name##_ = name##__; }\
+private:
+
+#define ADD_HASHED(type, name)\
+protected:\
+  type name##_;\
+public:\
+  type name() const        { return name##_; }\
+  type name(type name##__) { hash_ = 0; return name##_ = name##__; }\
+private:
+
+#endif
diff --git a/libsass/src/ast_factory.hpp b/libsass/src/ast_factory.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/ast_factory.hpp
@@ -0,0 +1,93 @@
+#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
new file mode 100644
--- /dev/null
+++ b/libsass/src/ast_fwd_decl.hpp
@@ -0,0 +1,91 @@
+#ifndef SASS_AST_FWD_DECL_H
+#define SASS_AST_FWD_DECL_H
+
+/////////////////////////////////////////////
+// Forward declarations for the AST visitors.
+/////////////////////////////////////////////
+namespace Sass {
+
+  class AST_Node;
+  // statements
+  class Statement;
+  class Block;
+  class Ruleset;
+  class Propset;
+  class Bubble;
+  class Media_Block;
+  class Supports_Block;
+  class At_Rule;
+  class Keyframe_Rule;
+  class At_Root_Block;
+  class Declaration;
+  class Assignment;
+  class Import;
+  class Import_Stub;
+  class Warning;
+  class Error;
+  class Debug;
+  class Comment;
+  class If;
+  class For;
+  class Each;
+  class While;
+  class Return;
+  class Content;
+  class Extension;
+  class Definition;
+  class Mixin_Call;
+  // expressions
+  class Value;
+  class Expression;
+  class List;
+  class Map;
+  class Binary_Expression;
+  class Unary_Expression;
+  class Function_Call;
+  class Function_Call_Schema;
+  class Custom_Warning;
+  class Custom_Error;
+  class Variable;
+  class Textual;
+  class Number;
+  class Color;
+  class Boolean;
+  class String_Schema;
+  class String;
+  class String_Constant;
+  class String_Quoted;
+  class Media_Query;
+  class Media_Query_Expression;
+  class Supports_Condition;
+  class Supports_Operator;
+  class Supports_Negation;
+  class Supports_Declaration;
+  class Supports_Interpolation;
+  class At_Root_Expression;
+  class Null;
+  class Parent_Selector;
+  // parameters and arguments
+  class Parameter;
+  class Parameters;
+  class Argument;
+  class Arguments;
+  // selectors
+  class Selector;
+  class Selector_Schema;
+  class Selector_Placeholder;
+  class Type_Selector;
+  class Selector_Qualifier;
+  class Attribute_Selector;
+  class Pseudo_Selector;
+  class Wrapped_Selector;
+  class Compound_Selector;
+  class Complex_Selector;
+  class Selector_List;
+
+  // common classes
+  class Context;
+
+}
+
+#endif
diff --git a/libsass/src/b64/cencode.h b/libsass/src/b64/cencode.h
new file mode 100644
--- /dev/null
+++ b/libsass/src/b64/cencode.h
@@ -0,0 +1,32 @@
+/*
+cencode.h - c header for a base64 encoding algorithm
+
+This is part of the libb64 project, and has been placed in the public domain.
+For details, see http://sourceforge.net/projects/libb64
+*/
+
+#ifndef BASE64_CENCODE_H
+#define BASE64_CENCODE_H
+
+typedef enum
+{
+  step_A, step_B, step_C
+} base64_encodestep;
+
+typedef struct
+{
+	base64_encodestep step;
+	char result;
+	int stepcount;
+} base64_encodestate;
+
+void base64_init_encodestate(base64_encodestate* state_in);
+
+char base64_encode_value(char value_in);
+
+int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in);
+
+int base64_encode_blockend(char* code_out, base64_encodestate* state_in);
+
+#endif /* BASE64_CENCODE_H */
+
diff --git a/libsass/src/b64/encode.h b/libsass/src/b64/encode.h
new file mode 100644
--- /dev/null
+++ b/libsass/src/b64/encode.h
@@ -0,0 +1,77 @@
+// :mode=c++:
+/*
+encode.h - c++ wrapper for a base64 encoding algorithm
+
+This is part of the libb64 project, and has been placed in the public domain.
+For details, see http://sourceforge.net/projects/libb64
+*/
+#ifndef BASE64_ENCODE_H
+#define BASE64_ENCODE_H
+
+#include <iostream>
+
+namespace base64
+{
+	extern "C"
+	{
+		#include "cencode.h"
+	}
+
+	struct encoder
+	{
+		base64_encodestate _state;
+		int _buffersize;
+
+		encoder(int buffersize_in = BUFFERSIZE)
+		: _buffersize(buffersize_in)
+		{}
+
+		int encode(char value_in)
+		{
+			return base64_encode_value(value_in);
+		}
+
+		int encode(const char* code_in, const int length_in, char* plaintext_out)
+		{
+			return base64_encode_block(code_in, length_in, plaintext_out, &_state);
+		}
+
+		int encode_end(char* plaintext_out)
+		{
+			return base64_encode_blockend(plaintext_out, &_state);
+		}
+
+		void encode(std::istream& istream_in, std::ostream& ostream_in)
+		{
+			base64_init_encodestate(&_state);
+			//
+			const int N = _buffersize;
+			char* plaintext = new char[N];
+			char* code = new char[2*N];
+			int plainlength;
+			int codelength;
+
+			do
+			{
+				istream_in.read(plaintext, N);
+				plainlength = static_cast<int>(istream_in.gcount());
+				//
+				codelength = encode(plaintext, plainlength, code);
+				ostream_in.write(code, codelength);
+			}
+			while (istream_in.good() && plainlength > 0);
+
+			codelength = encode_end(code);
+			ostream_in.write(code, codelength);
+			//
+			base64_init_encodestate(&_state);
+
+			delete [] code;
+			delete [] plaintext;
+		}
+	};
+
+} // namespace base64
+
+#endif // BASE64_ENCODE_H
+
diff --git a/libsass/src/backtrace.hpp b/libsass/src/backtrace.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/backtrace.hpp
@@ -0,0 +1,76 @@
+#ifndef SASS_BACKTRACE_H
+#define SASS_BACKTRACE_H
+
+#include <sstream>
+
+#include "file.hpp"
+#include "position.hpp"
+
+namespace Sass {
+
+
+  struct Backtrace {
+
+    Backtrace*  parent;
+    ParserState pstate;
+    std::string      caller;
+
+    Backtrace(Backtrace* prn, ParserState pstate, std::string c)
+    : parent(prn),
+      pstate(pstate),
+      caller(c)
+    { }
+
+    std::string to_string(bool warning = false)
+    {
+      size_t i = -1;
+      std::stringstream ss;
+      std::string cwd(Sass::File::get_cwd());
+      Backtrace* this_point = this;
+
+      if (!warning) ss << std::endl << "Backtrace:";
+      // the first tracepoint (which is parent-less) is an empty placeholder
+      while (this_point->parent) {
+
+        // make path relative to the current directory
+        std::string rel_path(Sass::File::abs2rel(this_point->pstate.path, cwd, cwd));
+
+        if (warning) {
+          ss << std::endl
+             << "\t"
+             << (++i == 0 ? "on" : "from")
+             << " line "
+             << this_point->pstate.line + 1
+             << " of "
+             << rel_path;
+        } else {
+          ss << std::endl
+             << "\t"
+             << rel_path
+             << ":"
+             << this_point->pstate.line + 1
+             << this_point->parent->caller;
+        }
+
+        this_point = this_point->parent;
+      }
+
+      return ss.str();
+    }
+
+    size_t depth()
+    {
+      size_t d = 0;
+      Backtrace* p = parent;
+      while (p) {
+        ++d;
+        p = p->parent;
+      }
+      return d-1;
+    }
+
+  };
+
+}
+
+#endif
diff --git a/libsass/src/base64vlq.cpp b/libsass/src/base64vlq.cpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/base64vlq.cpp
@@ -0,0 +1,43 @@
+#include "base64vlq.hpp"
+
+namespace Sass {
+
+  std::string Base64VLQ::encode(const int number) const
+  {
+    std::string encoded = "";
+
+    int vlq = to_vlq_signed(number);
+
+    do {
+      int digit = vlq & VLQ_BASE_MASK;
+      vlq >>= VLQ_BASE_SHIFT;
+      if (vlq > 0) {
+        digit |= VLQ_CONTINUATION_BIT;
+      }
+      encoded += base64_encode(digit);
+    } while (vlq > 0);
+
+    return encoded;
+  }
+
+  char Base64VLQ::base64_encode(const int number) const
+  {
+    int index = number;
+    if (index < 0) index = 0;
+    if (index > 63) index = 63;
+    return CHARACTERS[index];
+  }
+
+  int Base64VLQ::to_vlq_signed(const int number) const
+  {
+    return (number < 0) ? ((-number) << 1) + 1 : (number << 1) + 0;
+  }
+
+  const char* Base64VLQ::CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+  const int Base64VLQ::VLQ_BASE_SHIFT = 5;
+  const int Base64VLQ::VLQ_BASE = 1 << VLQ_BASE_SHIFT;
+  const int Base64VLQ::VLQ_BASE_MASK = VLQ_BASE - 1;
+  const int Base64VLQ::VLQ_CONTINUATION_BIT = VLQ_BASE;
+
+}
diff --git a/libsass/src/base64vlq.hpp b/libsass/src/base64vlq.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/base64vlq.hpp
@@ -0,0 +1,30 @@
+#ifndef SASS_BASE64VLQ_H
+#define SASS_BASE64VLQ_H
+
+#include <string>
+
+namespace Sass {
+
+  class Base64VLQ {
+
+  public:
+
+    std::string encode(const int number) const;
+
+  private:
+
+    char base64_encode(const int number) const;
+
+    int to_vlq_signed(const int number) const;
+
+    static const char* CHARACTERS;
+
+    static const int VLQ_BASE_SHIFT;
+    static const int VLQ_BASE;
+    static const int VLQ_BASE_MASK;
+    static const int VLQ_CONTINUATION_BIT;
+  };
+
+}
+
+#endif
diff --git a/libsass/src/bind.cpp b/libsass/src/bind.cpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/bind.cpp
@@ -0,0 +1,301 @@
+#include "bind.hpp"
+#include "ast.hpp"
+#include "context.hpp"
+#include "eval.hpp"
+#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)
+  {
+    std::string callee(type + " " + name);
+    Listize listize(*ctx);
+    std::map<std::string, Parameter*> param_map;
+
+    for (size_t i = 0, L = as->length(); i < L; ++i) {
+      if (auto str = dynamic_cast<String_Quoted*>((*as)[i]->value())) {
+        // force optional quotes (only if needed)
+        if (str->quote_mark()) {
+          str->quote_mark('*');
+          str->is_delayed(true);
+        }
+      }
+    }
+
+    // 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];
+      param_map[p->name()] = p;
+      // if (p->default_value()) {
+      //   env->local_frame()[p->name()] = p->default_value()->perform(eval->with(env));
+      // }
+    }
+
+    // plug in all args; if we have leftover params, deal with it later
+    size_t ip = 0, LP = ps->length();
+    size_t ia = 0, LA = as->length();
+    while (ia < LA) {
+      Argument* a = (*as)[ia];
+      if (ip >= LP) {
+        // skip empty rest arguments
+        if (a->is_rest_argument()) {
+          if (List* l = dynamic_cast<List*>(a->value())) {
+            if (l->length() == 0) {
+              ++ ia; continue;
+            }
+          }
+        }
+        std::stringstream msg;
+        msg << "wrong number of arguments (" << LA << " for " << LP << ")";
+        msg << " for `" << name << "'";
+        return error(msg.str(), as->pstate());
+      }
+      Parameter* p = (*ps)[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 {
+              // create a new list object for wrapped items
+              List* arglist = SASS_MEMORY_NEW(ctx->mem, 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);
+              }
+              // assign new arglist to environment
+              env->local_frame()[p->name()] = arglist;
+            }
+          }
+          // invalid state
+          else {
+            throw std::runtime_error("invalid state");
+          }
+        } 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);
+          env->local_frame()[p->name()] = arglist;
+          Map* argmap = static_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);
+          }
+
+        } else {
+
+          // create a new list object for wrapped items
+          List* arglist = SASS_MEMORY_NEW(ctx->mem, List,
+                                          p->pstate(),
+                                          0,
+                                          SASS_COMMA,
+                                          true);
+          // consume the next args
+          while (ia < LA) {
+            // get and post inc
+            a = (*as)[ia++];
+            // maybe we have another list as argument
+            List* ls = dynamic_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],
+                                                "",
+                                                false,
+                                                false);
+                }
+              }
+            }
+            // already have a wrapped argument
+            else if (Argument* arg = dynamic_cast<Argument*>(a->value())) {
+              (*arglist) << SASS_MEMORY_NEW(ctx->mem, Argument, *arg);
+            }
+            // wrap all other value types into Argument
+            else {
+              (*arglist) << SASS_MEMORY_NEW(ctx->mem, 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;
+            }
+          }
+          // assign new arglist to environment
+          env->local_frame()[p->name()] = arglist;
+        }
+        // consumed parameter
+        ++ip;
+        // no more paramaters
+        break;
+      }
+
+      // 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());
+        // 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);
+            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());
+          }
+        }
+        // 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,
+                              a_to_convert->pstate(),
+                              a_to_convert,
+                              "",
+                              false,
+                              false);
+        }
+        arglist->elements().erase(arglist->elements().begin());
+        if (!arglist->length() || (!arglist->is_arglist() && ip + 1 == LP)) {
+          ++ia;
+        }
+      } else if (a->is_keyword_argument()) {
+        Map* argmap = static_cast<Map*>(a->value());
+
+        for (auto key : argmap->keys()) {
+          std::string name = "$" + unquote(static_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);
+        }
+        ++ia;
+        continue;
+      } else {
+        ++ia;
+      }
+
+      if (a->name().empty()) {
+        if (env->has_local(p->name())) {
+          std::stringstream msg;
+          msg << "parameter " << p->name()
+          << " provided more than once in call to " << callee;
+          error(msg.str(), a->pstate());
+        }
+        // ordinal arg -- bind it to the next param
+        env->local_frame()[p->name()] = a->value();
+        ++ip;
+      }
+      else {
+        // named arg -- bind it to the appropriately named param
+        if (!param_map.count(a->name())) {
+          std::stringstream msg;
+          msg << callee << " has no parameter named " << a->name();
+          error(msg.str(), a->pstate());
+        }
+        if (param_map[a->name()]->is_rest_parameter()) {
+          std::stringstream msg;
+          msg << "argument " << a->name() << " of " << callee
+              << "cannot be used as named argument";
+          error(msg.str(), a->pstate());
+        }
+        if (env->has_local(a->name())) {
+          std::stringstream msg;
+          msg << "parameter " << p->name()
+              << "provided more than once in call to " << callee;
+          error(msg.str(), a->pstate());
+        }
+        env->local_frame()[a->name()] = a->value();
+      }
+    }
+    // EO while ia
+
+    // If we make it here, we're out of args but may have leftover params.
+    // That's only okay if they have default values, or were already bound by
+    // 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];
+      // 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,
+                                                                   leftover->pstate(),
+                                                                   0,
+                                                                   SASS_COMMA,
+                                                                   true);
+        }
+        else if (leftover->default_value()) {
+          Expression* 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());
+        }
+      }
+    }
+
+    return;
+  }
+
+
+}
diff --git a/libsass/src/bind.hpp b/libsass/src/bind.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/bind.hpp
@@ -0,0 +1,18 @@
+#ifndef SASS_BIND_H
+#define SASS_BIND_H
+
+#include <string>
+#include "environment.hpp"
+
+namespace Sass {
+  class   AST_Node;
+  class   Parameters;
+  class   Arguments;
+  class   Context;
+  class   Eval;
+  typedef Environment<AST_Node*> Env;
+
+  void bind(std::string type, std::string name, Parameters*, Arguments*, Context*, Env*, Eval*);
+}
+
+#endif
diff --git a/libsass/src/c99func.c b/libsass/src/c99func.c
new file mode 100644
--- /dev/null
+++ b/libsass/src/c99func.c
@@ -0,0 +1,54 @@
+/*
+  Copyright (C) 2011 Joseph A. Adams (joeyadams3.14159@gmail.com)
+  All rights reserved.
+
+  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 the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+  THE SOFTWARE.
+*/
+
+#if defined(_MSC_VER) && _MSC_VER < 1900
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+static int c99_vsnprintf(char* str, size_t size, const char* format, va_list ap)
+{
+    int count = -1;
+
+    if (size != 0)
+        count = _vsnprintf_s(str, size, _TRUNCATE, format, ap);
+    if (count == -1)
+        count = _vscprintf(format, ap);
+
+    return count;
+}
+
+int snprintf(char* str, size_t size, const char* format, ...)
+{
+    int count;
+    va_list ap;
+
+    va_start(ap, format);
+    count = c99_vsnprintf(str, size, format, ap);
+    va_end(ap);
+
+    return count;
+}
+
+#endif
diff --git a/libsass/src/cencode.c b/libsass/src/cencode.c
new file mode 100644
--- /dev/null
+++ b/libsass/src/cencode.c
@@ -0,0 +1,102 @@
+/*
+cencoder.c - c source to a base64 encoding algorithm implementation
+
+This is part of the libb64 project, and has been placed in the public domain.
+For details, see http://sourceforge.net/projects/libb64
+*/
+
+#include "b64/cencode.h"
+
+void base64_init_encodestate(base64_encodestate* state_in)
+{
+	state_in->step = step_A;
+	state_in->result = 0;
+	state_in->stepcount = 0;
+}
+
+char base64_encode_value(char value_in)
+{
+	static const char* encoding = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+	if (value_in > 63) return '=';
+	return encoding[(int)value_in];
+}
+
+int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in)
+{
+	const char* plainchar = plaintext_in;
+	const char* const plaintextend = plaintext_in + length_in;
+	char* codechar = code_out;
+	char result;
+	char fragment;
+
+	result = state_in->result;
+
+	switch (state_in->step)
+	{
+		while (1)
+		{
+	case step_A:
+			if (plainchar == plaintextend)
+			{
+				state_in->result = result;
+				state_in->step = step_A;
+				return (int)(codechar - code_out);
+			}
+			fragment = *plainchar++;
+			result = (fragment & 0x0fc) >> 2;
+			*codechar++ = base64_encode_value(result);
+			result = (fragment & 0x003) << 4;
+	case step_B:
+			if (plainchar == plaintextend)
+			{
+				state_in->result = result;
+				state_in->step = step_B;
+				return (int)(codechar - code_out);
+			}
+			fragment = *plainchar++;
+			result |= (fragment & 0x0f0) >> 4;
+			*codechar++ = base64_encode_value(result);
+			result = (fragment & 0x00f) << 2;
+	case step_C:
+			if (plainchar == plaintextend)
+			{
+				state_in->result = result;
+				state_in->step = step_C;
+				return (int)(codechar - code_out);
+			}
+			fragment = *plainchar++;
+			result |= (fragment & 0x0c0) >> 6;
+			*codechar++ = base64_encode_value(result);
+			result  = (fragment & 0x03f) >> 0;
+			*codechar++ = base64_encode_value(result);
+
+			++(state_in->stepcount);
+		}
+	}
+	/* control should not reach here */
+	return (int)(codechar - code_out);
+}
+
+int base64_encode_blockend(char* code_out, base64_encodestate* state_in)
+{
+	char* codechar = code_out;
+
+	switch (state_in->step)
+	{
+	case step_B:
+		*codechar++ = base64_encode_value(state_in->result);
+		*codechar++ = '=';
+		*codechar++ = '=';
+		break;
+	case step_C:
+		*codechar++ = base64_encode_value(state_in->result);
+		*codechar++ = '=';
+		break;
+	case step_A:
+		break;
+	}
+	*codechar++ = '\n';
+
+	return (int)(codechar - code_out);
+}
+
diff --git a/libsass/src/color_maps.cpp b/libsass/src/color_maps.cpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/color_maps.cpp
@@ -0,0 +1,643 @@
+#include "ast.hpp"
+#include "color_maps.hpp"
+
+namespace Sass {
+
+  namespace ColorNames
+  {
+    const char aliceblue [] = "aliceblue";
+    const char antiquewhite [] = "antiquewhite";
+    const char cyan [] = "cyan";
+    const char aqua [] = "aqua";
+    const char aquamarine [] = "aquamarine";
+    const char azure [] = "azure";
+    const char beige [] = "beige";
+    const char bisque [] = "bisque";
+    const char black [] = "black";
+    const char blanchedalmond [] = "blanchedalmond";
+    const char blue [] = "blue";
+    const char blueviolet [] = "blueviolet";
+    const char brown [] = "brown";
+    const char burlywood [] = "burlywood";
+    const char cadetblue [] = "cadetblue";
+    const char chartreuse [] = "chartreuse";
+    const char chocolate [] = "chocolate";
+    const char coral [] = "coral";
+    const char cornflowerblue [] = "cornflowerblue";
+    const char cornsilk [] = "cornsilk";
+    const char crimson [] = "crimson";
+    const char darkblue [] = "darkblue";
+    const char darkcyan [] = "darkcyan";
+    const char darkgoldenrod [] = "darkgoldenrod";
+    const char darkgray [] = "darkgray";
+    const char darkgrey [] = "darkgrey";
+    const char darkgreen [] = "darkgreen";
+    const char darkkhaki [] = "darkkhaki";
+    const char darkmagenta [] = "darkmagenta";
+    const char darkolivegreen [] = "darkolivegreen";
+    const char darkorange [] = "darkorange";
+    const char darkorchid [] = "darkorchid";
+    const char darkred [] = "darkred";
+    const char darksalmon [] = "darksalmon";
+    const char darkseagreen [] = "darkseagreen";
+    const char darkslateblue [] = "darkslateblue";
+    const char darkslategray [] = "darkslategray";
+    const char darkslategrey [] = "darkslategrey";
+    const char darkturquoise [] = "darkturquoise";
+    const char darkviolet [] = "darkviolet";
+    const char deeppink [] = "deeppink";
+    const char deepskyblue [] = "deepskyblue";
+    const char dimgray [] = "dimgray";
+    const char dimgrey [] = "dimgrey";
+    const char dodgerblue [] = "dodgerblue";
+    const char firebrick [] = "firebrick";
+    const char floralwhite [] = "floralwhite";
+    const char forestgreen [] = "forestgreen";
+    const char magenta [] = "magenta";
+    const char fuchsia [] = "fuchsia";
+    const char gainsboro [] = "gainsboro";
+    const char ghostwhite [] = "ghostwhite";
+    const char gold [] = "gold";
+    const char goldenrod [] = "goldenrod";
+    const char gray [] = "gray";
+    const char grey [] = "grey";
+    const char green [] = "green";
+    const char greenyellow [] = "greenyellow";
+    const char honeydew [] = "honeydew";
+    const char hotpink [] = "hotpink";
+    const char indianred [] = "indianred";
+    const char indigo [] = "indigo";
+    const char ivory [] = "ivory";
+    const char khaki [] = "khaki";
+    const char lavender [] = "lavender";
+    const char lavenderblush [] = "lavenderblush";
+    const char lawngreen [] = "lawngreen";
+    const char lemonchiffon [] = "lemonchiffon";
+    const char lightblue [] = "lightblue";
+    const char lightcoral [] = "lightcoral";
+    const char lightcyan [] = "lightcyan";
+    const char lightgoldenrodyellow [] = "lightgoldenrodyellow";
+    const char lightgray [] = "lightgray";
+    const char lightgrey [] = "lightgrey";
+    const char lightgreen [] = "lightgreen";
+    const char lightpink [] = "lightpink";
+    const char lightsalmon [] = "lightsalmon";
+    const char lightseagreen [] = "lightseagreen";
+    const char lightskyblue [] = "lightskyblue";
+    const char lightslategray [] = "lightslategray";
+    const char lightslategrey [] = "lightslategrey";
+    const char lightsteelblue [] = "lightsteelblue";
+    const char lightyellow [] = "lightyellow";
+    const char lime [] = "lime";
+    const char limegreen [] = "limegreen";
+    const char linen [] = "linen";
+    const char maroon [] = "maroon";
+    const char mediumaquamarine [] = "mediumaquamarine";
+    const char mediumblue [] = "mediumblue";
+    const char mediumorchid [] = "mediumorchid";
+    const char mediumpurple [] = "mediumpurple";
+    const char mediumseagreen [] = "mediumseagreen";
+    const char mediumslateblue [] = "mediumslateblue";
+    const char mediumspringgreen [] = "mediumspringgreen";
+    const char mediumturquoise [] = "mediumturquoise";
+    const char mediumvioletred [] = "mediumvioletred";
+    const char midnightblue [] = "midnightblue";
+    const char mintcream [] = "mintcream";
+    const char mistyrose [] = "mistyrose";
+    const char moccasin [] = "moccasin";
+    const char navajowhite [] = "navajowhite";
+    const char navy [] = "navy";
+    const char oldlace [] = "oldlace";
+    const char olive [] = "olive";
+    const char olivedrab [] = "olivedrab";
+    const char orange [] = "orange";
+    const char orangered [] = "orangered";
+    const char orchid [] = "orchid";
+    const char palegoldenrod [] = "palegoldenrod";
+    const char palegreen [] = "palegreen";
+    const char paleturquoise [] = "paleturquoise";
+    const char palevioletred [] = "palevioletred";
+    const char papayawhip [] = "papayawhip";
+    const char peachpuff [] = "peachpuff";
+    const char peru [] = "peru";
+    const char pink [] = "pink";
+    const char plum [] = "plum";
+    const char powderblue [] = "powderblue";
+    const char purple [] = "purple";
+    const char red [] = "red";
+    const char rosybrown [] = "rosybrown";
+    const char royalblue [] = "royalblue";
+    const char saddlebrown [] = "saddlebrown";
+    const char salmon [] = "salmon";
+    const char sandybrown [] = "sandybrown";
+    const char seagreen [] = "seagreen";
+    const char seashell [] = "seashell";
+    const char sienna [] = "sienna";
+    const char silver [] = "silver";
+    const char skyblue [] = "skyblue";
+    const char slateblue [] = "slateblue";
+    const char slategray [] = "slategray";
+    const char slategrey [] = "slategrey";
+    const char snow [] = "snow";
+    const char springgreen [] = "springgreen";
+    const char steelblue [] = "steelblue";
+    const char tan [] = "tan";
+    const char teal [] = "teal";
+    const char thistle [] = "thistle";
+    const char tomato [] = "tomato";
+    const char turquoise [] = "turquoise";
+    const char violet [] = "violet";
+    const char wheat [] = "wheat";
+    const char white [] = "white";
+    const char whitesmoke [] = "whitesmoke";
+    const char yellow [] = "yellow";
+    const char yellowgreen [] = "yellowgreen";
+    const char rebeccapurple [] = "rebeccapurple";
+    const char transparent [] = "transparent";
+  }
+
+  namespace Colors {
+    const ParserState color_table("[COLOR TABLE]");
+    const Color aliceblue(color_table, 240, 248, 255, 1);
+    const Color antiquewhite(color_table, 250, 235, 215, 1);
+    const Color cyan(color_table, 0, 255, 255, 1);
+    const Color aqua(color_table, 0, 255, 255, 1);
+    const Color aquamarine(color_table, 127, 255, 212, 1);
+    const Color azure(color_table, 240, 255, 255, 1);
+    const Color beige(color_table, 245, 245, 220, 1);
+    const Color bisque(color_table, 255, 228, 196, 1);
+    const Color black(color_table, 0, 0, 0, 1);
+    const Color blanchedalmond(color_table, 255, 235, 205, 1);
+    const Color blue(color_table, 0, 0, 255, 1);
+    const Color blueviolet(color_table, 138, 43, 226, 1);
+    const Color brown(color_table, 165, 42, 42, 1);
+    const Color burlywood(color_table, 222, 184, 135, 1);
+    const Color cadetblue(color_table, 95, 158, 160, 1);
+    const Color chartreuse(color_table, 127, 255, 0, 1);
+    const Color chocolate(color_table, 210, 105, 30, 1);
+    const Color coral(color_table, 255, 127, 80, 1);
+    const Color cornflowerblue(color_table, 100, 149, 237, 1);
+    const Color cornsilk(color_table, 255, 248, 220, 1);
+    const Color crimson(color_table, 220, 20, 60, 1);
+    const Color darkblue(color_table, 0, 0, 139, 1);
+    const Color darkcyan(color_table, 0, 139, 139, 1);
+    const Color darkgoldenrod(color_table, 184, 134, 11, 1);
+    const Color darkgray(color_table, 169, 169, 169, 1);
+    const Color darkgrey(color_table, 169, 169, 169, 1);
+    const Color darkgreen(color_table, 0, 100, 0, 1);
+    const Color darkkhaki(color_table, 189, 183, 107, 1);
+    const Color darkmagenta(color_table, 139, 0, 139, 1);
+    const Color darkolivegreen(color_table, 85, 107, 47, 1);
+    const Color darkorange(color_table, 255, 140, 0, 1);
+    const Color darkorchid(color_table, 153, 50, 204, 1);
+    const Color darkred(color_table, 139, 0, 0, 1);
+    const Color darksalmon(color_table, 233, 150, 122, 1);
+    const Color darkseagreen(color_table, 143, 188, 143, 1);
+    const Color darkslateblue(color_table, 72, 61, 139, 1);
+    const Color darkslategray(color_table, 47, 79, 79, 1);
+    const Color darkslategrey(color_table, 47, 79, 79, 1);
+    const Color darkturquoise(color_table, 0, 206, 209, 1);
+    const Color darkviolet(color_table, 148, 0, 211, 1);
+    const Color deeppink(color_table, 255, 20, 147, 1);
+    const Color deepskyblue(color_table, 0, 191, 255, 1);
+    const Color dimgray(color_table, 105, 105, 105, 1);
+    const Color dimgrey(color_table, 105, 105, 105, 1);
+    const Color dodgerblue(color_table, 30, 144, 255, 1);
+    const Color firebrick(color_table, 178, 34, 34, 1);
+    const Color floralwhite(color_table, 255, 250, 240, 1);
+    const Color forestgreen(color_table, 34, 139, 34, 1);
+    const Color magenta(color_table, 255, 0, 255, 1);
+    const Color fuchsia(color_table, 255, 0, 255, 1);
+    const Color gainsboro(color_table, 220, 220, 220, 1);
+    const Color ghostwhite(color_table, 248, 248, 255, 1);
+    const Color gold(color_table, 255, 215, 0, 1);
+    const Color goldenrod(color_table, 218, 165, 32, 1);
+    const Color gray(color_table, 128, 128, 128, 1);
+    const Color grey(color_table, 128, 128, 128, 1);
+    const Color green(color_table, 0, 128, 0, 1);
+    const Color greenyellow(color_table, 173, 255, 47, 1);
+    const Color honeydew(color_table, 240, 255, 240, 1);
+    const Color hotpink(color_table, 255, 105, 180, 1);
+    const Color indianred(color_table, 205, 92, 92, 1);
+    const Color indigo(color_table, 75, 0, 130, 1);
+    const Color ivory(color_table, 255, 255, 240, 1);
+    const Color khaki(color_table, 240, 230, 140, 1);
+    const Color lavender(color_table, 230, 230, 250, 1);
+    const Color lavenderblush(color_table, 255, 240, 245, 1);
+    const Color lawngreen(color_table, 124, 252, 0, 1);
+    const Color lemonchiffon(color_table, 255, 250, 205, 1);
+    const Color lightblue(color_table, 173, 216, 230, 1);
+    const Color lightcoral(color_table, 240, 128, 128, 1);
+    const Color lightcyan(color_table, 224, 255, 255, 1);
+    const Color lightgoldenrodyellow(color_table, 250, 250, 210, 1);
+    const Color lightgray(color_table, 211, 211, 211, 1);
+    const Color lightgrey(color_table, 211, 211, 211, 1);
+    const Color lightgreen(color_table, 144, 238, 144, 1);
+    const Color lightpink(color_table, 255, 182, 193, 1);
+    const Color lightsalmon(color_table, 255, 160, 122, 1);
+    const Color lightseagreen(color_table, 32, 178, 170, 1);
+    const Color lightskyblue(color_table, 135, 206, 250, 1);
+    const Color lightslategray(color_table, 119, 136, 153, 1);
+    const Color lightslategrey(color_table, 119, 136, 153, 1);
+    const Color lightsteelblue(color_table, 176, 196, 222, 1);
+    const Color lightyellow(color_table, 255, 255, 224, 1);
+    const Color lime(color_table, 0, 255, 0, 1);
+    const Color limegreen(color_table, 50, 205, 50, 1);
+    const Color linen(color_table, 250, 240, 230, 1);
+    const Color maroon(color_table, 128, 0, 0, 1);
+    const Color mediumaquamarine(color_table, 102, 205, 170, 1);
+    const Color mediumblue(color_table, 0, 0, 205, 1);
+    const Color mediumorchid(color_table, 186, 85, 211, 1);
+    const Color mediumpurple(color_table, 147, 112, 219, 1);
+    const Color mediumseagreen(color_table, 60, 179, 113, 1);
+    const Color mediumslateblue(color_table, 123, 104, 238, 1);
+    const Color mediumspringgreen(color_table, 0, 250, 154, 1);
+    const Color mediumturquoise(color_table, 72, 209, 204, 1);
+    const Color mediumvioletred(color_table, 199, 21, 133, 1);
+    const Color midnightblue(color_table, 25, 25, 112, 1);
+    const Color mintcream(color_table, 245, 255, 250, 1);
+    const Color mistyrose(color_table, 255, 228, 225, 1);
+    const Color moccasin(color_table, 255, 228, 181, 1);
+    const Color navajowhite(color_table, 255, 222, 173, 1);
+    const Color navy(color_table, 0, 0, 128, 1);
+    const Color oldlace(color_table, 253, 245, 230, 1);
+    const Color olive(color_table, 128, 128, 0, 1);
+    const Color olivedrab(color_table, 107, 142, 35, 1);
+    const Color orange(color_table, 255, 165, 0, 1);
+    const Color orangered(color_table, 255, 69, 0, 1);
+    const Color orchid(color_table, 218, 112, 214, 1);
+    const Color palegoldenrod(color_table, 238, 232, 170, 1);
+    const Color palegreen(color_table, 152, 251, 152, 1);
+    const Color paleturquoise(color_table, 175, 238, 238, 1);
+    const Color palevioletred(color_table, 219, 112, 147, 1);
+    const Color papayawhip(color_table, 255, 239, 213, 1);
+    const Color peachpuff(color_table, 255, 218, 185, 1);
+    const Color peru(color_table, 205, 133, 63, 1);
+    const Color pink(color_table, 255, 192, 203, 1);
+    const Color plum(color_table, 221, 160, 221, 1);
+    const Color powderblue(color_table, 176, 224, 230, 1);
+    const Color purple(color_table, 128, 0, 128, 1);
+    const Color red(color_table, 255, 0, 0, 1);
+    const Color rosybrown(color_table, 188, 143, 143, 1);
+    const Color royalblue(color_table, 65, 105, 225, 1);
+    const Color saddlebrown(color_table, 139, 69, 19, 1);
+    const Color salmon(color_table, 250, 128, 114, 1);
+    const Color sandybrown(color_table, 244, 164, 96, 1);
+    const Color seagreen(color_table, 46, 139, 87, 1);
+    const Color seashell(color_table, 255, 245, 238, 1);
+    const Color sienna(color_table, 160, 82, 45, 1);
+    const Color silver(color_table, 192, 192, 192, 1);
+    const Color skyblue(color_table, 135, 206, 235, 1);
+    const Color slateblue(color_table, 106, 90, 205, 1);
+    const Color slategray(color_table, 112, 128, 144, 1);
+    const Color slategrey(color_table, 112, 128, 144, 1);
+    const Color snow(color_table, 255, 250, 250, 1);
+    const Color springgreen(color_table, 0, 255, 127, 1);
+    const Color steelblue(color_table, 70, 130, 180, 1);
+    const Color tan(color_table, 210, 180, 140, 1);
+    const Color teal(color_table, 0, 128, 128, 1);
+    const Color thistle(color_table, 216, 191, 216, 1);
+    const Color tomato(color_table, 255, 99, 71, 1);
+    const Color turquoise(color_table, 64, 224, 208, 1);
+    const Color violet(color_table, 238, 130, 238, 1);
+    const Color wheat(color_table, 245, 222, 179, 1);
+    const Color white(color_table, 255, 255, 255, 1);
+    const Color whitesmoke(color_table, 245, 245, 245, 1);
+    const Color yellow(color_table, 255, 255, 0, 1);
+    const Color yellowgreen(color_table, 154, 205, 50, 1);
+    const Color rebeccapurple(color_table, 102, 51, 153, 1);
+    const Color transparent(color_table, 0, 0, 0, 0);
+  }
+
+  const std::map<const int, const char*> colors_to_names {
+    { 240 * 0x10000 + 248 * 0x100 + 255, ColorNames::aliceblue },
+    { 250 * 0x10000 + 235 * 0x100 + 215, ColorNames::antiquewhite },
+    {   0 * 0x10000 + 255 * 0x100 + 255, ColorNames::cyan },
+    { 127 * 0x10000 + 255 * 0x100 + 212, ColorNames::aquamarine },
+    { 240 * 0x10000 + 255 * 0x100 + 255, ColorNames::azure },
+    { 245 * 0x10000 + 245 * 0x100 + 220, ColorNames::beige },
+    { 255 * 0x10000 + 228 * 0x100 + 196, ColorNames::bisque },
+    {   0 * 0x10000 +   0 * 0x100 +   0, ColorNames::black },
+    { 255 * 0x10000 + 235 * 0x100 + 205, ColorNames::blanchedalmond },
+    {   0 * 0x10000 +   0 * 0x100 + 255, ColorNames::blue },
+    { 138 * 0x10000 +  43 * 0x100 + 226, ColorNames::blueviolet },
+    { 165 * 0x10000 +  42 * 0x100 +  42, ColorNames::brown },
+    { 222 * 0x10000 + 184 * 0x100 + 135, ColorNames::burlywood },
+    {  95 * 0x10000 + 158 * 0x100 + 160, ColorNames::cadetblue },
+    { 127 * 0x10000 + 255 * 0x100 +   0, ColorNames::chartreuse },
+    { 210 * 0x10000 + 105 * 0x100 +  30, ColorNames::chocolate },
+    { 255 * 0x10000 + 127 * 0x100 +  80, ColorNames::coral },
+    { 100 * 0x10000 + 149 * 0x100 + 237, ColorNames::cornflowerblue },
+    { 255 * 0x10000 + 248 * 0x100 + 220, ColorNames::cornsilk },
+    { 220 * 0x10000 +  20 * 0x100 +  60, ColorNames::crimson },
+    {   0 * 0x10000 +   0 * 0x100 + 139, ColorNames::darkblue },
+    {   0 * 0x10000 + 139 * 0x100 + 139, ColorNames::darkcyan },
+    { 184 * 0x10000 + 134 * 0x100 +  11, ColorNames::darkgoldenrod },
+    { 169 * 0x10000 + 169 * 0x100 + 169, ColorNames::darkgray },
+    {   0 * 0x10000 + 100 * 0x100 +   0, ColorNames::darkgreen },
+    { 189 * 0x10000 + 183 * 0x100 + 107, ColorNames::darkkhaki },
+    { 139 * 0x10000 +   0 * 0x100 + 139, ColorNames::darkmagenta },
+    {  85 * 0x10000 + 107 * 0x100 +  47, ColorNames::darkolivegreen },
+    { 255 * 0x10000 + 140 * 0x100 +   0, ColorNames::darkorange },
+    { 153 * 0x10000 +  50 * 0x100 + 204, ColorNames::darkorchid },
+    { 139 * 0x10000 +   0 * 0x100 +   0, ColorNames::darkred },
+    { 233 * 0x10000 + 150 * 0x100 + 122, ColorNames::darksalmon },
+    { 143 * 0x10000 + 188 * 0x100 + 143, ColorNames::darkseagreen },
+    {  72 * 0x10000 +  61 * 0x100 + 139, ColorNames::darkslateblue },
+    {  47 * 0x10000 +  79 * 0x100 +  79, ColorNames::darkslategray },
+    {   0 * 0x10000 + 206 * 0x100 + 209, ColorNames::darkturquoise },
+    { 148 * 0x10000 +   0 * 0x100 + 211, ColorNames::darkviolet },
+    { 255 * 0x10000 +  20 * 0x100 + 147, ColorNames::deeppink },
+    {   0 * 0x10000 + 191 * 0x100 + 255, ColorNames::deepskyblue },
+    { 105 * 0x10000 + 105 * 0x100 + 105, ColorNames::dimgray },
+    {  30 * 0x10000 + 144 * 0x100 + 255, ColorNames::dodgerblue },
+    { 178 * 0x10000 +  34 * 0x100 +  34, ColorNames::firebrick },
+    { 255 * 0x10000 + 250 * 0x100 + 240, ColorNames::floralwhite },
+    {  34 * 0x10000 + 139 * 0x100 +  34, ColorNames::forestgreen },
+    { 255 * 0x10000 +   0 * 0x100 + 255, ColorNames::magenta },
+    { 220 * 0x10000 + 220 * 0x100 + 220, ColorNames::gainsboro },
+    { 248 * 0x10000 + 248 * 0x100 + 255, ColorNames::ghostwhite },
+    { 255 * 0x10000 + 215 * 0x100 +   0, ColorNames::gold },
+    { 218 * 0x10000 + 165 * 0x100 +  32, ColorNames::goldenrod },
+    { 128 * 0x10000 + 128 * 0x100 + 128, ColorNames::gray },
+    {   0 * 0x10000 + 128 * 0x100 +   0, ColorNames::green },
+    { 173 * 0x10000 + 255 * 0x100 +  47, ColorNames::greenyellow },
+    { 240 * 0x10000 + 255 * 0x100 + 240, ColorNames::honeydew },
+    { 255 * 0x10000 + 105 * 0x100 + 180, ColorNames::hotpink },
+    { 205 * 0x10000 +  92 * 0x100 +  92, ColorNames::indianred },
+    {  75 * 0x10000 +   0 * 0x100 + 130, ColorNames::indigo },
+    { 255 * 0x10000 + 255 * 0x100 + 240, ColorNames::ivory },
+    { 240 * 0x10000 + 230 * 0x100 + 140, ColorNames::khaki },
+    { 230 * 0x10000 + 230 * 0x100 + 250, ColorNames::lavender },
+    { 255 * 0x10000 + 240 * 0x100 + 245, ColorNames::lavenderblush },
+    { 124 * 0x10000 + 252 * 0x100 +   0, ColorNames::lawngreen },
+    { 255 * 0x10000 + 250 * 0x100 + 205, ColorNames::lemonchiffon },
+    { 173 * 0x10000 + 216 * 0x100 + 230, ColorNames::lightblue },
+    { 240 * 0x10000 + 128 * 0x100 + 128, ColorNames::lightcoral },
+    { 224 * 0x10000 + 255 * 0x100 + 255, ColorNames::lightcyan },
+    { 250 * 0x10000 + 250 * 0x100 + 210, ColorNames::lightgoldenrodyellow },
+    { 211 * 0x10000 + 211 * 0x100 + 211, ColorNames::lightgray },
+    { 144 * 0x10000 + 238 * 0x100 + 144, ColorNames::lightgreen },
+    { 255 * 0x10000 + 182 * 0x100 + 193, ColorNames::lightpink },
+    { 255 * 0x10000 + 160 * 0x100 + 122, ColorNames::lightsalmon },
+    {  32 * 0x10000 + 178 * 0x100 + 170, ColorNames::lightseagreen },
+    { 135 * 0x10000 + 206 * 0x100 + 250, ColorNames::lightskyblue },
+    { 119 * 0x10000 + 136 * 0x100 + 153, ColorNames::lightslategray },
+    { 176 * 0x10000 + 196 * 0x100 + 222, ColorNames::lightsteelblue },
+    { 255 * 0x10000 + 255 * 0x100 + 224, ColorNames::lightyellow },
+    {   0 * 0x10000 + 255 * 0x100 +   0, ColorNames::lime },
+    {  50 * 0x10000 + 205 * 0x100 +  50, ColorNames::limegreen },
+    { 250 * 0x10000 + 240 * 0x100 + 230, ColorNames::linen },
+    { 128 * 0x10000 +   0 * 0x100 +   0, ColorNames::maroon },
+    { 102 * 0x10000 + 205 * 0x100 + 170, ColorNames::mediumaquamarine },
+    {   0 * 0x10000 +   0 * 0x100 + 205, ColorNames::mediumblue },
+    { 186 * 0x10000 +  85 * 0x100 + 211, ColorNames::mediumorchid },
+    { 147 * 0x10000 + 112 * 0x100 + 219, ColorNames::mediumpurple },
+    {  60 * 0x10000 + 179 * 0x100 + 113, ColorNames::mediumseagreen },
+    { 123 * 0x10000 + 104 * 0x100 + 238, ColorNames::mediumslateblue },
+    {   0 * 0x10000 + 250 * 0x100 + 154, ColorNames::mediumspringgreen },
+    {  72 * 0x10000 + 209 * 0x100 + 204, ColorNames::mediumturquoise },
+    { 199 * 0x10000 +  21 * 0x100 + 133, ColorNames::mediumvioletred },
+    {  25 * 0x10000 +  25 * 0x100 + 112, ColorNames::midnightblue },
+    { 245 * 0x10000 + 255 * 0x100 + 250, ColorNames::mintcream },
+    { 255 * 0x10000 + 228 * 0x100 + 225, ColorNames::mistyrose },
+    { 255 * 0x10000 + 228 * 0x100 + 181, ColorNames::moccasin },
+    { 255 * 0x10000 + 222 * 0x100 + 173, ColorNames::navajowhite },
+    {   0 * 0x10000 +   0 * 0x100 + 128, ColorNames::navy },
+    { 253 * 0x10000 + 245 * 0x100 + 230, ColorNames::oldlace },
+    { 128 * 0x10000 + 128 * 0x100 +   0, ColorNames::olive },
+    { 107 * 0x10000 + 142 * 0x100 +  35, ColorNames::olivedrab },
+    { 255 * 0x10000 + 165 * 0x100 +   0, ColorNames::orange },
+    { 255 * 0x10000 +  69 * 0x100 +   0, ColorNames::orangered },
+    { 218 * 0x10000 + 112 * 0x100 + 214, ColorNames::orchid },
+    { 238 * 0x10000 + 232 * 0x100 + 170, ColorNames::palegoldenrod },
+    { 152 * 0x10000 + 251 * 0x100 + 152, ColorNames::palegreen },
+    { 175 * 0x10000 + 238 * 0x100 + 238, ColorNames::paleturquoise },
+    { 219 * 0x10000 + 112 * 0x100 + 147, ColorNames::palevioletred },
+    { 255 * 0x10000 + 239 * 0x100 + 213, ColorNames::papayawhip },
+    { 255 * 0x10000 + 218 * 0x100 + 185, ColorNames::peachpuff },
+    { 205 * 0x10000 + 133 * 0x100 +  63, ColorNames::peru },
+    { 255 * 0x10000 + 192 * 0x100 + 203, ColorNames::pink },
+    { 221 * 0x10000 + 160 * 0x100 + 221, ColorNames::plum },
+    { 176 * 0x10000 + 224 * 0x100 + 230, ColorNames::powderblue },
+    { 128 * 0x10000 +   0 * 0x100 + 128, ColorNames::purple },
+    { 255 * 0x10000 +   0 * 0x100 +   0, ColorNames::red },
+    { 188 * 0x10000 + 143 * 0x100 + 143, ColorNames::rosybrown },
+    {  65 * 0x10000 + 105 * 0x100 + 225, ColorNames::royalblue },
+    { 139 * 0x10000 +  69 * 0x100 +  19, ColorNames::saddlebrown },
+    { 250 * 0x10000 + 128 * 0x100 + 114, ColorNames::salmon },
+    { 244 * 0x10000 + 164 * 0x100 +  96, ColorNames::sandybrown },
+    {  46 * 0x10000 + 139 * 0x100 +  87, ColorNames::seagreen },
+    { 255 * 0x10000 + 245 * 0x100 + 238, ColorNames::seashell },
+    { 160 * 0x10000 +  82 * 0x100 +  45, ColorNames::sienna },
+    { 192 * 0x10000 + 192 * 0x100 + 192, ColorNames::silver },
+    { 135 * 0x10000 + 206 * 0x100 + 235, ColorNames::skyblue },
+    { 106 * 0x10000 +  90 * 0x100 + 205, ColorNames::slateblue },
+    { 112 * 0x10000 + 128 * 0x100 + 144, ColorNames::slategray },
+    { 255 * 0x10000 + 250 * 0x100 + 250, ColorNames::snow },
+    {   0 * 0x10000 + 255 * 0x100 + 127, ColorNames::springgreen },
+    {  70 * 0x10000 + 130 * 0x100 + 180, ColorNames::steelblue },
+    { 210 * 0x10000 + 180 * 0x100 + 140, ColorNames::tan },
+    {   0 * 0x10000 + 128 * 0x100 + 128, ColorNames::teal },
+    { 216 * 0x10000 + 191 * 0x100 + 216, ColorNames::thistle },
+    { 255 * 0x10000 +  99 * 0x100 +  71, ColorNames::tomato },
+    {  64 * 0x10000 + 224 * 0x100 + 208, ColorNames::turquoise },
+    { 238 * 0x10000 + 130 * 0x100 + 238, ColorNames::violet },
+    { 245 * 0x10000 + 222 * 0x100 + 179, ColorNames::wheat },
+    { 255 * 0x10000 + 255 * 0x100 + 255, ColorNames::white },
+    { 245 * 0x10000 + 245 * 0x100 + 245, ColorNames::whitesmoke },
+    { 255 * 0x10000 + 255 * 0x100 +   0, ColorNames::yellow },
+    { 154 * 0x10000 + 205 * 0x100 +  50, ColorNames::yellowgreen },
+    { 102 * 0x10000 +  51 * 0x100 + 153, ColorNames::rebeccapurple }
+  };
+
+  const std::map<const char*, const Color*, map_cmp_str> names_to_colors
+  {
+    { ColorNames::aliceblue, &Colors::aliceblue },
+    { ColorNames::antiquewhite, &Colors::antiquewhite },
+    { ColorNames::cyan, &Colors::cyan },
+    { ColorNames::aqua, &Colors::aqua },
+    { ColorNames::aquamarine, &Colors::aquamarine },
+    { ColorNames::azure, &Colors::azure },
+    { ColorNames::beige, &Colors::beige },
+    { ColorNames::bisque, &Colors::bisque },
+    { ColorNames::black, &Colors::black },
+    { ColorNames::blanchedalmond, &Colors::blanchedalmond },
+    { ColorNames::blue, &Colors::blue },
+    { ColorNames::blueviolet, &Colors::blueviolet },
+    { ColorNames::brown, &Colors::brown },
+    { ColorNames::burlywood, &Colors::burlywood },
+    { ColorNames::cadetblue, &Colors::cadetblue },
+    { ColorNames::chartreuse, &Colors::chartreuse },
+    { ColorNames::chocolate, &Colors::chocolate },
+    { ColorNames::coral, &Colors::coral },
+    { ColorNames::cornflowerblue, &Colors::cornflowerblue },
+    { ColorNames::cornsilk, &Colors::cornsilk },
+    { ColorNames::crimson, &Colors::crimson },
+    { ColorNames::darkblue, &Colors::darkblue },
+    { ColorNames::darkcyan, &Colors::darkcyan },
+    { ColorNames::darkgoldenrod, &Colors::darkgoldenrod },
+    { ColorNames::darkgray, &Colors::darkgray },
+    { ColorNames::darkgrey, &Colors::darkgrey },
+    { ColorNames::darkgreen, &Colors::darkgreen },
+    { ColorNames::darkkhaki, &Colors::darkkhaki },
+    { ColorNames::darkmagenta, &Colors::darkmagenta },
+    { ColorNames::darkolivegreen, &Colors::darkolivegreen },
+    { ColorNames::darkorange, &Colors::darkorange },
+    { ColorNames::darkorchid, &Colors::darkorchid },
+    { ColorNames::darkred, &Colors::darkred },
+    { ColorNames::darksalmon, &Colors::darksalmon },
+    { ColorNames::darkseagreen, &Colors::darkseagreen },
+    { ColorNames::darkslateblue, &Colors::darkslateblue },
+    { ColorNames::darkslategray, &Colors::darkslategray },
+    { ColorNames::darkslategrey, &Colors::darkslategrey },
+    { ColorNames::darkturquoise, &Colors::darkturquoise },
+    { ColorNames::darkviolet, &Colors::darkviolet },
+    { ColorNames::deeppink, &Colors::deeppink },
+    { ColorNames::deepskyblue, &Colors::deepskyblue },
+    { ColorNames::dimgray, &Colors::dimgray },
+    { ColorNames::dimgrey, &Colors::dimgrey },
+    { ColorNames::dodgerblue, &Colors::dodgerblue },
+    { ColorNames::firebrick, &Colors::firebrick },
+    { ColorNames::floralwhite, &Colors::floralwhite },
+    { ColorNames::forestgreen, &Colors::forestgreen },
+    { ColorNames::magenta, &Colors::magenta },
+    { ColorNames::fuchsia, &Colors::fuchsia },
+    { ColorNames::gainsboro, &Colors::gainsboro },
+    { ColorNames::ghostwhite, &Colors::ghostwhite },
+    { ColorNames::gold, &Colors::gold },
+    { ColorNames::goldenrod, &Colors::goldenrod },
+    { ColorNames::gray, &Colors::gray },
+    { ColorNames::grey, &Colors::grey },
+    { ColorNames::green, &Colors::green },
+    { ColorNames::greenyellow, &Colors::greenyellow },
+    { ColorNames::honeydew, &Colors::honeydew },
+    { ColorNames::hotpink, &Colors::hotpink },
+    { ColorNames::indianred, &Colors::indianred },
+    { ColorNames::indigo, &Colors::indigo },
+    { ColorNames::ivory, &Colors::ivory },
+    { ColorNames::khaki, &Colors::khaki },
+    { ColorNames::lavender, &Colors::lavender },
+    { ColorNames::lavenderblush, &Colors::lavenderblush },
+    { ColorNames::lawngreen, &Colors::lawngreen },
+    { ColorNames::lemonchiffon, &Colors::lemonchiffon },
+    { ColorNames::lightblue, &Colors::lightblue },
+    { ColorNames::lightcoral, &Colors::lightcoral },
+    { ColorNames::lightcyan, &Colors::lightcyan },
+    { ColorNames::lightgoldenrodyellow, &Colors::lightgoldenrodyellow },
+    { ColorNames::lightgray, &Colors::lightgray },
+    { ColorNames::lightgrey, &Colors::lightgrey },
+    { ColorNames::lightgreen, &Colors::lightgreen },
+    { ColorNames::lightpink, &Colors::lightpink },
+    { ColorNames::lightsalmon, &Colors::lightsalmon },
+    { ColorNames::lightseagreen, &Colors::lightseagreen },
+    { ColorNames::lightskyblue, &Colors::lightskyblue },
+    { ColorNames::lightslategray, &Colors::lightslategray },
+    { ColorNames::lightslategrey, &Colors::lightslategrey },
+    { ColorNames::lightsteelblue, &Colors::lightsteelblue },
+    { ColorNames::lightyellow, &Colors::lightyellow },
+    { ColorNames::lime, &Colors::lime },
+    { ColorNames::limegreen, &Colors::limegreen },
+    { ColorNames::linen, &Colors::linen },
+    { ColorNames::maroon, &Colors::maroon },
+    { ColorNames::mediumaquamarine, &Colors::mediumaquamarine },
+    { ColorNames::mediumblue, &Colors::mediumblue },
+    { ColorNames::mediumorchid, &Colors::mediumorchid },
+    { ColorNames::mediumpurple, &Colors::mediumpurple },
+    { ColorNames::mediumseagreen, &Colors::mediumseagreen },
+    { ColorNames::mediumslateblue, &Colors::mediumslateblue },
+    { ColorNames::mediumspringgreen, &Colors::mediumspringgreen },
+    { ColorNames::mediumturquoise, &Colors::mediumturquoise },
+    { ColorNames::mediumvioletred, &Colors::mediumvioletred },
+    { ColorNames::midnightblue, &Colors::midnightblue },
+    { ColorNames::mintcream, &Colors::mintcream },
+    { ColorNames::mistyrose, &Colors::mistyrose },
+    { ColorNames::moccasin, &Colors::moccasin },
+    { ColorNames::navajowhite, &Colors::navajowhite },
+    { ColorNames::navy, &Colors::navy },
+    { ColorNames::oldlace, &Colors::oldlace },
+    { ColorNames::olive, &Colors::olive },
+    { ColorNames::olivedrab, &Colors::olivedrab },
+    { ColorNames::orange, &Colors::orange },
+    { ColorNames::orangered, &Colors::orangered },
+    { ColorNames::orchid, &Colors::orchid },
+    { ColorNames::palegoldenrod, &Colors::palegoldenrod },
+    { ColorNames::palegreen, &Colors::palegreen },
+    { ColorNames::paleturquoise, &Colors::paleturquoise },
+    { ColorNames::palevioletred, &Colors::palevioletred },
+    { ColorNames::papayawhip, &Colors::papayawhip },
+    { ColorNames::peachpuff, &Colors::peachpuff },
+    { ColorNames::peru, &Colors::peru },
+    { ColorNames::pink, &Colors::pink },
+    { ColorNames::plum, &Colors::plum },
+    { ColorNames::powderblue, &Colors::powderblue },
+    { ColorNames::purple, &Colors::purple },
+    { ColorNames::red, &Colors::red },
+    { ColorNames::rosybrown, &Colors::rosybrown },
+    { ColorNames::royalblue, &Colors::royalblue },
+    { ColorNames::saddlebrown, &Colors::saddlebrown },
+    { ColorNames::salmon, &Colors::salmon },
+    { ColorNames::sandybrown, &Colors::sandybrown },
+    { ColorNames::seagreen, &Colors::seagreen },
+    { ColorNames::seashell, &Colors::seashell },
+    { ColorNames::sienna, &Colors::sienna },
+    { ColorNames::silver, &Colors::silver },
+    { ColorNames::skyblue, &Colors::skyblue },
+    { ColorNames::slateblue, &Colors::slateblue },
+    { ColorNames::slategray, &Colors::slategray },
+    { ColorNames::slategrey, &Colors::slategrey },
+    { ColorNames::snow, &Colors::snow },
+    { ColorNames::springgreen, &Colors::springgreen },
+    { ColorNames::steelblue, &Colors::steelblue },
+    { ColorNames::tan, &Colors::tan },
+    { ColorNames::teal, &Colors::teal },
+    { ColorNames::thistle, &Colors::thistle },
+    { ColorNames::tomato, &Colors::tomato },
+    { ColorNames::turquoise, &Colors::turquoise },
+    { ColorNames::violet, &Colors::violet },
+    { ColorNames::wheat, &Colors::wheat },
+    { ColorNames::white, &Colors::white },
+    { ColorNames::whitesmoke, &Colors::whitesmoke },
+    { ColorNames::yellow, &Colors::yellow },
+    { ColorNames::yellowgreen, &Colors::yellowgreen },
+    { ColorNames::rebeccapurple, &Colors::rebeccapurple },
+    { ColorNames::transparent, &Colors::transparent }
+  };
+
+  const Color* name_to_color(const char* key)
+  {
+    auto p = names_to_colors.find(key);
+    if (p != names_to_colors.end()) {
+      return p->second;
+    }
+    return 0;
+  }
+
+  const Color* name_to_color(const std::string& key)
+  {
+    return name_to_color(key.c_str());
+  }
+
+  const char* color_to_name(const int key)
+  {
+    auto p = colors_to_names.find(key);
+    if (p != colors_to_names.end()) {
+      return p->second;
+    }
+    return 0;
+  }
+
+  const char* color_to_name(const double key)
+  {
+    return color_to_name((int)key);
+  }
+
+  const char* color_to_name(const Color& c)
+  {
+    double key = c.r() * 0x10000
+               + c.g() * 0x100
+               + c.b();
+    return color_to_name(key);
+  }
+
+}
diff --git a/libsass/src/color_maps.hpp b/libsass/src/color_maps.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/color_maps.hpp
@@ -0,0 +1,333 @@
+#ifndef SASS_COLOR_MAPS_H
+#define SASS_COLOR_MAPS_H
+
+#include <map>
+#include "ast.hpp"
+
+namespace Sass {
+
+  struct map_cmp_str
+  {
+    bool operator()(char const *a, char const *b) const
+    {
+      return std::strcmp(a, b) < 0;
+    }
+  };
+
+  namespace ColorNames
+  {
+    extern const char aliceblue[];
+    extern const char antiquewhite[];
+    extern const char cyan[];
+    extern const char aqua[];
+    extern const char aquamarine[];
+    extern const char azure[];
+    extern const char beige[];
+    extern const char bisque[];
+    extern const char black[];
+    extern const char blanchedalmond[];
+    extern const char blue[];
+    extern const char blueviolet[];
+    extern const char brown[];
+    extern const char burlywood[];
+    extern const char cadetblue[];
+    extern const char chartreuse[];
+    extern const char chocolate[];
+    extern const char coral[];
+    extern const char cornflowerblue[];
+    extern const char cornsilk[];
+    extern const char crimson[];
+    extern const char darkblue[];
+    extern const char darkcyan[];
+    extern const char darkgoldenrod[];
+    extern const char darkgray[];
+    extern const char darkgrey[];
+    extern const char darkgreen[];
+    extern const char darkkhaki[];
+    extern const char darkmagenta[];
+    extern const char darkolivegreen[];
+    extern const char darkorange[];
+    extern const char darkorchid[];
+    extern const char darkred[];
+    extern const char darksalmon[];
+    extern const char darkseagreen[];
+    extern const char darkslateblue[];
+    extern const char darkslategray[];
+    extern const char darkslategrey[];
+    extern const char darkturquoise[];
+    extern const char darkviolet[];
+    extern const char deeppink[];
+    extern const char deepskyblue[];
+    extern const char dimgray[];
+    extern const char dimgrey[];
+    extern const char dodgerblue[];
+    extern const char firebrick[];
+    extern const char floralwhite[];
+    extern const char forestgreen[];
+    extern const char magenta[];
+    extern const char fuchsia[];
+    extern const char gainsboro[];
+    extern const char ghostwhite[];
+    extern const char gold[];
+    extern const char goldenrod[];
+    extern const char gray[];
+    extern const char grey[];
+    extern const char green[];
+    extern const char greenyellow[];
+    extern const char honeydew[];
+    extern const char hotpink[];
+    extern const char indianred[];
+    extern const char indigo[];
+    extern const char ivory[];
+    extern const char khaki[];
+    extern const char lavender[];
+    extern const char lavenderblush[];
+    extern const char lawngreen[];
+    extern const char lemonchiffon[];
+    extern const char lightblue[];
+    extern const char lightcoral[];
+    extern const char lightcyan[];
+    extern const char lightgoldenrodyellow[];
+    extern const char lightgray[];
+    extern const char lightgrey[];
+    extern const char lightgreen[];
+    extern const char lightpink[];
+    extern const char lightsalmon[];
+    extern const char lightseagreen[];
+    extern const char lightskyblue[];
+    extern const char lightslategray[];
+    extern const char lightslategrey[];
+    extern const char lightsteelblue[];
+    extern const char lightyellow[];
+    extern const char lime[];
+    extern const char limegreen[];
+    extern const char linen[];
+    extern const char maroon[];
+    extern const char mediumaquamarine[];
+    extern const char mediumblue[];
+    extern const char mediumorchid[];
+    extern const char mediumpurple[];
+    extern const char mediumseagreen[];
+    extern const char mediumslateblue[];
+    extern const char mediumspringgreen[];
+    extern const char mediumturquoise[];
+    extern const char mediumvioletred[];
+    extern const char midnightblue[];
+    extern const char mintcream[];
+    extern const char mistyrose[];
+    extern const char moccasin[];
+    extern const char navajowhite[];
+    extern const char navy[];
+    extern const char oldlace[];
+    extern const char olive[];
+    extern const char olivedrab[];
+    extern const char orange[];
+    extern const char orangered[];
+    extern const char orchid[];
+    extern const char palegoldenrod[];
+    extern const char palegreen[];
+    extern const char paleturquoise[];
+    extern const char palevioletred[];
+    extern const char papayawhip[];
+    extern const char peachpuff[];
+    extern const char peru[];
+    extern const char pink[];
+    extern const char plum[];
+    extern const char powderblue[];
+    extern const char purple[];
+    extern const char red[];
+    extern const char rosybrown[];
+    extern const char royalblue[];
+    extern const char saddlebrown[];
+    extern const char salmon[];
+    extern const char sandybrown[];
+    extern const char seagreen[];
+    extern const char seashell[];
+    extern const char sienna[];
+    extern const char silver[];
+    extern const char skyblue[];
+    extern const char slateblue[];
+    extern const char slategray[];
+    extern const char slategrey[];
+    extern const char snow[];
+    extern const char springgreen[];
+    extern const char steelblue[];
+    extern const char tan[];
+    extern const char teal[];
+    extern const char thistle[];
+    extern const char tomato[];
+    extern const char turquoise[];
+    extern const char violet[];
+    extern const char wheat[];
+    extern const char white[];
+    extern const char whitesmoke[];
+    extern const char yellow[];
+    extern const char yellowgreen[];
+    extern const char rebeccapurple[];
+    extern const char transparent[];
+  }
+
+  namespace Colors {
+    extern const Color aliceblue;
+    extern const Color antiquewhite;
+    extern const Color cyan;
+    extern const Color aqua;
+    extern const Color aquamarine;
+    extern const Color azure;
+    extern const Color beige;
+    extern const Color bisque;
+    extern const Color black;
+    extern const Color blanchedalmond;
+    extern const Color blue;
+    extern const Color blueviolet;
+    extern const Color brown;
+    extern const Color burlywood;
+    extern const Color cadetblue;
+    extern const Color chartreuse;
+    extern const Color chocolate;
+    extern const Color coral;
+    extern const Color cornflowerblue;
+    extern const Color cornsilk;
+    extern const Color crimson;
+    extern const Color darkblue;
+    extern const Color darkcyan;
+    extern const Color darkgoldenrod;
+    extern const Color darkgray;
+    extern const Color darkgrey;
+    extern const Color darkgreen;
+    extern const Color darkkhaki;
+    extern const Color darkmagenta;
+    extern const Color darkolivegreen;
+    extern const Color darkorange;
+    extern const Color darkorchid;
+    extern const Color darkred;
+    extern const Color darksalmon;
+    extern const Color darkseagreen;
+    extern const Color darkslateblue;
+    extern const Color darkslategray;
+    extern const Color darkslategrey;
+    extern const Color darkturquoise;
+    extern const Color darkviolet;
+    extern const Color deeppink;
+    extern const Color deepskyblue;
+    extern const Color dimgray;
+    extern const Color dimgrey;
+    extern const Color dodgerblue;
+    extern const Color firebrick;
+    extern const Color floralwhite;
+    extern const Color forestgreen;
+    extern const Color magenta;
+    extern const Color fuchsia;
+    extern const Color gainsboro;
+    extern const Color ghostwhite;
+    extern const Color gold;
+    extern const Color goldenrod;
+    extern const Color gray;
+    extern const Color grey;
+    extern const Color green;
+    extern const Color greenyellow;
+    extern const Color honeydew;
+    extern const Color hotpink;
+    extern const Color indianred;
+    extern const Color indigo;
+    extern const Color ivory;
+    extern const Color khaki;
+    extern const Color lavender;
+    extern const Color lavenderblush;
+    extern const Color lawngreen;
+    extern const Color lemonchiffon;
+    extern const Color lightblue;
+    extern const Color lightcoral;
+    extern const Color lightcyan;
+    extern const Color lightgoldenrodyellow;
+    extern const Color lightgray;
+    extern const Color lightgrey;
+    extern const Color lightgreen;
+    extern const Color lightpink;
+    extern const Color lightsalmon;
+    extern const Color lightseagreen;
+    extern const Color lightskyblue;
+    extern const Color lightslategray;
+    extern const Color lightslategrey;
+    extern const Color lightsteelblue;
+    extern const Color lightyellow;
+    extern const Color lime;
+    extern const Color limegreen;
+    extern const Color linen;
+    extern const Color maroon;
+    extern const Color mediumaquamarine;
+    extern const Color mediumblue;
+    extern const Color mediumorchid;
+    extern const Color mediumpurple;
+    extern const Color mediumseagreen;
+    extern const Color mediumslateblue;
+    extern const Color mediumspringgreen;
+    extern const Color mediumturquoise;
+    extern const Color mediumvioletred;
+    extern const Color midnightblue;
+    extern const Color mintcream;
+    extern const Color mistyrose;
+    extern const Color moccasin;
+    extern const Color navajowhite;
+    extern const Color navy;
+    extern const Color oldlace;
+    extern const Color olive;
+    extern const Color olivedrab;
+    extern const Color orange;
+    extern const Color orangered;
+    extern const Color orchid;
+    extern const Color palegoldenrod;
+    extern const Color palegreen;
+    extern const Color paleturquoise;
+    extern const Color palevioletred;
+    extern const Color papayawhip;
+    extern const Color peachpuff;
+    extern const Color peru;
+    extern const Color pink;
+    extern const Color plum;
+    extern const Color powderblue;
+    extern const Color purple;
+    extern const Color red;
+    extern const Color rosybrown;
+    extern const Color royalblue;
+    extern const Color saddlebrown;
+    extern const Color salmon;
+    extern const Color sandybrown;
+    extern const Color seagreen;
+    extern const Color seashell;
+    extern const Color sienna;
+    extern const Color silver;
+    extern const Color skyblue;
+    extern const Color slateblue;
+    extern const Color slategray;
+    extern const Color slategrey;
+    extern const Color snow;
+    extern const Color springgreen;
+    extern const Color steelblue;
+    extern const Color tan;
+    extern const Color teal;
+    extern const Color thistle;
+    extern const Color tomato;
+    extern const Color turquoise;
+    extern const Color violet;
+    extern const Color wheat;
+    extern const Color white;
+    extern const Color whitesmoke;
+    extern const Color yellow;
+    extern const Color yellowgreen;
+    extern const Color rebeccapurple;
+    extern const Color transparent;
+  }
+
+  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 Color* name_to_color(const char*);
+  extern const Color* 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);
+
+}
+
+#endif
diff --git a/libsass/src/constants.cpp b/libsass/src/constants.cpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/constants.cpp
@@ -0,0 +1,176 @@
+#include "constants.hpp"
+
+namespace Sass {
+  namespace Constants {
+
+    extern const unsigned long MaxCallStack = 1024;
+
+    // https://github.com/sass/libsass/issues/592
+    // https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity
+    // https://github.com/sass/sass/issues/1495#issuecomment-61189114
+    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;
+
+    // sass keywords
+    extern const char at_root_kwd[]       = "@at-root";
+    extern const char import_kwd[]        = "@import";
+    extern const char mixin_kwd[]         = "@mixin";
+    extern const char function_kwd[]      = "@function";
+    extern const char return_kwd[]        = "@return";
+    extern const char include_kwd[]       = "@include";
+    extern const char content_kwd[]       = "@content";
+    extern const char extend_kwd[]        = "@extend";
+    extern const char if_kwd[]            = "@if";
+    extern const char else_kwd[]          = "@else";
+    extern const char if_after_else_kwd[] = "if";
+    extern const char for_kwd[]           = "@for";
+    extern const char from_kwd[]          = "from";
+    extern const char to_kwd[]            = "to";
+    extern const char through_kwd[]       = "through";
+    extern const char each_kwd[]          = "@each";
+    extern const char in_kwd[]            = "in";
+    extern const char while_kwd[]         = "@while";
+    extern const char warn_kwd[]          = "@warn";
+    extern const char error_kwd[]         = "@error";
+    extern const char debug_kwd[]         = "@debug";
+    extern const char default_kwd[]       = "default";
+    extern const char global_kwd[]        = "global";
+    extern const char null_kwd[]          = "null";
+    extern const char optional_kwd[]      = "optional";
+    extern const char with_kwd[]          = "with";
+    extern const char without_kwd[]       = "without";
+    extern const char all_kwd[]           = "all";
+    extern const char rule_kwd[]          = "rule";
+
+    // css standard units
+    extern const char em_kwd[]   = "em";
+    extern const char ex_kwd[]   = "ex";
+    extern const char px_kwd[]   = "px";
+    extern const char cm_kwd[]   = "cm";
+    extern const char mm_kwd[]   = "mm";
+    extern const char pt_kwd[]   = "pt";
+    extern const char pc_kwd[]   = "pc";
+    extern const char deg_kwd[]  = "deg";
+    extern const char rad_kwd[]  = "rad";
+    extern const char grad_kwd[] = "grad";
+    extern const char turn_kwd[] = "turn";
+    extern const char ms_kwd[]   = "ms";
+    extern const char s_kwd[]    = "s";
+    extern const char Hz_kwd[]   = "Hz";
+    extern const char kHz_kwd[]  = "kHz";
+
+    // vendor prefixes
+    extern const char vendor_opera_kwd[]    = "-o-";
+    extern const char vendor_webkit_kwd[]   = "-webkit-";
+    extern const char vendor_mozilla_kwd[]  = "-moz-";
+    extern const char vendor_ms_kwd[]       = "-ms-";
+    extern const char vendor_khtml_kwd[]    = "-khtml-";
+
+    // css functions and keywords
+    extern const char charset_kwd[]      = "@charset";
+    extern const char media_kwd[]        = "@media";
+    extern const char supports_kwd[]     = "@supports";
+    extern const char keyframes_kwd[]    = "keyframes";
+    extern const char only_kwd[]         = "only";
+    extern const char rgb_kwd[]          = "rgb(";
+    extern const char url_kwd[]          = "url(";
+    // extern const char url_prefix_kwd[]   = "url-prefix(";
+    extern const char important_kwd[]    = "important";
+    extern const char pseudo_not_kwd[]   = ":not(";
+    extern const char even_kwd[]         = "even";
+    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(";
+
+    // css selector keywords
+    extern const char sel_deep_kwd[] = "/deep/";
+
+    // css attribute-matching operators
+    extern const char tilde_equal[]  = "~=";
+    extern const char pipe_equal[]   = "|=";
+    extern const char caret_equal[]  = "^=";
+    extern const char dollar_equal[] = "$=";
+    extern const char star_equal[]   = "*=";
+
+    // relational & logical operators and constants
+    extern const char and_kwd[]   = "and";
+    extern const char or_kwd[]    = "or";
+    extern const char not_kwd[]   = "not";
+    extern const char gt[]        = ">";
+    extern const char gte[]       = ">=";
+    extern const char lt[]        = "<";
+    extern const char lte[]       = "<=";
+    extern const char eq[]        = "==";
+    extern const char neq[]       = "!=";
+    extern const char true_kwd[]  = "true";
+    extern const char false_kwd[] = "false";
+
+    // miscellaneous punctuation and delimiters
+    extern const char percent_str[]     = "%";
+    extern const char empty_str[]       = "";
+    extern const char slash_slash[]     = "//";
+    extern const char slash_star[]      = "/*";
+    extern const char star_slash[]      = "*/";
+    extern const char hash_lbrace[]     = "#{";
+    extern const char rbrace[]          = "}";
+    extern const char rparen[]          = ")";
+    extern const char sign_chars[]      = "-+";
+    extern const char hyphen[]          = "-";
+    extern const char ellipsis[]        = "...";
+    // extern const char url_space_chars[] = " \t\r\n\f";
+    // type names
+    extern const char numeric_name[]    = "numeric value";
+    extern const char number_name[]     = "number";
+    extern const char percentage_name[] = "percentage";
+    extern const char dimension_name[]  = "numeric dimension";
+    extern const char string_name[]     = "string";
+    extern const char bool_name[]       = "bool";
+    extern const char color_name[]      = "color";
+    extern const char list_name[]       = "list";
+    extern const char map_name[]        = "map";
+    extern const char arglist_name[]    = "arglist";
+
+    // constants for uri parsing (RFC 3986 Appendix A.)
+    extern const char uri_chars[]  = ":;/?!%&#@|[]{}'`^\"*+-.,_=~";
+    extern const char real_uri_chars[]  = "#%&";
+
+    // some specific constant character classes
+    // they must be static to be useable by lexer
+    extern const char static_ops[]      = "*/%";
+    // some character classes for the parser
+    extern const char selector_list_delims[] = "){};!";
+    extern const char complex_selector_delims[] = ",){};!";
+    extern const char selector_combinator_ops[] = "+~>";
+    // optional modifiers for alternative compare context
+    extern const char attribute_compare_modifiers[] = "~|^$*";
+    extern const char selector_lookahead_ops[] = "*&%,()[]";
+
+    // byte order marks
+    // (taken from http://en.wikipedia.org/wiki/Byte_order_mark)
+    extern const unsigned char utf_8_bom[]      = { 0xEF, 0xBB, 0xBF };
+    extern const unsigned char utf_16_bom_be[]  = { 0xFE, 0xFF };
+    extern const unsigned char utf_16_bom_le[]  = { 0xFF, 0xFE };
+    extern const unsigned char utf_32_bom_be[]  = { 0x00, 0x00, 0xFE, 0xFF };
+    extern const unsigned char utf_32_bom_le[]  = { 0xFF, 0xFE, 0x00, 0x00 };
+    extern const unsigned char utf_7_bom_1[]    = { 0x2B, 0x2F, 0x76, 0x38 };
+    extern const unsigned char utf_7_bom_2[]    = { 0x2B, 0x2F, 0x76, 0x39 };
+    extern const unsigned char utf_7_bom_3[]    = { 0x2B, 0x2F, 0x76, 0x2B };
+    extern const unsigned char utf_7_bom_4[]    = { 0x2B, 0x2F, 0x76, 0x2F };
+    extern const unsigned char utf_7_bom_5[]    = { 0x2B, 0x2F, 0x76, 0x38, 0x2D };
+    extern const unsigned char utf_1_bom[]      = { 0xF7, 0x64, 0x4C };
+    extern const unsigned char utf_ebcdic_bom[] = { 0xDD, 0x73, 0x66, 0x73 };
+    extern const unsigned char scsu_bom[]       = { 0x0E, 0xFE, 0xFF };
+    extern const unsigned char bocu_1_bom[]     = { 0xFB, 0xEE, 0x28 };
+    extern const unsigned char gb_18030_bom[]   = { 0x84, 0x31, 0x95, 0x33 };
+
+  }
+}
diff --git a/libsass/src/constants.hpp b/libsass/src/constants.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/constants.hpp
@@ -0,0 +1,179 @@
+#ifndef SASS_CONSTANTS_H
+#define SASS_CONSTANTS_H
+
+namespace Sass {
+  namespace Constants {
+
+    // The maximum call stack that can be created
+    extern const unsigned long MaxCallStack;
+
+    // https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity
+    // The following list of selectors is by increasing specificity:
+    extern const unsigned long Specificity_Star;
+    extern const unsigned long Specificity_Universal;
+    extern const unsigned long Specificity_Type;
+    extern const unsigned long Specificity_Class;
+    extern const unsigned long Specificity_Attr;
+    extern const unsigned long Specificity_Pseudo;
+    extern const unsigned long Specificity_ID;
+
+    // sass keywords
+    extern const char at_root_kwd[];
+    extern const char import_kwd[];
+    extern const char mixin_kwd[];
+    extern const char function_kwd[];
+    extern const char return_kwd[];
+    extern const char include_kwd[];
+    extern const char content_kwd[];
+    extern const char extend_kwd[];
+    extern const char if_kwd[];
+    extern const char else_kwd[];
+    extern const char if_after_else_kwd[];
+    extern const char for_kwd[];
+    extern const char from_kwd[];
+    extern const char to_kwd[];
+    extern const char through_kwd[];
+    extern const char each_kwd[];
+    extern const char in_kwd[];
+    extern const char while_kwd[];
+    extern const char warn_kwd[];
+    extern const char error_kwd[];
+    extern const char debug_kwd[];
+    extern const char default_kwd[];
+    extern const char global_kwd[];
+    extern const char null_kwd[];
+    extern const char optional_kwd[];
+    extern const char with_kwd[];
+    extern const char without_kwd[];
+    extern const char all_kwd[];
+    extern const char rule_kwd[];
+
+    // css standard units
+    extern const char em_kwd[];
+    extern const char ex_kwd[];
+    extern const char px_kwd[];
+    extern const char cm_kwd[];
+    extern const char mm_kwd[];
+    extern const char pt_kwd[];
+    extern const char pc_kwd[];
+    extern const char deg_kwd[];
+    extern const char rad_kwd[];
+    extern const char grad_kwd[];
+    extern const char turn_kwd[];
+    extern const char ms_kwd[];
+    extern const char s_kwd[];
+    extern const char Hz_kwd[];
+    extern const char kHz_kwd[];
+
+    // vendor prefixes
+    extern const char vendor_opera_kwd[];
+    extern const char vendor_webkit_kwd[];
+    extern const char vendor_mozilla_kwd[];
+    extern const char vendor_ms_kwd[];
+    extern const char vendor_khtml_kwd[];
+
+    // css functions and keywords
+    extern const char charset_kwd[];
+    extern const char media_kwd[];
+    extern const char supports_kwd[];
+    extern const char keyframes_kwd[];
+    extern const char only_kwd[];
+    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[];
+
+    // css selector keywords
+    extern const char sel_deep_kwd[];
+
+    // css attribute-matching operators
+    extern const char tilde_equal[];
+    extern const char pipe_equal[];
+    extern const char caret_equal[];
+    extern const char dollar_equal[];
+    extern const char star_equal[];
+
+    // relational & logical operators and constants
+    extern const char and_kwd[];
+    extern const char or_kwd[];
+    extern const char not_kwd[];
+    extern const char gt[];
+    extern const char gte[];
+    extern const char lt[];
+    extern const char lte[];
+    extern const char eq[];
+    extern const char neq[];
+    extern const char true_kwd[];
+    extern const char false_kwd[];
+
+    // miscellaneous punctuation and delimiters
+    extern const char percent_str[];
+    extern const char empty_str[];
+    extern const char slash_slash[];
+    extern const char slash_star[];
+    extern const char star_slash[];
+    extern const char hash_lbrace[];
+    extern const char rbrace[];
+    extern const char rparen[];
+    extern const char sign_chars[];
+    extern const char hyphen[];
+    extern const char ellipsis[];
+    // extern const char url_space_chars[];
+
+    // type names
+    extern const char numeric_name[];
+    extern const char number_name[];
+    extern const char percentage_name[];
+    extern const char dimension_name[];
+    extern const char string_name[];
+    extern const char bool_name[];
+    extern const char color_name[];
+    extern const char list_name[];
+    extern const char map_name[];
+    extern const char arglist_name[];
+
+    // constants for uri parsing (RFC 3986 Appendix A.)
+    extern const char uri_chars[];
+    extern const char real_uri_chars[];
+
+    // some specific constant character classes
+    // they must be static to be useable by lexer
+    extern const char static_ops[];
+    extern const char selector_list_delims[];
+    extern const char complex_selector_delims[];
+    extern const char selector_combinator_ops[];
+    extern const char attribute_compare_modifiers[];
+    extern const char selector_lookahead_ops[];
+
+    // byte order marks
+    // (taken from http://en.wikipedia.org/wiki/Byte_order_mark)
+    extern const unsigned char utf_8_bom[];
+    extern const unsigned char utf_16_bom_be[];
+    extern const unsigned char utf_16_bom_le[];
+    extern const unsigned char utf_32_bom_be[];
+    extern const unsigned char utf_32_bom_le[];
+    extern const unsigned char utf_7_bom_1[];
+    extern const unsigned char utf_7_bom_2[];
+    extern const unsigned char utf_7_bom_3[];
+    extern const unsigned char utf_7_bom_4[];
+    extern const unsigned char utf_7_bom_5[];
+    extern const unsigned char utf_1_bom[];
+    extern const unsigned char utf_ebcdic_bom[];
+    extern const unsigned char scsu_bom[];
+    extern const unsigned char bocu_1_bom[];
+    extern const unsigned char gb_18030_bom[];
+
+  }
+}
+
+#endif
diff --git a/libsass/src/context.cpp b/libsass/src/context.cpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/context.cpp
@@ -0,0 +1,848 @@
+#ifdef _WIN32
+#define PATH_SEP ';'
+#else
+#define PATH_SEP ':'
+#endif
+
+#include <string>
+#include <cstdlib>
+#include <cstring>
+#include <iomanip>
+#include <sstream>
+#include <iostream>
+
+#include "ast.hpp"
+#include "util.hpp"
+#include "sass.h"
+#include "context.hpp"
+#include "plugins.hpp"
+#include "constants.hpp"
+#include "parser.hpp"
+#include "file.hpp"
+#include "inspect.hpp"
+#include "output.hpp"
+#include "expand.hpp"
+#include "eval.hpp"
+#include "cssize.hpp"
+#include "listize.hpp"
+#include "extend.hpp"
+#include "remove_placeholders.hpp"
+#include "functions.hpp"
+#include "backtrace.hpp"
+#include "sass2scss.h"
+#include "prelexer.hpp"
+#include "emitter.hpp"
+
+namespace Sass {
+  using namespace Constants;
+  using namespace File;
+  using namespace Sass;
+
+  inline bool sort_importers (const Sass_Importer_Entry& i, const Sass_Importer_Entry& j)
+  { return sass_importer_get_priority(i) > sass_importer_get_priority(j); }
+
+  static std::string safe_input(const char* in_path)
+  {
+    // enforce some safe defaults
+    // used to create relative file links
+    std::string safe_path(in_path ? in_path : "");
+    return safe_path == "" ? "stdin" : safe_path;
+  }
+
+  static std::string safe_output(const char* out_path, const std::string& input_path = "")
+  {
+    std::string safe_path(out_path ? out_path : "");
+    // maybe we can extract an output path from input path
+    if (safe_path == "" && input_path != "") {
+      int lastindex = static_cast<int>(input_path.find_last_of("."));
+      return (lastindex > -1 ? input_path.substr(0, lastindex) : input_path) + ".css";
+    }
+    // enforce some safe defaults
+    // used to create relative file links
+    return safe_path == "" ? "stdout" : safe_path;
+  }
+
+  Context::Context(struct Sass_Context* c_ctx)
+  : CWD(File::get_cwd()),
+    entry_path(""),
+    head_imports(0),
+    mem(Memory_Manager()),
+    plugins(),
+    emitter(this),
+
+    strings(),
+    resources(),
+    sheets(),
+    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")),
+
+    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, "")))
+
+  {
+
+    // add cwd to include paths
+    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());
+
+    // load plugins and register custom behaviors
+    for(auto plug : plugin_paths) plugins.load_plugins(plug);
+    for(auto fn : plugins.get_headers()) c_headers.push_back(fn);
+    for(auto fn : plugins.get_importers()) c_importers.push_back(fn);
+    for(auto fn : plugins.get_functions()) c_functions.push_back(fn);
+
+    // sort the items by priority (lowest first)
+    sort (c_headers.begin(), c_headers.end(), sort_importers);
+    sort (c_importers.begin(), c_importers.end(), sort_importers);
+
+    emitter.set_filename(abs2rel(output_path, source_map_file, CWD));
+
+  }
+
+  void Context::add_c_function(Sass_Function_Entry function)
+  {
+    c_functions.push_back(function);
+  }
+  void Context::add_c_header(Sass_Importer_Entry header)
+  {
+    c_headers.push_back(header);
+    // need to sort the array afterwards (no big deal)
+    sort (c_headers.begin(), c_headers.end(), sort_importers);
+  }
+  void Context::add_c_importer(Sass_Importer_Entry importer)
+  {
+    c_importers.push_back(importer);
+    // need to sort the array afterwards (no big deal)
+    sort (c_importers.begin(), c_importers.end(), sort_importers);
+  }
+
+  Context::~Context()
+  {
+    // resources were allocated by strdup or malloc
+    for (size_t i = 0; i < resources.size(); ++i) {
+      free(resources[i].contents);
+      free(resources[i].srcmap);
+    }
+    // free all strings we kept alive during compiler execution
+    for (size_t n = 0; n < strings.size(); ++n) free(strings[n]);
+    // everything that gets put into sources will be freed by us
+    // this shouldn't have anything in it anyway!?
+    for (size_t m = 0; m < import_stack.size(); ++m) {
+      sass_import_take_source(import_stack[m]);
+      sass_import_take_srcmap(import_stack[m]);
+      sass_delete_import(import_stack[m]);
+    }
+    // clear inner structures (vectors) and input source
+    resources.clear(); import_stack.clear();
+  }
+
+  Data_Context::~Data_Context()
+  {
+    // --> this will be freed by resources
+    // make sure we free the source even if not processed!
+    // if (resources.size() == 0 && source_c_str) free(source_c_str);
+    // if (resources.size() == 0 && srcmap_c_str) free(srcmap_c_str);
+    // source_c_str = 0; srcmap_c_str = 0;
+  }
+
+  File_Context::~File_Context()
+  {
+  }
+
+  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);
+
+      while (end) {
+        std::string path(beg, end - beg);
+        if (!path.empty()) {
+          if (*path.rbegin() != '/') path += '/';
+          include_paths.push_back(path);
+        }
+        beg = end + 1;
+        end = Prelexer::find_first<PATH_SEP>(beg);
+      }
+
+      std::string path(beg);
+      if (!path.empty()) {
+        if (*path.rbegin() != '/') path += '/';
+        include_paths.push_back(path);
+      }
+    }
+  }
+
+  void Context::collect_include_paths(const char** paths_array)
+  {
+    if (!paths_array) return;
+    for (size_t i = 0; paths_array[i]; i++) {
+      collect_include_paths(paths_array[i]);
+    }
+  }
+
+  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);
+
+      while (end) {
+        std::string path(beg, end - beg);
+        if (!path.empty()) {
+          if (*path.rbegin() != '/') path += '/';
+          plugin_paths.push_back(path);
+        }
+        beg = end + 1;
+        end = Prelexer::find_first<PATH_SEP>(beg);
+      }
+
+      std::string path(beg);
+      if (!path.empty()) {
+        if (*path.rbegin() != '/') path += '/';
+        plugin_paths.push_back(path);
+      }
+    }
+  }
+
+  void Context::collect_plugin_paths(const char** paths_array)
+  {
+    if (!paths_array) return;
+    for (size_t i = 0; paths_array[i]; i++) {
+      collect_plugin_paths(paths_array[i]);
+    }
+  }
+
+
+  // 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)
+  {
+    // make sure we resolve against an absolute path
+    std::string base_path(rel2abs(import.base_path));
+    // first try to resolve the load path relative to the base path
+    std::vector<Include> vec(resolve_includes(base_path, import.imp_path));
+    // then search in every include path (but only if nothing found yet)
+    for (size_t i = 0, S = include_paths.size(); vec.size() == 0 && i < S; ++i)
+    {
+      // call resolve_includes and individual base path and append all results
+      std::vector<Include> resolved(resolve_includes(include_paths[i], import.imp_path));
+      if (resolved.size()) vec.insert(vec.end(), resolved.begin(), resolved.end());
+    }
+    // return vector
+    return vec;
+  }
+
+
+  // register include with resolved path and its content
+  // memory of the resources will be freed by us on exit
+  void Context::register_resource(const Include& inc, const Resource& res)
+  {
+
+    // do not parse same resource twice
+    // maybe raise an error in this case
+    // if (sheets.count(inc.abs_path)) {
+    //   free(res.contents); free(res.srcmap);
+    //   throw std::runtime_error("duplicate resource registered");
+    //   return;
+    // }
+
+    // get index for this resource
+    size_t idx = resources.size();
+
+    // tell emitter about new resource
+    emitter.add_source_index(idx);
+
+    // put resources under our control
+    // the memory will be freed later
+    resources.push_back(res);
+
+    // add a relative link to the working directory
+    included_files.push_back(inc.abs_path);
+    // add a relative link  to the source map output file
+    srcmap_links.push_back(abs2rel(inc.abs_path, source_map_file, CWD));
+
+    // get pointer to the loaded content
+    Sass_Import_Entry import = sass_make_import(
+      inc.imp_path.c_str(),
+      inc.abs_path.c_str(),
+      res.contents,
+      res.srcmap
+    );
+    // add the entry to the stack
+    import_stack.push_back(import);
+
+    // get pointer to the loaded content
+    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()));
+    // create the initial parser state from resource
+    ParserState pstate(strings.back(), contents, idx);
+    // 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();
+    // 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>
+      ast_pair(inc.abs_path, { res, root });
+    // register resulting resource
+    sheets.insert(ast_pair);
+
+  }
+
+  // Add a new import to the context (called from `import_url`)
+  Include Context::load_import(const Importer& imp, ParserState pstate)
+  {
+
+    // search for valid imports (ie. partials) on the filesystem
+    // this may return more than one valid result (ambiguous imp_path)
+    const std::vector<Include> resolved(find_includes(imp));
+
+    // error nicely on ambiguous imp_path
+    if (resolved.size() > 1) {
+      std::stringstream msg_stream;
+      msg_stream << "It's not clear which file to import for ";
+      msg_stream << "'@import \"" << imp.imp_path << "\"'." << "\n";
+      msg_stream << "Candidates:" << "\n";
+      for (size_t i = 0, L = resolved.size(); i < L; ++i)
+      { msg_stream << "  " << resolved[i].imp_path << "\n"; }
+      msg_stream << "Please delete or rename all but one of these files." << "\n";
+      error(msg_stream.str(), pstate);
+    }
+
+    // process the resolved entry
+    else if (resolved.size() == 1) {
+      // use cache for the resource loading
+      if (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 });
+        // return resolved entry
+        return resolved[0];
+      }
+    }
+
+    // nothing found
+    return { imp, "" };
+
+  }
+
+  void Context::import_url (Import* imp, std::string load_path, const std::string& ctx_path) {
+
+    ParserState pstate(imp->pstate());
+    std::string imp_path(unquote(load_path));
+    std::string protocol("file");
+
+    using namespace Prelexer;
+    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) {
+
+      }
+    }
+
+    // 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));
+    }
+    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);
+      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);
+      }
+      imp->incs().push_back(include);
+    }
+
+  }
+
+
+  // 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)
+  {
+    // unique counter
+    size_t count = 0;
+    // need one correct import
+    bool has_import = false;
+    // process all custom importers (or custom headers)
+    for (Sass_Importer_Entry& importer : importers) {
+      // int priority = sass_importer_get_priority(importer);
+      Sass_Importer_Fn fn = sass_importer_get_function(importer);
+      // skip importer if it returns NULL
+      if (Sass_Import_List includes =
+          fn(load_path.c_str(), importer, c_compiler)
+      ) {
+        // get c pointer copy to iterate over
+        Sass_Import_List it_includes = includes;
+        while (*it_includes) { ++count;
+          // create unique path to use as key
+          std::string uniq_path = load_path;
+          if (!only_one && count) {
+            std::stringstream path_strm;
+            path_strm << uniq_path << ":" << count;
+            uniq_path = path_strm.str();
+          }
+          // create the importer struct
+          Importer importer(uniq_path, ctx_path);
+          // query data from the current include
+          Sass_Import_Entry include = *it_includes;
+          char* source = sass_import_take_source(include);
+          char* srcmap = sass_import_take_source(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 (line == std::string::npos && column == std::string::npos) error(err_message, pstate);
+            else error(err_message, ParserState(ctx_path, source, Position(line, column)));
+          }
+          // content for import was set
+          else if (source) {
+            // resolved abs_path should be set by custom importer
+            // use the created uniq_path as fallback (maybe enforce)
+            std::string path_key(abs_path ? abs_path : uniq_path);
+            // create the importer struct
+            Include include(importer, path_key);
+            // attach information to AST node
+            imp->incs().push_back(include);
+            // register the resource buffers
+            register_resource(include, { source, srcmap });
+          }
+          // only a path was retuned
+          // try to load it like normal
+          else if(abs_path) {
+            // checks some urls to preserve
+            // `http://`, `https://` and `//`
+            // or dispatchs to `import_file`
+            // which will check for a `.css` extension
+            // or resolves the file on the filesystem
+            // added and resolved via `add_file`
+            // finally stores everything on `imp`
+            import_url(imp, abs_path, ctx_path);
+          }
+          // move to next
+          ++it_includes;
+        }
+        // deallocate the returned memory
+        sass_delete_import_list(includes);
+        // set success flag
+        has_import = true;
+        // break out of loop
+        if (only_one) break;
+      }
+    }
+    // return result
+    return has_import;
+  }
+
+  void register_function(Context&, Signature sig, Native_Function f, Env* env);
+  void register_function(Context&, Signature sig, Native_Function f, size_t arity, Env* env);
+  void register_overload_stub(Context&, std::string name, Env* env);
+  void register_built_in_functions(Context&, Env* env);
+  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)
+  {
+    // check for valid block
+    if (!root) return 0;
+    // start the render process
+    root->perform(&emitter);
+    // finish emitter stream
+    emitter.finalize();
+    // 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) {
+      // generate an embeded source map
+      if (c_options->source_map_embed) {
+        emitted.buffer += linefeed;
+        emitted.buffer += format_embedded_source_map();
+      }
+      // or just link the generated one
+      else if (source_map_file != "") {
+        emitted.buffer += linefeed;
+        emitted.buffer += format_source_mapping_url(source_map_file);
+      }
+    }
+    // create a copy of the resulting buffer string
+    // this must be freed or taken over by implementor
+    return sass_strdup(emitted.buffer.c_str());
+  }
+
+  void Context::apply_custom_headers(Block* root, const char* ctx_path, ParserState pstate)
+  {
+    // create a custom import to resolve headers
+    Import* imp = SASS_MEMORY_NEW(mem, 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);
+    // increase head count to skip later
+    head_imports += resources.size() - 1;
+    // add the statement if we have urls
+    if (!imp->urls().empty()) (*root) << 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]);
+    }
+  }
+
+  Block* File_Context::parse()
+  {
+
+    // check if entry file is given
+    if (input_path.empty()) return 0;
+
+    // create absolute path from input filename
+    // ToDo: this should be resolved via custom importers
+    std::string abs_path(rel2abs(input_path, CWD));
+
+    // try to load the entry file
+    char* contents = read_file(abs_path);
+
+    // alternatively also look inside each include path folder
+    // I think this differs from ruby sass (IMO too late to remove)
+    for (size_t i = 0, S = include_paths.size(); contents == 0 && i < S; ++i) {
+      // build absolute path for this include path entry
+      abs_path = rel2abs(input_path, include_paths[i]);
+      // try to load the resulting path
+      contents = read_file(abs_path);
+    }
+
+    // abort early if no content could be loaded (various reasons)
+    if (!contents) throw "File to read not found or unreadable: " + input_path;
+
+    // store entry path
+    entry_path = abs_path;
+
+    // create entry only for import stack
+    Sass_Import_Entry import = sass_make_import(
+      input_path.c_str(),
+      entry_path.c_str(),
+      contents,
+      0
+    );
+    // add the entry to the stack
+    import_stack.push_back(import);
+
+    // create the source entry for file entry
+    register_resource({{ input_path, "." }, abs_path }, { contents, 0 });
+
+    // create root ast tree node
+    return compile();
+
+  }
+
+  Block* 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) {
+      // call sass2scss to convert the string
+      char * converted = sass2scss(source_c_str,
+        // preserve the structure as much as possible
+        SASS2SCSS_PRETTIFY_1 | SASS2SCSS_KEEP_COMMENT);
+      // replace old source_c_str with converted
+      free(source_c_str); source_c_str = converted;
+    }
+
+    // remember entry path (defaults to stdin for string)
+    entry_path = input_path.empty() ? "stdin" : input_path;
+
+    // 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());
+    strings.push_back(abs_path_c_str);
+
+    // create entry only for the import stack
+    Sass_Import_Entry import = sass_make_import(
+      entry_path.c_str(),
+      abs_path_c_str,
+      source_c_str,
+      srcmap_c_str
+    );
+    // add the entry to the stack
+    import_stack.push_back(import);
+
+    // register a synthetic resource (path does not really exist, skip in includes)
+    register_resource({{ input_path, "." }, input_path }, { source_c_str, srcmap_c_str });
+
+    // create root ast tree node
+    return compile();
+  }
+
+
+
+  // parse root block from includes
+  Block* 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;
+    // abort on invalid root
+    if (root == 0) return 0;
+
+    Env global; // create root environment
+    // register built-in functions on env
+    register_built_in_functions(*this, &global);
+    // register custom functions (defined via C-API)
+    for (size_t i = 0, S = c_functions.size(); i < S; ++i)
+    { register_c_function(*this, &global, c_functions[i]); }
+    // create initial backtrace entry
+    Backtrace backtrace(0, ParserState("", 0), "");
+    // create crtp visitor objects
+    Expand expand(*this, &global, &backtrace);
+    Cssize cssize(*this, &backtrace);
+    // expand and eval the tree
+    root = root->perform(&expand)->block();
+    // merge and bubble certain rules
+    root = root->perform(&cssize)->block();
+    // should we extend something?
+    if (!subset_map.empty()) {
+      // create crtp visitor object
+      Extend extend(*this, subset_map);
+      // extend tree nodes
+      root->perform(&extend);
+    }
+
+    // clean up by removing empty placeholders
+    // ToDo: maybe we can do this somewhere else?
+    Remove_Placeholders remove_placeholders(*this);
+    root->perform(&remove_placeholders);
+    // return processed tree
+    return root;
+  }
+  // EO compile
+
+  std::string Context::format_embedded_source_map()
+  {
+    std::string map = emitter.render_srcmap(*this);
+    std::istringstream is( map );
+    std::ostringstream buffer;
+    base64::encoder E;
+    E.encode(is, buffer);
+    std::string url = "data:application/json;base64," + buffer.str();
+    url.erase(url.size() - 1);
+    return "/*# sourceMappingURL=" + url + " */";
+  }
+
+  std::string Context::format_source_mapping_url(const std::string& file)
+  {
+    std::string url = abs2rel(file, output_path, CWD);
+    return "/*# sourceMappingURL=" + url + " */";
+  }
+
+  char* Context::render_srcmap()
+  {
+    if (source_map_file == "") return 0;
+    char* result = 0;
+    std::string map = emitter.render_srcmap(*this);
+    result = sass_strdup(map.c_str());
+    return result;
+  }
+
+
+  // for data context we want to start after "stdin"
+  // we probably always want to skip the header includes?
+  std::vector<std::string> Context::get_included_files(bool skip, size_t headers)
+  {
+      // create a copy of the vector for manipulations
+      std::vector<std::string> includes = included_files;
+      if (includes.size() == 0) return includes;
+      if (skip) { includes.erase( includes.begin(), includes.begin() + 1 + headers); }
+      else { includes.erase( includes.begin() + 1, includes.begin() + 1 + headers); }
+      includes.erase( std::unique( includes.begin(), includes.end() ), includes.end() );
+      std::sort( includes.begin() + (skip ? 0 : 1), includes.end() );
+      return includes;
+  }
+
+  void register_function(Context& ctx, Signature sig, Native_Function f, Env* env)
+  {
+    Definition* 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);
+    std::stringstream ss;
+    ss << def->name() << "[f]" << arity;
+    def->environment(env);
+    (*env)[ss.str()] = def;
+  }
+
+  void register_overload_stub(Context& ctx, std::string name, Env* env)
+  {
+    Definition* stub = SASS_MEMORY_NEW(ctx.mem, Definition,
+                                       ParserState("[built-in function]"),
+                                       0,
+                                       name,
+                                       0,
+                                       0,
+                                       true);
+    (*env)[name + "[f]"] = stub;
+  }
+
+
+  void register_built_in_functions(Context& ctx, Env* env)
+  {
+    using namespace Functions;
+    // RGB Functions
+    register_function(ctx, rgb_sig, rgb, env);
+    register_overload_stub(ctx, "rgba", env);
+    register_function(ctx, rgba_4_sig, rgba_4, 4, env);
+    register_function(ctx, rgba_2_sig, rgba_2, 2, env);
+    register_function(ctx, red_sig, red, env);
+    register_function(ctx, green_sig, green, env);
+    register_function(ctx, blue_sig, blue, env);
+    register_function(ctx, mix_sig, mix, env);
+    // HSL Functions
+    register_function(ctx, hsl_sig, hsl, env);
+    register_function(ctx, hsla_sig, hsla, env);
+    register_function(ctx, hue_sig, hue, env);
+    register_function(ctx, saturation_sig, saturation, env);
+    register_function(ctx, lightness_sig, lightness, env);
+    register_function(ctx, adjust_hue_sig, adjust_hue, env);
+    register_function(ctx, lighten_sig, lighten, env);
+    register_function(ctx, darken_sig, darken, env);
+    register_function(ctx, saturate_sig, saturate, env);
+    register_function(ctx, desaturate_sig, desaturate, env);
+    register_function(ctx, grayscale_sig, grayscale, env);
+    register_function(ctx, complement_sig, complement, env);
+    register_function(ctx, invert_sig, invert, env);
+    // Opacity Functions
+    register_function(ctx, alpha_sig, alpha, env);
+    register_function(ctx, opacity_sig, alpha, env);
+    register_function(ctx, opacify_sig, opacify, env);
+    register_function(ctx, fade_in_sig, opacify, env);
+    register_function(ctx, transparentize_sig, transparentize, env);
+    register_function(ctx, fade_out_sig, transparentize, env);
+    // Other Color Functions
+    register_function(ctx, adjust_color_sig, adjust_color, env);
+    register_function(ctx, scale_color_sig, scale_color, env);
+    register_function(ctx, change_color_sig, change_color, env);
+    register_function(ctx, ie_hex_str_sig, ie_hex_str, env);
+    // String Functions
+    register_function(ctx, unquote_sig, sass_unquote, env);
+    register_function(ctx, quote_sig, sass_quote, env);
+    register_function(ctx, str_length_sig, str_length, env);
+    register_function(ctx, str_insert_sig, str_insert, env);
+    register_function(ctx, str_index_sig, str_index, env);
+    register_function(ctx, str_slice_sig, str_slice, env);
+    register_function(ctx, to_upper_case_sig, to_upper_case, env);
+    register_function(ctx, to_lower_case_sig, to_lower_case, env);
+    // Number Functions
+    register_function(ctx, percentage_sig, percentage, env);
+    register_function(ctx, round_sig, round, env);
+    register_function(ctx, ceil_sig, ceil, env);
+    register_function(ctx, floor_sig, floor, env);
+    register_function(ctx, abs_sig, abs, env);
+    register_function(ctx, min_sig, min, env);
+    register_function(ctx, max_sig, max, env);
+    register_function(ctx, random_sig, random, env);
+    // List Functions
+    register_function(ctx, length_sig, length, env);
+    register_function(ctx, nth_sig, nth, env);
+    register_function(ctx, set_nth_sig, set_nth, env);
+    register_function(ctx, index_sig, index, env);
+    register_function(ctx, join_sig, join, env);
+    register_function(ctx, append_sig, append, env);
+    register_function(ctx, zip_sig, zip, env);
+    register_function(ctx, list_separator_sig, list_separator, env);
+    // Map Functions
+    register_function(ctx, map_get_sig, map_get, env);
+    register_function(ctx, map_merge_sig, map_merge, env);
+    register_function(ctx, map_remove_sig, map_remove, env);
+    register_function(ctx, map_keys_sig, map_keys, env);
+    register_function(ctx, map_values_sig, map_values, env);
+    register_function(ctx, map_has_key_sig, map_has_key, env);
+    register_function(ctx, keywords_sig, keywords, env);
+    // Introspection Functions
+    register_function(ctx, type_of_sig, type_of, env);
+    register_function(ctx, unit_sig, unit, env);
+    register_function(ctx, unitless_sig, unitless, env);
+    register_function(ctx, comparable_sig, comparable, env);
+    register_function(ctx, variable_exists_sig, variable_exists, env);
+    register_function(ctx, global_variable_exists_sig, global_variable_exists, env);
+    register_function(ctx, function_exists_sig, function_exists, env);
+    register_function(ctx, mixin_exists_sig, mixin_exists, env);
+    register_function(ctx, feature_exists_sig, feature_exists, env);
+    register_function(ctx, call_sig, call, env);
+    // Boolean Functions
+    register_function(ctx, not_sig, sass_not, env);
+    register_function(ctx, if_sig, sass_if, env);
+    // Misc Functions
+    register_function(ctx, inspect_sig, inspect, env);
+    register_function(ctx, unique_id_sig, unique_id, env);
+    // Selector functions
+    register_function(ctx, selector_nest_sig, selector_nest, env);
+    register_function(ctx, selector_append_sig, selector_append, env);
+    register_function(ctx, selector_extend_sig, selector_extend, env);
+    register_function(ctx, selector_replace_sig, selector_replace, env);
+    register_function(ctx, selector_unify_sig, selector_unify, env);
+    register_function(ctx, is_superselector_sig, is_superselector, env);
+    register_function(ctx, simple_selectors_sig, simple_selectors, env);
+    register_function(ctx, selector_parse_sig, selector_parse, env);
+  }
+
+  void register_c_functions(Context& ctx, Env* env, Sass_Function_List descrs)
+  {
+    while (descrs && *descrs) {
+      register_c_function(ctx, env, *descrs);
+      ++descrs;
+    }
+  }
+  void register_c_function(Context& ctx, Env* env, Sass_Function_Entry descr)
+  {
+    Definition* 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
new file mode 100644
--- /dev/null
+++ b/libsass/src/context.hpp
@@ -0,0 +1,147 @@
+#ifndef SASS_CONTEXT_H
+#define SASS_CONTEXT_H
+
+#include <string>
+#include <vector>
+#include <map>
+
+#define BUFFERSIZE 255
+#include "b64/encode.h"
+
+#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"
+#include "source_map.hpp"
+#include "subset_map.hpp"
+#include "output.hpp"
+#include "plugins.hpp"
+#include "file.hpp"
+
+
+struct Sass_Function;
+
+namespace Sass {
+
+  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)
+    { 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)
+    { 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);
+
+  public:
+    const std::string CWD;
+    std::string entry_path;
+    size_t head_imports;
+    Memory_Manager mem;
+    Plugins plugins;
+    Output emitter;
+
+    // resources add under our control
+    // 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::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;
+    // relative includes for sourcemap
+    std::vector<std::string> srcmap_links;
+    // vectors above have same size
+
+    std::vector<std::string> plugin_paths; // relative paths to load plugins
+    std::vector<std::string> include_paths; // lookup paths for includes
+
+
+
+
+
+    void apply_custom_headers(Block* root, const char* path, ParserState pstate);
+
+    std::vector<Sass_Importer_Entry> c_headers;
+    std::vector<Sass_Importer_Entry> c_importers;
+    std::vector<Sass_Function_Entry> c_functions;
+
+    void add_c_header(Sass_Importer_Entry header);
+    void add_c_importer(Sass_Importer_Entry importer);
+    void add_c_function(Sass_Function_Entry function);
+
+    const std::string indent; // String to be used for indentation
+    const std::string linefeed; // String to be used for line feeds
+    const std::string input_path; // for relative paths in src-map
+    const std::string output_path; // for relative paths to the output
+    const std::string source_map_file; // path to source map file (enables feature)
+    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);
+    virtual char* render_srcmap();
+
+    void register_resource(const Include&, const Resource&);
+    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; };
+    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_include_paths(const char* paths_str);
+    void collect_include_paths(const char** paths_array);
+    std::string format_embedded_source_map();
+    std::string format_source_mapping_url(const std::string& out_path);
+
+
+    // void register_built_in_functions(Env* env);
+    // void register_function(Signature sig, Native_Function f, Env* env);
+    // void register_function(Signature sig, Native_Function f, size_t arity, Env* env);
+    // void register_overload_stub(std::string name, Env* env);
+
+  public:
+    const std::string& cwd() { return CWD; };
+  };
+
+  class File_Context : public Context {
+  public:
+    File_Context(struct Sass_File_Context* ctx)
+    : Context(ctx)
+    { }
+    virtual ~File_Context();
+    virtual Block* parse();
+  };
+
+  class Data_Context : public Context {
+  public:
+    char* source_c_str;
+    char* srcmap_c_str;
+    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
+    }
+    virtual ~Data_Context();
+    virtual Block* parse();
+  };
+
+}
+
+#endif
diff --git a/libsass/src/cssize.cpp b/libsass/src/cssize.cpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/cssize.cpp
@@ -0,0 +1,565 @@
+#include <iostream>
+#include <typeinfo>
+#include <vector>
+
+#include "cssize.hpp"
+#include "to_string.hpp"
+#include "context.hpp"
+#include "backtrace.hpp"
+
+namespace Sass {
+
+  Cssize::Cssize(Context& ctx, Backtrace* bt)
+  : ctx(ctx),
+    block_stack(std::vector<Block*>()),
+    p_stack(std::vector<Statement*>()),
+    backtrace(bt)
+  {  }
+
+  Statement* Cssize::parent()
+  {
+    return p_stack.size() ? p_stack.back() : block_stack.front();
+  }
+
+  Statement* Cssize::operator()(Block* b)
+  {
+    Block* bb = SASS_MEMORY_NEW(ctx.mem, Block, b->pstate(), b->length(), b->is_root());
+    // bb->tabs(b->tabs());
+    block_stack.push_back(bb);
+    append_block(b);
+    block_stack.pop_back();
+    return bb;
+  }
+
+  Statement* Cssize::operator()(At_Rule* 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);
+    }
+
+    p_stack.push_back(r);
+    At_Rule* rr = SASS_MEMORY_NEW(ctx.mem, At_Rule,
+                                  r->pstate(),
+                                  r->keyword(),
+                                  r->selector(),
+                                  r->block() ? r->block()->perform(this)->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];
+      if (s->statement_type() != Statement::BUBBLE) directive_exists = true;
+      else {
+        s = static_cast<Bubble*>(s)->node();
+        if (s->statement_type() != Statement::DIRECTIVE) directive_exists = false;
+        else directive_exists = (static_cast<At_Rule*>(s)->keyword() == rr->keyword());
+      }
+
+    }
+
+    Block* result = SASS_MEMORY_NEW(ctx.mem, 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;
+    }
+
+    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];
+    }
+
+    return result;
+  }
+
+  Statement* Cssize::operator()(Keyframe_Rule* r)
+  {
+    if (!r->block() || !r->block()->length()) return r;
+
+    Keyframe_Rule* rr = SASS_MEMORY_NEW(ctx.mem, Keyframe_Rule,
+                                        r->pstate(),
+                                        r->block()->perform(this)->block());
+    if (r->selector()) rr->selector(r->selector());
+
+    return debubble(rr->block(), rr)->block();
+  }
+
+  Statement* Cssize::operator()(Ruleset* r)
+  {
+    p_stack.push_back(r);
+    Ruleset* rr = SASS_MEMORY_NEW(ctx.mem, Ruleset,
+                                  r->pstate(),
+                                  r->selector(),
+                                  r->block()->perform(this)->block());
+    // 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());
+    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;
+    }
+
+    if (props->length())
+    {
+      Block* bb = SASS_MEMORY_NEW(ctx.mem, Block, rr->block()->pstate());
+      *bb += props;
+      rr->block(bb);
+
+      for (size_t i = 0, L = rules->length(); i < L; i++)
+      {
+        (*rules)[i]->tabs((*rules)[i]->tabs() + 1);
+      }
+
+      rules->unshift(rr);
+    }
+
+    rules = debubble(rules)->block();
+
+    if (!(!rules->length() ||
+          !bubblable(rules->last()) ||
+          parent()->statement_type() == Statement::RULESET))
+    {
+      rules->last()->group_end(true);
+    }
+
+    return rules;
+  }
+
+  Statement* Cssize::operator()(Null* m)
+  {
+    return 0;
+  }
+
+  Statement* Cssize::operator()(Media_Block* 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); }
+
+    p_stack.push_back(m);
+
+    Media_Block* mm = SASS_MEMORY_NEW(ctx.mem, Media_Block,
+                                      m->pstate(),
+                                      m->media_queries(),
+                                      m->block()->perform(this)->block());
+    mm->tabs(m->tabs());
+
+    p_stack.pop_back();
+
+    return debubble(mm->block(), mm)->block();
+  }
+
+  Statement* Cssize::operator()(Supports_Block* m)
+  {
+    if (!m->block()->length())
+    { return m; }
+
+    if (parent()->statement_type() == Statement::RULESET)
+    { return bubble(m); }
+
+    p_stack.push_back(m);
+
+    Supports_Block* mm = SASS_MEMORY_NEW(ctx.mem, Supports_Block,
+                                       m->pstate(),
+                                       m->condition(),
+                                       m->block()->perform(this)->block());
+    mm->tabs(m->tabs());
+
+    p_stack.pop_back();
+
+    return debubble(mm->block(), mm)->block();
+  }
+
+  Statement* Cssize::operator()(At_Root_Block* m)
+  {
+    bool tmp = false;
+    for (size_t i = 0, L = p_stack.size(); i < L; ++i) {
+      Statement* s = p_stack[i];
+      tmp |= m->exclude_node(s);
+    }
+
+    if (!tmp)
+    {
+      Block* bb = m->block()->perform(this)->block();
+      for (size_t i = 0, L = bb->length(); i < L; ++i) {
+        // (bb->elements())[i]->tabs(m->tabs());
+        if (bubblable((*bb)[i])) (*bb)[i]->tabs((*bb)[i]->tabs() + m->tabs());
+      }
+      if (bb->length() && bubblable(bb->last())) bb->last()->group_end(m->group_end());
+      return bb;
+    }
+
+    if (m->exclude_node(parent()))
+    {
+      return SASS_MEMORY_NEW(ctx.mem, Bubble, m->pstate(), m);
+    }
+
+    return bubble(m);
+  }
+
+  Statement* Cssize::bubble(At_Rule* m)
+  {
+    Block* bb = SASS_MEMORY_NEW(ctx.mem, Block, this->parent()->pstate());
+    Has_Block* new_rule = static_cast<Has_Block*>(shallow_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];
+    }
+
+    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,
+                                  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);
+    return bubble;
+  }
+
+  Statement* Cssize::bubble(At_Root_Block* m)
+  {
+    Block* bb = SASS_MEMORY_NEW(ctx.mem, Block, this->parent()->pstate());
+    Has_Block* new_rule = static_cast<Has_Block*>(shallow_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];
+    }
+
+    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,
+                                        m->pstate(),
+                                        wrapper_block,
+                                        m->expression());
+    Bubble* bubble = SASS_MEMORY_NEW(ctx.mem, Bubble, mm->pstate(), mm);
+    return bubble;
+  }
+
+  Statement* Cssize::bubble(Supports_Block* m)
+  {
+    Ruleset* parent = static_cast<Ruleset*>(shallow_copy(this->parent()));
+
+    Block* bb = SASS_MEMORY_NEW(ctx.mem, Block, parent->block()->pstate());
+    Ruleset* new_rule = SASS_MEMORY_NEW(ctx.mem, 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];
+    }
+
+    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,
+                                       m->pstate(),
+                                       m->condition(),
+                                       wrapper_block);
+
+    mm->tabs(m->tabs());
+
+    Bubble* bubble = SASS_MEMORY_NEW(ctx.mem, Bubble, mm->pstate(), mm);
+    return bubble;
+  }
+
+  Statement* Cssize::bubble(Media_Block* m)
+  {
+    Ruleset* parent = static_cast<Ruleset*>(shallow_copy(this->parent()));
+
+    Block* bb = SASS_MEMORY_NEW(ctx.mem, Block, parent->block()->pstate());
+    Ruleset* new_rule = SASS_MEMORY_NEW(ctx.mem, 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];
+    }
+
+    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,
+                                      m->pstate(),
+                                      m->media_queries(),
+                                      wrapper_block,
+                                      0);
+
+    mm->tabs(m->tabs());
+
+    Bubble* bubble = SASS_MEMORY_NEW(ctx.mem, Bubble, mm->pstate(), mm);
+
+    return bubble;
+  }
+
+  bool Cssize::bubblable(Statement* s)
+  {
+    return s->statement_type() == Statement::RULESET || s->bubbles();
+  }
+
+  Statement* Cssize::flatten(Statement* s)
+  {
+    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];
+        }
+      }
+      else {
+        *result << ss;
+      }
+    }
+    return result;
+  }
+
+  std::vector<std::pair<bool, Block*>> Cssize::slice_by_bubble(Statement* 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;
+
+      if (!results.empty() && results.back().first == key)
+      {
+        Block* wrapper_block = results.back().second;
+        *wrapper_block << value;
+      }
+      else
+      {
+        Block* wrapper_block = SASS_MEMORY_NEW(ctx.mem, Block, value->pstate());
+        *wrapper_block << 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)
+  {
+    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());
+
+    for (size_t i = 0, L = baz.size(); i < L; ++i) {
+      bool is_bubble = baz[i].first;
+      Block* slice = baz[i].second;
+
+      if (!is_bubble) {
+        if (!parent) {
+          *result << slice;
+        }
+        else if (previous_parent) {
+          *previous_parent->block() += slice;
+        }
+        else {
+          previous_parent = static_cast<Has_Block*>(shallow_copy(parent));
+          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;
+        }
+        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]);
+
+        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())
+        {
+          ss = b->node();
+        }
+        else
+        {
+          List* mq = merge_media_queries(static_cast<Media_Block*>(b->node()), static_cast<Media_Block*>(parent));
+          if (!mq->length()) continue;
+          static_cast<Media_Block*>(b->node())->media_queries(mq);
+          ss = b->node();
+        }
+
+        if (!ss) continue;
+
+        ss->tabs(ss->tabs() + b->tabs());
+        ss->group_end(b->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;
+
+        if (wrapper->block()->length()) {
+          previous_parent = 0;
+        }
+      }
+
+      if (wrapper_block) {
+        *result << flatten(wrapper_block);
+      }
+    }
+
+    return flatten(result);
+  }
+
+  Statement* Cssize::fallback_impl(AST_Node* n)
+  {
+    return static_cast<Statement*>(n);
+  }
+
+  void Cssize::append_block(Block* b)
+  {
+    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];
+        }
+      }
+      else if (ith) {
+        *current_block << ith;
+      }
+    }
+  }
+
+  List* Cssize::merge_media_queries(Media_Block* m1, Media_Block* m2)
+  {
+    List* qq = SASS_MEMORY_NEW(ctx.mem, 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;
+      }
+    }
+
+    return qq;
+  }
+
+
+  Media_Query* Cssize::merge_media_query(Media_Query* mq1, Media_Query* 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 m2 = std::string(mq2->is_restricted() ? "only" : mq1->is_negated() ? "not" : "");
+    std::string t2 = mq2->media_type() ? mq2->media_type()->perform(&to_string) : "";
+
+
+    if (t1.empty()) t1 = t2;
+    if (t2.empty()) t2 = t1;
+
+    if ((m1 == "not") ^ (m2 == "not")) {
+      if (t1 == t2) {
+        return 0;
+      }
+      type = m1 == "not" ? t2 : t1;
+      mod = m1 == "not" ? m2 : m1;
+    }
+    else if (m1 == "not" && m2 == "not") {
+      if (t1 != t2) {
+        return 0;
+      }
+      type = t1;
+      mod = "not";
+    }
+    else if (t1 != t2) {
+      return 0;
+    } else {
+      type = t1;
+      mod = m1.empty() ? m2 : m1;
+    }
+
+    Media_Query* mm = SASS_MEMORY_NEW(ctx.mem, 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 += mq2;
+    *mm += mq1;
+    return mm;
+  }
+}
diff --git a/libsass/src/cssize.hpp b/libsass/src/cssize.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/cssize.hpp
@@ -0,0 +1,78 @@
+#ifndef SASS_CSSIZE_H
+#define SASS_CSSIZE_H
+
+#include "ast.hpp"
+#include "context.hpp"
+#include "operation.hpp"
+#include "environment.hpp"
+
+namespace Sass {
+
+  typedef Environment<AST_Node*> Env;
+  struct Backtrace;
+
+  class Cssize : public Operation_CRTP<Statement*, Cssize> {
+
+    Context&                 ctx;
+    std::vector<Block*>      block_stack;
+    std::vector<Statement*>  p_stack;
+    Backtrace*               backtrace;
+
+    Statement* fallback_impl(AST_Node* n);
+
+  public:
+    Cssize(Context&, Backtrace*);
+    virtual ~Cssize() { }
+
+    using Operation<Statement*>::operator();
+
+    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*);
+
+    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*);
+
+    List* merge_media_queries(Media_Block*, Media_Block*);
+    Media_Query* merge_media_query(Media_Query*, Media_Query*);
+
+    template <typename U>
+    Statement* fallback(U x) { return fallback_impl(x); }
+
+    void append_block(Block*);
+  };
+
+}
+
+#endif
diff --git a/libsass/src/debug.hpp b/libsass/src/debug.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/debug.hpp
@@ -0,0 +1,43 @@
+#ifndef SASS_DEBUG_H
+#define SASS_DEBUG_H
+
+#include <stdint.h>
+
+#ifndef UINT32_MAX
+  #define UINT32_MAX 0xffffffffU
+#endif
+
+enum dbg_lvl_t : uint32_t {
+  NONE = 0,
+  TRIM = 1,
+  CHUNKS = 2,
+  SUBWEAVE = 4,
+  WEAVE = 8,
+  EXTEND_COMPOUND = 16,
+  EXTEND_COMPLEX = 32,
+  LCS = 64,
+  EXTEND_OBJECT = 128,
+  ALL = UINT32_MAX
+};
+
+#ifdef DEBUG
+
+#ifndef DEBUG_LVL
+const uint32_t debug_lvl = UINT32_MAX;
+#else
+const uint32_t debug_lvl = (DEBUG_LVL);
+#endif // DEBUG_LVL
+
+#define DEBUG_PRINT(lvl, x) if((lvl) & debug_lvl) { std::cerr << x; }
+#define DEBUG_PRINTLN(lvl, x) if((lvl) & debug_lvl) { std::cerr << x << std::endl; }
+#define DEBUG_EXEC(lvl, x) if((lvl) & debug_lvl) { x; }
+
+#else // DEBUG
+
+#define DEBUG_PRINT(lvl, x)
+#define DEBUG_PRINTLN(lvl, x)
+#define DEBUG_EXEC(lvl, x)
+
+#endif // DEBUG
+
+#endif // SASS_DEBUG
diff --git a/libsass/src/debugger.hpp b/libsass/src/debugger.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/debugger.hpp
@@ -0,0 +1,686 @@
+#ifndef SASS_DEBUGGER_H
+#define SASS_DEBUGGER_H
+
+#include <string>
+#include <sstream>
+#include "node.hpp"
+#include "ast_fwd_decl.hpp"
+
+using namespace Sass;
+
+inline void debug_ast(AST_Node* 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(set[pair], ind + "first: ");
+  }
+  if (ind == "") std::cerr << "#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
+}
+
+inline std::string str_replace(std::string str, const std::string& oldStr, const std::string& newStr)
+{
+  size_t pos = 0;
+  while((pos = str.find(oldStr, pos)) != std::string::npos)
+  {
+     str.replace(pos, oldStr.length(), newStr);
+     pos += newStr.length();
+  }
+  return str;
+}
+
+inline std::string prettyprint(const std::string& str) {
+  std::string clean = str_replace(str, "\n", "\\n");
+  clean = str_replace(clean, "	", "\\t");
+  clean = str_replace(clean, "\r", "\\r");
+  return clean;
+}
+
+inline std::string longToHex(long long t) {
+  std::stringstream is;
+  is << std::hex << t;
+  return is.str();
+}
+
+inline std::string pstate_source_position(AST_Node* node)
+{
+  std::stringstream str;
+  Position start(node->pstate());
+  Position end(start + node->pstate().offset);
+  str << (start.file == std::string::npos ? -1 : start.file)
+    << "@[" << start.line << ":" << start.column << "]"
+    << "-[" << end.line << ":" << end.column << "]";
+  return str.str();
+}
+
+inline void debug_ast(AST_Node* 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);
+    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);
+    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);
+    std::cerr << ind << "Selector_List " << selector;
+    std::cerr << " (" << pstate_source_position(node) << ")";
+    std::cerr << " [@media:" << selector->media_block() << "]";
+    std::cerr << (selector->is_optional() ? " [is_optional]": " -");
+    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); }
+
+//  } else if (dynamic_cast<Expression*>(node)) {
+//    Expression* expression = dynamic_cast<Expression*>(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);
+    std::cerr << ind << "Parent_Selector " << selector;
+//    if (selector->not_selector()) cerr << " [in_declaration]";
+    std::cerr << " (" << pstate_source_position(node) << ")";
+    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);
+    std::cerr << ind << "Complex_Selector " << selector
+      << " (" << pstate_source_position(node) << ")"
+      << " [weight:" << longToHex(selector->specificity()) << "]"
+      << " [@media:" << selector->media_block() << "]"
+      << (selector->is_optional() ? " [is_optional]": " -")
+      << (selector->has_line_feed() ? " [line-feed]": " -")
+      << (selector->has_line_break() ? " [line-break]": " -")
+      << " -- ";
+      std::string del;
+      switch (selector->combinator()) {
+        case Complex_Selector::PARENT_OF:   del = ">"; break;
+        case Complex_Selector::PRECEDES:    del = "~"; break;
+        case Complex_Selector::ADJACENT_TO: del = "+"; break;
+        case Complex_Selector::ANCESTOR_OF: del = " "; break;
+        case Complex_Selector::REFERENCE:   del = "//"; break;
+      }
+      // 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);
+    if (selector->tail()) {
+      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);
+    std::cerr << ind << "Compound_Selector " << selector;
+    std::cerr << " (" << pstate_source_position(node) << ")";
+    std::cerr << " [weight:" << longToHex(selector->specificity()) << "]";
+    std::cerr << " [@media:" << selector->media_block() << "]";
+    std::cerr << (selector->is_optional() ? " [is_optional]": " -");
+    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);
+    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 << 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 << 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 << " (" << 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 << " (" << 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)) {
+
+    Selector_Placeholder* selector = dynamic_cast<Selector_Placeholder*>(node);
+    std::cerr << ind << "Selector_Placeholder [" << selector->ns_name() << "] " << selector
+      << " [@media:" << selector->media_block() << "]"
+      << (selector->is_optional() ? " [is_optional]": " -")
+      << (selector->has_line_break() ? " [line-break]": " -")
+      << (selector->has_line_feed() ? " [line-feed]": " -")
+    << std::endl;
+
+  } else if (dynamic_cast<Simple_Selector*>(node)) {
+    Simple_Selector* selector = dynamic_cast<Simple_Selector*>(node);
+    std::cerr << ind << "Simple_Selector " << selector;
+    std::cerr << " (" << pstate_source_position(node) << ")";
+    std::cerr << (selector->has_line_break() ? " [line-break]": " -") << (selector->has_line_feed() ? " [line-feed]": " -") << std::endl;
+
+  } else if (dynamic_cast<Selector_Schema*>(node)) {
+    Selector_Schema* selector = dynamic_cast<Selector_Schema*>(node);
+    std::cerr << ind << "Selector_Schema " << selector;
+    std::cerr << " (" << pstate_source_position(node) << ")"
+      << (selector->at_root() && selector->at_root() ? " [@ROOT]" : "")
+      << " [@media:" << selector->media_block() << "]"
+      << (selector->has_line_break() ? " [line-break]": " -")
+      << (selector->has_line_feed() ? " [line-feed]": " -")
+    << std::endl;
+
+    debug_ast(selector->contents(), ind + " ");
+    // for(auto i : selector->elements()) { debug_ast(i, ind + " ", env); }
+
+  } else if (dynamic_cast<Selector*>(node)) {
+    Selector* selector = dynamic_cast<Selector*>(node);
+    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);
+    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) ");
+
+  } else if (dynamic_cast<Media_Query*>(node)) {
+    Media_Query* block = dynamic_cast<Media_Query*>(node);
+    std::cerr << ind << "Media_Query " << block;
+    std::cerr << " (" << pstate_source_position(node) << ")";
+    std::cerr << (block->is_negated() ? " [is_negated]": " -")
+      << (block->is_restricted() ? " [is_restricted]": " -")
+    << std::endl;
+    debug_ast(block->media_type(), ind + " ");
+    for(auto i : block->elements()) { debug_ast(i, ind + " ", env); }
+
+  } else if (dynamic_cast<Media_Block*>(node)) {
+    Media_Block* block = dynamic_cast<Media_Block*>(node);
+    std::cerr << ind << "Media_Block " << block;
+    std::cerr << " (" << pstate_source_position(node) << ")";
+    std::cerr << " " << block->tabs() << std::endl;
+    debug_ast(block->media_queries(), ind + " =@ ");
+    if (block->block()) for(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);
+    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);
+    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);
+    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);
+    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);
+    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);
+    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);
+    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);
+    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);
+    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);
+    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);
+    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);
+    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);
+    std::cerr << ind << "Content " << block;
+    std::cerr << " (" << pstate_source_position(node) << ")";
+    std::cerr << " " << block->tabs() << std::endl;
+  } else if (dynamic_cast<Import_Stub*>(node)) {
+    Import_Stub* block = dynamic_cast<Import_Stub*>(node);
+    std::cerr << ind << "Import_Stub " << block;
+    std::cerr << " (" << pstate_source_position(node) << ")";
+    std::cerr << " " << block->tabs() << std::endl;
+  } else if (dynamic_cast<Import*>(node)) {
+    Import* block = dynamic_cast<Import*>(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);
+    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);
+    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);
+    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;
+    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);
+    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);
+    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);
+    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);
+    std::cerr << ind << "Definition " << block;
+    std::cerr << " (" << pstate_source_position(node) << ")";
+    std::cerr << " [name: " << block->name() << "] ";
+    std::cerr << " [type: " << (block->type() == Sass::Definition::Type::MIXIN ? "Mixin " : "Function ") << "] ";
+    // this seems to lead to segfaults some times?
+    // 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);
+    std::cerr << ind << "Mixin_Call " << block << " " << block->tabs();
+    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)) {
+    std::cerr << ind << "Ruleset " << ruleset;
+    std::cerr << " (" << pstate_source_position(node) << ")";
+    std::cerr << " [indent: " << ruleset->tabs() << "]";
+    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);
+    std::cerr << ind << "Block " << block;
+    std::cerr << " (" << pstate_source_position(node) << ")";
+    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 ";
+    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() << "]";
+    if (expression->is_delayed()) std::cerr << " [delayed]";
+    std::cerr << std::endl;
+  } else if (dynamic_cast<Variable*>(node)) {
+    Variable* expression = dynamic_cast<Variable*>(node);
+    std::cerr << ind << "Variable " << expression;
+    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);
+    std::cerr << ind << "Function_Call_Schema " << expression;
+    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);
+    std::cerr << ind << "Function_Call " << expression;
+    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 << ind << "Arguments " << expression;
+    if (expression->is_delayed()) std::cerr << " [delayed]";
+    std::cerr << " (" << pstate_source_position(node) << ")";
+    if (expression->has_named_arguments()) std::cerr << " [has_named_arguments]";
+    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);
+    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);
+    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);
+    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);
+    std::cerr << ind << "Unary_Expression " << expression;
+    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);
+    std::cerr << ind << "Binary_Expression " << expression;
+    std::cerr << " [delayed: " << expression->is_delayed() << "] ";
+    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);
+    std::cerr << ind << "Map " << expression;
+    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: ");
+    }
+  } else if (dynamic_cast<List*>(node)) {
+    List* expression = dynamic_cast<List*>(node);
+    std::cerr << ind << "List " << expression;
+    std::cerr << " (" << pstate_source_position(node) << ")";
+    std::cerr << " (" << expression->length() << ") " <<
+      (expression->separator() == SASS_COMMA ? "Comma " : "Space ") <<
+      " [delayed: " << expression->is_delayed() << "] " <<
+      " [interpolant: " << expression->is_interpolant() << "] " <<
+      " [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);
+    std::cerr << ind << "Content " << expression;
+    std::cerr << " (" << pstate_source_position(node) << ")";
+    std::cerr << " [Statement]" << std::endl;
+  } else if (dynamic_cast<Boolean*>(node)) {
+    Boolean* expression = dynamic_cast<Boolean*>(node);
+    std::cerr << ind << "Boolean " << expression;
+    std::cerr << " (" << pstate_source_position(node) << ")";
+    std::cerr << " [" << expression->value() << "]" << std::endl;
+  } else if (dynamic_cast<Color*>(node)) {
+    Color* expression = dynamic_cast<Color*>(node);
+    std::cerr << ind << "Color " << expression;
+    std::cerr << " (" << pstate_source_position(node) << ")";
+    std::cerr << " [" << expression->r() << ":"  << expression->g() << ":" << expression->b() << "@" << expression->a() << "]" << std::endl;
+  } else if (dynamic_cast<Number*>(node)) {
+    Number* expression = dynamic_cast<Number*>(node);
+    std::cerr << ind << "Number " << expression;
+    std::cerr << " (" << pstate_source_position(node) << ")";
+    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);
+    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);
+    std::cerr << ind << "String_Constant " << expression;
+    if (expression->concrete_type()) {
+      std::cerr << " " << expression->concrete_type();
+    }
+    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);
+    std::cerr << ind << "String_Schema " << expression;
+    std::cerr << " " << expression->concrete_type();
+    if (expression->is_delayed()) std::cerr << " [delayed]";
+    if (expression->has_interpolants()) std::cerr << " [has_interpolants]";
+    if (expression->is_interpolant()) std::cerr << " [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);
+    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);
+    std::cerr << ind << "Expression " << expression;
+    std::cerr << " (" << pstate_source_position(node) << ")";
+    switch (expression->concrete_type()) {
+      case Expression::Concrete_Type::NONE: std::cerr << " [NONE]"; break;
+      case Expression::Concrete_Type::BOOLEAN: std::cerr << " [BOOLEAN]"; break;
+      case Expression::Concrete_Type::NUMBER: std::cerr << " [NUMBER]"; break;
+      case Expression::Concrete_Type::COLOR: std::cerr << " [COLOR]"; break;
+      case Expression::Concrete_Type::STRING: std::cerr << " [STRING]"; break;
+      case Expression::Concrete_Type::LIST: std::cerr << " [LIST]"; break;
+      case Expression::Concrete_Type::MAP: std::cerr << " [MAP]"; break;
+      case Expression::Concrete_Type::SELECTOR: std::cerr << " [SELECTOR]"; break;
+      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::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);
+    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);
+    std::cerr << ind << "Statement " << statement;
+    std::cerr << " (" << pstate_source_position(node) << ")";
+    std::cerr << " " << statement->tabs() << std::endl;
+  }
+
+  if (ind == "") std::cerr << "####################################################################\n";
+}
+
+inline void debug_node(Node* node, std::string ind = "")
+{
+  if (ind == "") std::cerr << "#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n";
+  if (node->isCombinator()) {
+    std::cerr << ind;
+    std::cerr << "Combinator ";
+    std::cerr << node << " ";
+    if (node->got_line_feed) std::cerr << "[LF] ";
+    switch (node->combinator()) {
+      case Complex_Selector::ADJACENT_TO: std::cerr << "{+} "; break;
+      case Complex_Selector::PARENT_OF:   std::cerr << "{>} "; break;
+      case Complex_Selector::PRECEDES:    std::cerr << "{~} "; break;
+      case Complex_Selector::REFERENCE:   std::cerr << "{@} "; break;
+      case Complex_Selector::ANCESTOR_OF: std::cerr << "{ } "; break;
+    }
+    std::cerr << std::endl;
+    // debug_ast(node->combinator(), ind + "  ");
+  } else if (node->isSelector()) {
+    std::cerr << ind;
+    std::cerr << "Selector ";
+    std::cerr << node << " ";
+    if (node->got_line_feed) std::cerr << "[LF] ";
+    std::cerr << std::endl;
+    debug_ast(node->selector(), ind + "  ");
+  } else if (node->isCollection()) {
+    std::cerr << ind;
+    std::cerr << "Collection ";
+    std::cerr << node << " ";
+    if (node->got_line_feed) std::cerr << "[LF] ";
+    std::cerr << std::endl;
+    for(auto n : (*node->collection())) {
+      debug_node(&n, ind + "  ");
+    }
+  } else if (node->isNil()) {
+    std::cerr << ind;
+    std::cerr << "Nil ";
+    std::cerr << node << " ";
+    if (node->got_line_feed) std::cerr << "[LF] ";
+    std::cerr << std::endl;
+  } else {
+    std::cerr << ind;
+    std::cerr << "OTHER ";
+    std::cerr << node << " ";
+    if (node->got_line_feed) std::cerr << "[LF] ";
+    std::cerr << std::endl;
+  }
+  if (ind == "") std::cerr << "#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n";
+}
+
+inline void debug_ast(const AST_Node* node, std::string ind = "", Env* env = 0)
+{
+  debug_ast(const_cast<AST_Node*>(node), ind, env);
+}
+
+inline void debug_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 = "")
+{
+  if (ind == "") std::cerr << "#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
+  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::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: ");
+  }
+  if (ind == "") std::cerr << "#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
+}
+
+#endif // SASS_DEBUGGER
diff --git a/libsass/src/emitter.cpp b/libsass/src/emitter.cpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/emitter.cpp
@@ -0,0 +1,261 @@
+#include "util.hpp"
+#include "context.hpp"
+#include "output.hpp"
+#include "emitter.hpp"
+#include "utf8_string.hpp"
+
+namespace Sass {
+
+  Emitter::Emitter(Context* ctx)
+  : wbuf(),
+    ctx(ctx),
+    indentation(0),
+    scheduled_space(0),
+    scheduled_linefeed(0),
+    scheduled_delimiter(false),
+    in_comment(false),
+    in_wrapped(false),
+    in_media_block(false),
+    in_declaration(false),
+    in_space_array(false),
+    in_comma_array(false),
+    in_debug(false)
+  { }
+
+  // return buffer as string
+  std::string Emitter::get_buffer(void)
+  {
+    return wbuf.buffer;
+  }
+
+  Sass_Output_Style Emitter::output_style(void)
+  {
+    return ctx ? ctx->output_style() : SASS_STYLE_COMPRESSED;
+  }
+
+  // PROXY METHODS FOR SOURCE MAPS
+
+  void Emitter::add_source_index(size_t idx)
+  { wbuf.smap.source_index.push_back(idx); }
+
+  std::string Emitter::render_srcmap(Context &ctx)
+  { return wbuf.smap.render_srcmap(ctx); }
+
+  void Emitter::set_filename(const std::string& str)
+  { wbuf.smap.file = str; }
+
+  void Emitter::add_open_mapping(AST_Node* node)
+  { wbuf.smap.add_open_mapping(node); }
+  void Emitter::add_close_mapping(AST_Node* node)
+  { wbuf.smap.add_close_mapping(node); }
+  ParserState Emitter::remap(const ParserState& pstate)
+  { return wbuf.smap.remap(pstate); }
+
+  // MAIN BUFFER MANIPULATION
+
+  // add outstanding delimiter
+  void Emitter::finalize(void)
+  {
+    scheduled_space = 0;
+    if (scheduled_linefeed)
+      scheduled_linefeed = 1;
+    flush_schedules();
+  }
+
+  // flush scheduled space/linefeed
+  void Emitter::flush_schedules(void)
+  {
+    // check the schedule
+    if (scheduled_linefeed) {
+      std::string linefeeds = "";
+
+      for (size_t i = 0; i < scheduled_linefeed; i++)
+        linefeeds += ctx ? ctx->linefeed : "\n";
+      scheduled_space = 0;
+      scheduled_linefeed = 0;
+      append_string(linefeeds);
+
+    } else if (scheduled_space) {
+      std::string spaces(scheduled_space, ' ');
+      scheduled_space = 0;
+      append_string(spaces);
+    }
+    if (scheduled_delimiter) {
+      scheduled_delimiter = false;
+      append_string(";");
+    }
+  }
+
+  // prepend some text or token to the buffer
+  void Emitter::prepend_output(const OutputBuffer& output)
+  {
+    wbuf.smap.prepend(output);
+    wbuf.buffer = output.buffer + wbuf.buffer;
+  }
+
+  // prepend some text or token to the buffer
+  void Emitter::prepend_string(const std::string& text)
+  {
+    wbuf.smap.prepend(Offset(text));
+    wbuf.buffer = text + wbuf.buffer;
+  }
+
+  // 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) {
+      // unescape comment nodes
+      std::string out = comment_to_string(text);
+      // add to buffer
+      wbuf.buffer += out;
+      // account for data in source-maps
+      wbuf.smap.append(Offset(out));
+    } else {
+      // add to buffer
+      wbuf.buffer += text;
+      // account for data in source-maps
+      wbuf.smap.append(Offset(text));
+    }
+  }
+
+  // append some white-space only text
+  void Emitter::append_wspace(const std::string& text)
+  {
+    if (text.empty()) return;
+    if (peek_linefeed(text.c_str())) {
+      scheduled_space = 0;
+      append_mandatory_linefeed();
+    }
+  }
+
+  // append some text or token to the buffer
+  // this adds source-mappings for node start and end
+  void Emitter::append_token(const std::string& text, AST_Node* node)
+  {
+    flush_schedules();
+    add_open_mapping(node);
+    append_string(text);
+    add_close_mapping(node);
+  }
+
+  // HELPER METHODS
+
+  void Emitter::append_indentation()
+  {
+    if (output_style() == SASS_STYLE_COMPRESSED) return;
+    if (output_style() == SASS_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 : "  ";
+    append_string(indent);
+  }
+
+  void Emitter::append_delimiter()
+  {
+    scheduled_delimiter = true;
+    if (output_style() == SASS_STYLE_COMPACT) {
+      if (indentation == 0) {
+        append_mandatory_linefeed();
+      } else {
+        append_mandatory_space();
+      }
+    } else if (output_style() != SASS_STYLE_COMPRESSED) {
+      append_optional_linefeed();
+    }
+  }
+
+  void Emitter::append_comma_separator()
+  {
+    // scheduled_space = 0;
+    append_string(",");
+    append_optional_space();
+  }
+
+  void Emitter::append_colon_separator()
+  {
+    scheduled_space = 0;
+    append_string(":");
+    append_optional_space();
+  }
+
+  void Emitter::append_mandatory_space()
+  {
+    scheduled_space = 1;
+  }
+
+  void Emitter::append_optional_space()
+  {
+    if ((output_style() != SASS_STYLE_COMPRESSED || in_debug) && buffer().size()) {
+      char lst = buffer().at(buffer().length() - 1);
+      if (!isspace(lst) || scheduled_delimiter) {
+        append_mandatory_space();
+      }
+    }
+  }
+
+  void Emitter::append_special_linefeed()
+  {
+    if (output_style() == SASS_STYLE_COMPACT) {
+      append_mandatory_linefeed();
+      for (size_t p = 0; p < indentation; p++)
+        append_string(ctx ? ctx->indent : "  ");
+    }
+  }
+
+  void Emitter::append_optional_linefeed()
+  {
+    if (in_declaration && in_comma_array) return;
+    if (output_style() == SASS_STYLE_COMPACT) {
+      append_mandatory_space();
+    } else {
+      append_mandatory_linefeed();
+    }
+  }
+
+  void Emitter::append_mandatory_linefeed()
+  {
+    if (output_style() != SASS_STYLE_COMPRESSED) {
+      scheduled_linefeed = 1;
+      scheduled_space = 0;
+      // flush_schedules();
+    }
+  }
+
+  void Emitter::append_scope_opener(AST_Node* node)
+  {
+    scheduled_linefeed = 0;
+    append_optional_space();
+    flush_schedules();
+    if (node) add_open_mapping(node);
+    append_string("{");
+    append_optional_linefeed();
+    // append_optional_space();
+    ++ indentation;
+  }
+  void Emitter::append_scope_closer(AST_Node* node)
+  {
+    -- indentation;
+    scheduled_linefeed = 0;
+    if (output_style() == SASS_STYLE_COMPRESSED)
+      scheduled_delimiter = false;
+    if (output_style() == SASS_STYLE_EXPANDED) {
+      append_optional_linefeed();
+      append_indentation();
+    } else {
+      append_optional_space();
+    }
+    append_string("}");
+    if (node) add_close_mapping(node);
+    append_optional_linefeed();
+    if (indentation != 0) return;
+    if (output_style() != SASS_STYLE_COMPRESSED)
+      scheduled_linefeed = 2;
+  }
+
+}
diff --git a/libsass/src/emitter.hpp b/libsass/src/emitter.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/emitter.hpp
@@ -0,0 +1,91 @@
+#ifndef SASS_EMITTER_H
+#define SASS_EMITTER_H
+
+#include <string>
+#include "sass/base.h"
+#include "source_map.hpp"
+#include "ast_fwd_decl.hpp"
+
+namespace Sass {
+  class Context;
+
+  class Emitter {
+
+    public:
+      Emitter(Context* ctx);
+      virtual ~Emitter() { }
+
+    protected:
+      OutputBuffer wbuf;
+    public:
+      const std::string& buffer(void) { return wbuf.buffer; }
+      const SourceMap smap(void) { return wbuf.smap; }
+      const OutputBuffer output(void) { return wbuf; }
+      // 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);
+      std::string render_srcmap(Context &ctx);
+      ParserState remap(const ParserState& pstate);
+
+    public:
+      Context* ctx;
+      size_t indentation;
+      size_t scheduled_space;
+      size_t scheduled_linefeed;
+      bool scheduled_delimiter;
+
+    public:
+      // output strings different in comments
+      bool in_comment;
+      // selector list does not get linefeeds
+      bool in_wrapped;
+      // lists always get a space after delimiter
+      bool in_media_block;
+      // nested list must not have parentheses
+      bool in_declaration;
+      // 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);
+      // add outstanding linefeed
+      void finalize(void);
+      // flush scheduled space/linefeed
+      void flush_schedules(void);
+      // prepend some text or token to the buffer
+      void prepend_string(const std::string& text);
+      void prepend_output(const OutputBuffer& out);
+      // append some text or token to the buffer
+      void append_string(const std::string& text);
+      // append some white-space only text
+      void append_wspace(const std::string& text);
+      // append some text or token to the buffer
+      // this adds source-mappings for node start and end
+      void append_token(const std::string& text, AST_Node* node);
+
+    public: // syntax sugar
+      void append_indentation();
+      void append_optional_space(void);
+      void append_mandatory_space(void);
+      void append_special_linefeed(void);
+      void append_optional_linefeed(void);
+      void append_mandatory_linefeed(void);
+      void append_scope_opener(AST_Node* node = 0);
+      void append_scope_closer(AST_Node* node = 0);
+      void append_comma_separator(void);
+      void append_colon_separator(void);
+      void append_delimiter(void);
+
+  };
+
+}
+
+#endif
diff --git a/libsass/src/environment.cpp b/libsass/src/environment.cpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/environment.cpp
@@ -0,0 +1,184 @@
+#include "ast.hpp"
+#include "environment.hpp"
+
+namespace Sass {
+
+  template <typename T>
+  Environment<T>::Environment() : local_frame_(std::map<std::string, T>()), parent_(0) { }
+  template <typename T>
+  Environment<T>::Environment(Environment<T>* env) : local_frame_(std::map<std::string, T>()), parent_(env) { }
+  template <typename T>
+  Environment<T>::Environment(Environment<T>& env) : local_frame_(std::map<std::string, T>()), parent_(&env) { }
+
+  // link parent to create a stack
+  template <typename T>
+  void Environment<T>::link(Environment& env) { parent_ = &env; }
+  template <typename T>
+  void Environment<T>::link(Environment* env) { parent_ = env; }
+
+  // this is used to find the global frame
+  // which is the second last on the stack
+  template <typename T>
+  bool Environment<T>::is_lexical() const
+  {
+    return !! parent_ && parent_->parent_;
+  }
+
+  // only match the real root scope
+  // there is still a parent around
+  // not sure what it is actually use for
+  // I guess we store functions etc. there
+  template <typename T>
+  bool Environment<T>::is_global() const
+  {
+    return parent_ && ! parent_->parent_;
+  }
+
+  template <typename T>
+  std::map<std::string, T>& Environment<T>::local_frame() {
+    return local_frame_;
+  }
+
+  template <typename T>
+  bool Environment<T>::has_local(const std::string& key) const
+  { return local_frame_.find(key) != local_frame_.end(); }
+
+  template <typename T>
+  T& Environment<T>::get_local(const std::string& key)
+  { return local_frame_[key]; }
+
+  template <typename T>
+  void Environment<T>::set_local(const std::string& key, T val)
+  {
+    local_frame_[key] = val;
+  }
+
+  template <typename T>
+  void Environment<T>::del_local(const std::string& key)
+  { local_frame_.erase(key); }
+
+  template <typename T>
+  Environment<T>* Environment<T>::global_env()
+  {
+    Environment* cur = this;
+    while (cur->is_lexical()) {
+      cur = cur->parent_;
+    }
+    return cur;
+  }
+
+  template <typename T>
+  bool Environment<T>::has_global(const std::string& key)
+  { return global_env()->has(key); }
+
+  template <typename T>
+  T& Environment<T>::get_global(const std::string& key)
+  { return (*global_env())[key]; }
+
+  template <typename T>
+  void Environment<T>::set_global(const std::string& key, T val)
+  {
+    global_env()->local_frame_[key] = val;
+  }
+
+  template <typename T>
+  void Environment<T>::del_global(const std::string& key)
+  { global_env()->local_frame_.erase(key); }
+
+  template <typename T>
+  Environment<T>* Environment<T>::lexical_env(const std::string& key)
+  {
+    Environment* cur = this;
+    while (cur) {
+      if (cur->has_local(key)) {
+        return cur;
+      }
+      cur = cur->parent_;
+    }
+    return this;
+  }
+
+  // see if we have a lexical variable
+  // move down the stack but stop before we
+  // reach the global frame (is not included)
+  template <typename T>
+  bool Environment<T>::has_lexical(const std::string& key) const
+  {
+    auto cur = this;
+    while (cur->is_lexical()) {
+      if (cur->has_local(key)) return true;
+      cur = cur->parent_;
+    }
+    return false;
+  }
+
+  // see if we have a lexical we could update
+  // either update already existing lexical value
+  // or if flag is set, we create one if no lexical found
+  template <typename T>
+  void Environment<T>::set_lexical(const std::string& key, T val)
+  {
+    auto cur = this;
+    while (cur->is_lexical()) {
+      if (cur->has_local(key)) {
+        cur->set_local(key, val);
+        return;
+      }
+      cur = cur->parent_;
+    }
+    set_local(key, val);
+  }
+
+  // look on the full stack for key
+  // include all scopes available
+  template <typename T>
+  bool Environment<T>::has(const std::string& key) const
+  {
+    auto cur = this;
+    while (cur) {
+      if (cur->has_local(key)) {
+        return true;
+      }
+      cur = cur->parent_;
+    }
+    return false;
+  }
+
+  // use array access for getter and setter functions
+  template <typename T>
+  T& Environment<T>::operator[](const std::string& key)
+  {
+    auto cur = this;
+    while (cur) {
+      if (cur->has_local(key)) {
+        return cur->get_local(key);
+      }
+      cur = cur->parent_;
+    }
+    return get_local(key);
+  }
+
+  #ifdef DEBUG
+  template <typename T>
+  size_t Environment<T>::print(std::string prefix)
+  {
+    size_t indent = 0;
+    if (parent_) indent = parent_->print(prefix) + 1;
+    std::cerr << prefix << std::string(indent, ' ') << "== " << this << std::endl;
+    for (typename std::map<std::string, T>::iterator i = local_frame_.begin(); i != local_frame_.end(); ++i) {
+      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); }
+        std::cerr << std::endl;
+      }
+    }
+    return indent ;
+  }
+  #endif
+
+  // compile implementation for AST_Node
+  template class Environment<AST_Node*>;
+
+}
+
diff --git a/libsass/src/environment.hpp b/libsass/src/environment.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/environment.hpp
@@ -0,0 +1,92 @@
+#ifndef SASS_ENVIRONMENT_H
+#define SASS_ENVIRONMENT_H
+
+#include <string>
+#include <map>
+
+#include "ast_fwd_decl.hpp"
+#include "ast_def_macros.hpp"
+#include "memory_manager.hpp"
+
+namespace Sass {
+
+  template <typename T>
+  class Environment {
+    // TODO: test with map
+    std::map<std::string, T> local_frame_;
+    ADD_PROPERTY(Environment*, parent)
+
+  public:
+    Memory_Manager mem;
+    Environment();
+    Environment(Environment* env);
+    Environment(Environment& env);
+
+    // link parent to create a stack
+    void link(Environment& env);
+    void link(Environment* env);
+
+    // this is used to find the global frame
+    // which is the second last on the stack
+    bool is_lexical() const;
+
+    // only match the real root scope
+    // there is still a parent around
+    // not sure what it is actually use for
+    // I guess we store functions etc. there
+    bool is_global() const;
+
+    // scope operates on the current frame
+
+    std::map<std::string, T>& local_frame();
+
+    bool has_local(const std::string& key) const;
+
+    T& get_local(const std::string& key);
+
+    // set variable on the current frame
+    void set_local(const std::string& key, T val);
+
+    void del_local(const std::string& key);
+
+    // global operates on the global frame
+    // which is the second last on the stack
+    Environment* global_env();
+    // get the env where the variable already exists
+    // if it does not yet exist, we return current env
+    Environment* lexical_env(const std::string& key);
+
+    bool has_global(const std::string& key);
+
+    T& get_global(const std::string& key);
+
+    // set a variable on the global frame
+    void set_global(const std::string& key, T val);
+
+    void del_global(const std::string& key);
+
+    // see if we have a lexical variable
+    // move down the stack but stop before we
+    // reach the global frame (is not included)
+    bool has_lexical(const std::string& key) const;
+
+    // see if we have a lexical we could update
+    // either update already existing lexical value
+    // or we create a new one on the current frame
+    void set_lexical(const std::string& key, T val);
+
+    // look on the full stack for key
+    // include all scopes available
+    bool has(const std::string& key) const;
+
+    // use array access for getter and setter functions
+    T& operator[](const std::string& key);
+
+    #ifdef DEBUG
+    size_t print(std::string prefix = "");
+    #endif
+
+  };
+}
+
+#endif
diff --git a/libsass/src/error_handling.cpp b/libsass/src/error_handling.cpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/error_handling.cpp
@@ -0,0 +1,117 @@
+#include "ast.hpp"
+#include "prelexer.hpp"
+#include "backtrace.hpp"
+#include "to_string.hpp"
+#include "error_handling.hpp"
+
+#include <iostream>
+
+namespace Sass {
+
+  namespace Exception {
+
+    Base::Base(ParserState pstate, std::string msg)
+    : std::runtime_error(msg),
+      msg(msg), pstate(pstate)
+    { }
+
+    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)
+    : Base(selector->pstate()), parent(parent), selector(selector)
+    {
+      msg = "Invalid parent selector for \"";
+      msg += selector->to_string(false);
+      msg += "\": \"";
+      msg += parent->to_string(false);;
+      msg += "\"";
+    }
+
+    InvalidArgumentType::InvalidArgumentType(ParserState pstate, std::string fn, std::string arg, std::string type, const Value* value)
+    : Base(pstate), fn(fn), arg(arg), type(type), value(value)
+    {
+      msg  = arg + ": \"";
+      msg += value->to_string(true, 5);
+      msg += "\" is not a " + type;
+      msg += " for `" + fn + "'";
+    }
+
+    InvalidSyntax::InvalidSyntax(ParserState pstate, std::string msg)
+    : Base(pstate, msg)
+    { }
+
+  }
+
+
+  void warn(std::string msg, ParserState pstate)
+  {
+    std::cerr << "Warning: " << msg<< std::endl;
+  }
+
+  void warn(std::string msg, ParserState pstate, Backtrace* bt)
+  {
+    Backtrace top(bt, pstate, "");
+    msg += top.to_string();
+    warn(msg, pstate);
+  }
+
+  void deprecated_function(std::string msg, ParserState pstate)
+  {
+    std::string cwd(Sass::File::get_cwd());
+    std::string abs_path(Sass::File::rel2abs(pstate.path, cwd, cwd));
+    std::string rel_path(Sass::File::abs2rel(pstate.path, cwd, cwd));
+    std::string output_path(Sass::File::path_for_console(rel_path, abs_path, pstate.path));
+
+    std::cerr << "DEPRECATION WARNING: " << msg << std::endl;
+    std::cerr << "will be an error in future versions of Sass." << std::endl;
+    std::cerr << "        on line " << pstate.line+1 << " of " << output_path << std::endl;
+  }
+
+  void deprecated(std::string msg, std::string msg2, ParserState pstate)
+  {
+    std::string cwd(Sass::File::get_cwd());
+    std::string abs_path(Sass::File::rel2abs(pstate.path, cwd, cwd));
+    std::string rel_path(Sass::File::abs2rel(pstate.path, cwd, cwd));
+    std::string output_path(Sass::File::path_for_console(rel_path, pstate.path, pstate.path));
+
+    std::cerr << "DEPRECATION WARNING on line " << pstate.line + 1;
+    if (output_path.length()) std::cerr << " of " << output_path;
+    std::cerr << ":" << std::endl;
+    std::cerr << msg << " and will be an error in future versions of Sass." << std::endl;
+    if (msg2.length()) std::cerr << msg2 << std::endl;
+    std::cerr << std::endl;
+  }
+
+  void deprecated_bind(std::string msg, ParserState pstate)
+  {
+    std::string cwd(Sass::File::get_cwd());
+    std::string abs_path(Sass::File::rel2abs(pstate.path, cwd, cwd));
+    std::string rel_path(Sass::File::abs2rel(pstate.path, cwd, cwd));
+    std::string output_path(Sass::File::path_for_console(rel_path, abs_path, pstate.path));
+
+    std::cerr << "WARNING: " << msg << std::endl;
+    std::cerr << "        on line " << pstate.line+1 << " of " << output_path << std::endl;
+    std::cerr << "This will be an error in future versions of Sass." << std::endl;
+  }
+
+  void error(std::string msg, ParserState pstate)
+  {
+    throw Exception::InvalidSyntax(pstate, msg);
+  }
+
+  void error(std::string msg, ParserState pstate, Backtrace* bt)
+  {
+    Backtrace top(bt, pstate, "");
+    msg += "\n" + top.to_string();
+    error(msg, pstate);
+  }
+
+}
diff --git a/libsass/src/error_handling.hpp b/libsass/src/error_handling.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/error_handling.hpp
@@ -0,0 +1,75 @@
+#ifndef SASS_ERROR_HANDLING_H
+#define SASS_ERROR_HANDLING_H
+
+#include <string>
+#include <sstream>
+#include <stdexcept>
+#include "position.hpp"
+
+namespace Sass {
+
+  struct Backtrace;
+
+  namespace Exception {
+
+    const std::string def_msg = "Invalid sass";
+
+    class Base : public std::runtime_error {
+      protected:
+        std::string msg;
+      public:
+        ParserState pstate;
+      public:
+        Base(ParserState pstate, std::string msg = def_msg);
+        virtual const char* what() const throw();
+        virtual ~Base() throw() {};
+    };
+
+    class InvalidSass : public Base {
+      public:
+        InvalidSass(ParserState pstate, std::string msg);
+        virtual ~InvalidSass() throw() {};
+    };
+
+    class InvalidParent : public Base {
+      protected:
+        Selector* parent;
+        Selector* selector;
+      public:
+        InvalidParent(Selector* parent, Selector* selector);
+        virtual ~InvalidParent() throw() {};
+    };
+
+    class InvalidArgumentType : public Base {
+      protected:
+        std::string fn;
+        std::string arg;
+        std::string type;
+        const Value* value;
+      public:
+        InvalidArgumentType(ParserState pstate, std::string fn, std::string arg, std::string type, const Value* value = 0);
+        virtual ~InvalidArgumentType() throw() {};
+    };
+
+    class InvalidSyntax : public Base {
+      public:
+        InvalidSyntax(ParserState pstate, std::string msg);
+        virtual ~InvalidSyntax() throw() {};
+    };
+
+  }
+
+  void warn(std::string msg, ParserState pstate);
+  void warn(std::string msg, ParserState pstate, Backtrace* bt);
+
+  void deprecated_function(std::string msg, ParserState pstate);
+  void deprecated(std::string msg, std::string msg2, ParserState pstate);
+  void deprecated_bind(std::string msg, ParserState pstate);
+  // void deprecated(std::string msg, ParserState pstate, Backtrace* bt);
+
+  void error(std::string msg, ParserState pstate);
+  void error(std::string msg, ParserState pstate, Backtrace* bt);
+
+}
+
+#endif
diff --git a/libsass/src/eval.cpp b/libsass/src/eval.cpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/eval.cpp
@@ -0,0 +1,1531 @@
+#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());
+    }
+  }
+
+}
diff --git a/libsass/src/eval.hpp b/libsass/src/eval.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/eval.hpp
@@ -0,0 +1,107 @@
+#ifndef SASS_EVAL_H
+#define SASS_EVAL_H
+
+#include "context.hpp"
+#include "listize.hpp"
+#include "operation.hpp"
+
+namespace Sass {
+
+  class Expand;
+  class Context;
+  class Listize;
+
+  class Eval : public Operation_CRTP<Expression*, Eval> {
+
+   private:
+    Expression* fallback_impl(AST_Node* n);
+
+   public:
+    Expand&  exp;
+    Context& ctx;
+    Listize  listize;
+    Eval(Expand& exp);
+    virtual ~Eval();
+
+    Env* environment();
+    Context& context();
+    Selector_List* selector();
+    Backtrace* backtrace();
+
+    using Operation<Expression*>::operator();
+
+    // 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* 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*);
+
+    // these will return selectors
+    Selector_List* operator()(Selector_List*);
+    Selector_List* operator()(Complex_Selector*);
+    Attribute_Selector* operator()(Attribute_Selector*);
+    // 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; };
+    // actual evaluated selectors
+    Selector_List* operator()(Selector_Schema*);
+    Expression* operator()(Parent_Selector*);
+
+    template <typename U>
+    Expression* 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*);
+    // -- 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);
+
+  private:
+    std::string interpolation(Expression* s, bool into_quotes = false);
+
+  };
+
+  Expression* cval_to_astnode(Memory_Manager& mem, union Sass_Value* v, Context& ctx, Backtrace* backtrace, ParserState pstate = ParserState("[AST]"));
+
+}
+
+#endif
diff --git a/libsass/src/expand.cpp b/libsass/src/expand.cpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/expand.cpp
@@ -0,0 +1,689 @@
+#ifdef _MSC_VER
+#pragma warning(disable : 4503)
+#endif
+
+#include <iostream>
+#include <typeinfo>
+
+#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)
+  : ctx(ctx),
+    eval(Eval(*this)),
+    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)
+  {
+    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);
+    backtrace_stack.push_back(0);
+    backtrace_stack.push_back(bt);
+  }
+
+  Context& Expand::context()
+  {
+    return ctx;
+  }
+
+  Env* Expand::environment()
+  {
+    if (env_stack.size() > 0)
+      return env_stack.back();
+    return 0;
+  }
+
+  Selector_List* Expand::selector()
+  {
+    if (selector_stack.size() > 0)
+      return selector_stack.back();
+    return 0;
+  }
+
+  Backtrace* Expand::backtrace()
+  {
+    if (backtrace_stack.size() > 0)
+      return backtrace_stack.back();
+    return 0;
+  }
+
+  // blocks create new variable scopes
+  Statement* Expand::operator()(Block* 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,
+                                b->pstate(),
+                                b->length(),
+                                b->is_root());
+    // setup block and env stack
+    this->block_stack.push_back(bb);
+    this->env_stack.push_back(&env);
+    // operate on block
+    this->append_block(b);
+    // revert block and env stack
+    this->block_stack.pop_back();
+    this->env_stack.pop_back();
+    // return copy
+    return bb;
+  }
+
+  Statement* Expand::operator()(Ruleset* r)
+  {
+    // reset when leaving scope
+
+    if (in_keyframes) {
+      Keyframe_Rule* k = SASS_MEMORY_NEW(ctx.mem, Keyframe_Rule, r->pstate(), r->block()->perform(this)->block());
+      if (r->selector()) {
+        selector_stack.push_back(0);
+        k->selector(static_cast<Selector_List*>(r->selector()->perform(&eval)));
+        selector_stack.pop_back();
+      }
+      return k;
+    }
+
+    // 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;
+          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));
+              error("Base-level rules cannot contain the parent-selector-referencing character '&'.", header->pstate(), backtrace());
+            }
+            tail = tail->tail();
+          }
+        }
+      }
+    }
+
+    Expression* ex = r->selector()->perform(&eval);
+    Selector_List* sel = dynamic_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,
+                                  r->pstate(),
+                                  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());
+      }
+    }
+
+    property_stack.pop_back();
+
+    return 0;
+  }
+
+  Statement* Expand::operator()(Supports_Block* f)
+  {
+    Expression* condition = f->condition()->perform(&eval);
+    Supports_Block* ff = SASS_MEMORY_NEW(ctx.mem, Supports_Block,
+                                       f->pstate(),
+                                       static_cast<Supports_Condition*>(condition),
+                                       f->block()->perform(this)->block());
+    return ff;
+  }
+
+  Statement* Expand::operator()(Media_Block* 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,
+                                      m->pstate(),
+                                      static_cast<List*>(mq),
+                                      m->block()->perform(this)->block(),
+                                      0);
+    mm->tabs(m->tabs());
+    return mm;
+  }
+
+  Statement* Expand::operator()(At_Root_Block* a)
+  {
+    Block* ab = a->block();
+    // if (ab) ab->is_root(true);
+    Expression* 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,
+                                        a->pstate(),
+                                        bb,
+                                        static_cast<At_Root_Expression*>(ae));
+    // aa->block()->is_root(true);
+    return aa;
+  }
+
+  Statement* Expand::operator()(At_Rule* a)
+  {
+    LOCAL_FLAG(in_keyframes, a->is_keyframes());
+    Block* ab = a->block();
+    Selector* as = a->selector();
+    Expression* av = a->value();
+    selector_stack.push_back(0);
+    if (av) av = av->perform(&eval);
+    if (as) as = dynamic_cast<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,
+                                  a->pstate(),
+                                  a->keyword(),
+                                  as,
+                                  bb,
+                                  av);
+    return aa;
+  }
+
+  Statement* Expand::operator()(Declaration* 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,
+                                        d->pstate(),
+                                        new_p,
+                                        value,
+                                        d->is_important());
+    decl->tabs(d->tabs());
+    return decl;
+  }
+
+  Statement* Expand::operator()(Assignment* 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));
+          if (!e || e->concrete_type() == Expression::NULL_VAL) {
+            env->set_global(var, a->value()->perform(&eval));
+          }
+        }
+        else {
+          env->set_global(var, a->value()->perform(&eval));
+        }
+      }
+      else {
+        env->set_global(var, a->value()->perform(&eval));
+      }
+    }
+    else if (a->is_default()) {
+      if (env->has_lexical(var)) {
+        auto cur = env;
+        while (cur && cur->is_lexical()) {
+          if (cur->has_local(var)) {
+            if (AST_Node* node = cur->get_local(var)) {
+              Expression* e = dynamic_cast<Expression*>(node);
+              if (!e || e->concrete_type() == Expression::NULL_VAL) {
+                cur->set_local(var, a->value()->perform(&eval));
+              }
+            }
+            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(&eval));
+          }
+        }
+      }
+      else if (env->is_lexical()) {
+        env->set_local(var, a->value()->perform(&eval));
+      }
+      else {
+        env->set_local(var, a->value()->perform(&eval));
+      }
+    }
+    else {
+      env->set_lexical(var, a->value()->perform(&eval));
+    }
+    return 0;
+  }
+
+  Statement* Expand::operator()(Import* 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));
+    }
+    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;
+  }
+
+  Statement* Expand::operator()(Import_Stub* i)
+  {
+    // we don't seem to need that actually afterall
+    Sass_Import_Entry import = sass_make_import(
+      i->imp_path().c_str(),
+      i->abs_path().c_str(),
+      0, 0
+    );
+    ctx.import_stack.push_back(import);
+    const std::string& abs_path(i->resource().abs_path);
+    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)
+  {
+    // eval handles this too, because warnings may occur in functions
+    w->perform(&eval);
+    return 0;
+  }
+
+  Statement* Expand::operator()(Error* e)
+  {
+    // eval handles this too, because errors may occur in functions
+    e->perform(&eval);
+    return 0;
+  }
+
+  Statement* Expand::operator()(Debug* d)
+  {
+    // eval handles this too, because warnings may occur in functions
+    d->perform(&eval);
+    return 0;
+  }
+
+  Statement* Expand::operator()(Comment* c)
+  {
+    // 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());
+  }
+
+  Statement* Expand::operator()(If* i)
+  {
+    if (*i->predicate()->perform(&eval)) {
+      append_block(i->block());
+    }
+    else {
+      Block* alt = i->alternative();
+      if (alt) append_block(alt);
+    }
+    return 0;
+  }
+
+  // For does not create a new env scope
+  // But iteration vars are reset afterwards
+  Statement* Expand::operator()(For* f)
+  {
+    std::string variable(f->variable());
+    Expression* low = f->lower_bound()->perform(&eval);
+    if (low->concrete_type() != Expression::NUMBER) {
+      error("lower bound of `@for` directive must be numeric", low->pstate(), backtrace());
+    }
+    Expression* high = f->upper_bound()->perform(&eval);
+    if (high->concrete_type() != Expression::NUMBER) {
+      error("upper bound of `@for` directive must be numeric", high->pstate(), backtrace());
+    }
+    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 = 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();
+    if (start < end) {
+      if (f->is_inclusive()) ++end;
+      for (double i = start;
+           i < end;
+           ++i) {
+        it->value(i);
+        env->set_local(variable, it);
+        append_block(body);
+      }
+    } else {
+      if (f->is_inclusive()) --end;
+      for (double i = start;
+           i > end;
+           --i) {
+        it->value(i);
+        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);
+    return 0;
+  }
+
+  // Eval does not create a new env scope
+  // But iteration vars are reset afterwards
+  Statement* Expand::operator()(Each* e)
+  {
+    std::vector<std::string> variables(e->variables());
+    Expression* expr = e->list()->perform(&eval);
+    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
+    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();
+
+    if (map) {
+      for (auto key : map->keys()) {
+        Expression* k = key->perform(&eval);
+        Expression* 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);
+        } else {
+          env->set_local(variables[0], k);
+          env->set_local(variables[1], v);
+        }
+        append_block(body);
+      }
+    }
+    else {
+      bool arglist = list->is_arglist();
+      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;
+            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())
+                : (*scalars)[j]->perform(&eval);
+              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);
+            }
+          }
+        }
+        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]);
+    }
+    return 0;
+  }
+
+  Statement* Expand::operator()(While* w)
+  {
+    Expression* pred = w->predicate();
+    Block* body = w->block();
+    while (*pred->perform(&eval)) {
+      append_block(body);
+    }
+    return 0;
+  }
+
+  Statement* Expand::operator()(Return* 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;
+        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));
+            error("Can't extend " + sel_str + ": can't extend parent selectors", header->pstate(), backtrace());
+          }
+          tail = tail->tail();
+        }
+      }
+    }
+
+    Selector_List* contextualized = dynamic_cast<Selector_List*>(e->selector()->perform(&eval));
+    if (contextualized == NULL) return 0;
+    for (auto complex_sel : contextualized->elements()) {
+      Complex_Selector* c = complex_sel;
+      if (!c->head() || c->tail()) {
+        To_String to_string(&ctx); std::string sel_str(contextualized->perform(&to_string));
+        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());
+      for (size_t i = 0, L = extender->length(); i < L; ++i) {
+        Complex_Selector* sel = (*extender)[i];
+        if (!(sel->head() && sel->head()->length() > 0 &&
+            dynamic_cast<Parent_Selector*>((*sel->head())[0])))
+        {
+          Compound_Selector* hh = SASS_MEMORY_NEW(ctx.mem, 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());
+          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());
+          ps->media_block((*extender)[i]->media_block());
+          *hh << 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));
+      }
+    }
+
+    selector_stack.pop_back();
+
+    return 0;
+  }
+
+  Statement* Expand::operator()(Definition* d)
+  {
+    Env* env = environment();
+    Definition* dd = SASS_MEMORY_NEW(ctx.mem, Definition, *d);
+    env->local_frame()[d->name() +
+                        (d->type() == Definition::MIXIN ? "[m]" : "[f]")] = dd;
+
+    if (d->type() == Definition::FUNCTION && (
+      d->name() == "calc"       ||
+      d->name() == "element"    ||
+      d->name() == "expression" ||
+      d->name() == "url"
+    )) {
+      deprecated(
+        "Naming a function \"" + d->name() + "\" is disallowed",
+        "This name conflicts with an existing CSS function with special parse rules.",
+         d->pstate()
+      );
+    }
+
+
+    // set the static link so we can have lexical scoping
+    dd->environment(env);
+    return 0;
+  }
+
+  Statement* Expand::operator()(Mixin_Call* c)
+  {
+    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();
+
+    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));
+    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,
+                                          c->pstate(),
+                                          "@content",
+                                          SASS_MEMORY_NEW(ctx.mem, Parameters, c->pstate()),
+                                          c->block(),
+                                          Definition::MIXIN);
+      thunk->environment(env);
+      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();
+    env_stack.pop_back();
+    return 0;
+  }
+
+  Statement* Expand::operator()(Content* 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,
+                                       c->pstate(),
+                                       "@content",
+                                       SASS_MEMORY_NEW(ctx.mem, Arguments, c->pstate()));
+    Statement* stm = call->perform(this);
+    if (block_stack.back()->is_root()) {
+      selector_stack.pop_back();
+    }
+    return stm;
+  }
+
+  // produce an error if something is not implemented
+  inline Statement* Expand::fallback_impl(AST_Node* 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);
+    error("unknown internal error; please contact the LibSass maintainers", n->pstate(), backtrace());
+    return SASS_MEMORY_NEW(ctx.mem, Warning, ParserState("[WARN]"), msg);
+  }
+
+  // process and add to last block on stack
+  inline void Expand::append_block(Block* b)
+  {
+    for (size_t i = 0, L = b->length(); i < L; ++i) {
+      Statement* ith = (*b)[i]->perform(this);
+      if (ith) *block_stack.back() << ith;
+    }
+  }
+
+}
diff --git a/libsass/src/expand.hpp b/libsass/src/expand.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/expand.hpp
@@ -0,0 +1,79 @@
+#ifndef SASS_EXPAND_H
+#define SASS_EXPAND_H
+
+#include <vector>
+
+#include "ast.hpp"
+#include "eval.hpp"
+#include "operation.hpp"
+#include "environment.hpp"
+
+namespace Sass {
+
+  class Listize;
+  class Context;
+  class Eval;
+  typedef Environment<AST_Node*> Env;
+  struct Backtrace;
+
+  class Expand : public Operation_CRTP<Statement*, Expand> {
+  public:
+
+    Env* environment();
+    Context& context();
+    Selector_List* selector();
+    Backtrace* backtrace();
+
+    Context&          ctx;
+    Eval              eval;
+
+    // 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;
+
+    Statement* fallback_impl(AST_Node* n);
+
+  public:
+    Expand(Context&, Env*, Backtrace*);
+    virtual ~Expand() { }
+
+    using Operation<Statement*>::operator();
+
+    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*);
+
+    template <typename U>
+    Statement* fallback(U x) { return fallback_impl(x); }
+
+    void append_block(Block*);
+  };
+
+}
+
+#endif
diff --git a/libsass/src/extend.cpp b/libsass/src/extend.cpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/extend.cpp
@@ -0,0 +1,2069 @@
+#ifdef _MSC_VER
+#pragma warning(disable : 4503)
+#endif
+
+#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 "debug.hpp"
+#include <iostream>
+#include <deque>
+#include <set>
+
+
+/*
+ NOTES:
+
+ - The print* functions print to cerr. This allows our testing frameworks (like sass-spec) to ignore the output, which
+   is very helpful when debugging. The format of the output is mainly to wrap things in square brackets to match what
+   ruby already outputs (to make comparisons easier).
+
+ - For the direct porting effort, we're trying to port method-for-method until we get all the tests passing.
+   Where applicable, I've tried to include the ruby code above the function for reference until all our tests pass.
+   The ruby code isn't always directly portable, so I've tried to include any modified ruby code that was actually
+   used for the porting.
+
+ - DO NOT try to optimize yet. We get a tremendous benefit out of comparing the output of each stage of the extend to the ruby
+   output at the same stage. This makes it much easier to determine where problems are. Try to keep as close to
+   the ruby code as you can until we have all the sass-spec tests passing. Then, we should optimize. However, if you see
+   something that could probably be optimized, let's not forget it. Add a // TODO: or // IMPROVEMENT: comment.
+
+ - Coding conventions in this file (these may need to be changed before merging back into master)
+   - Very basic hungarian notation:
+     p prefix for pointers (pSelector)
+     no prefix for value types and references (selector)
+   - Use STL iterators where possible
+   - prefer verbose naming over terse naming
+   - use typedefs for STL container types for make maintenance easier
+
+ - You may see a lot of comments that say "// TODO: is this the correct combinator?". See the comment referring to combinators
+   in extendCompoundSelector for a more extensive explanation of my confusion. I think our divergence in data model from ruby
+   sass causes this to be necessary.
+
+
+ GLOBAL TODOS:
+
+ - wrap the contents of the print functions in DEBUG preprocesser conditionals so they will be optimized away in non-debug mode.
+
+ - consider making the extend* functions member functions to avoid passing around ctx and subset_map map around. This has the
+   drawback that the implementation details of the operator are then exposed to the outside world, which is not ideal and
+   can cause additional compile time dependencies.
+
+ - mark the helper methods in this file static to given them compilation unit linkage.
+
+ - implement parent directive matching
+
+ - fix compilation warnings for unused Extend members if we really don't need those references anymore.
+ */
+
+
+namespace Sass {
+
+
+  typedef std::pair<Complex_Selector*, Compound_Selector*> ExtensionPair;
+  typedef std::vector<ExtensionPair> SubsetMapEntries;
+
+#ifdef DEBUG
+
+  // TODO: move the ast specific ostream operators into ast.hpp/ast.cpp
+  std::ostream& operator<<(std::ostream& os, const Complex_Selector::Combinator combinator) {
+    switch (combinator) {
+      case Complex_Selector::ANCESTOR_OF: os << "\" \""; break;
+      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;
+    }
+
+    return os;
+  }
+
+
+  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);
+    }
+    return os;
+  }
+
+  std::ostream& operator<<(std::ostream& os, Simple_Selector& simpleSelector) {
+    To_String to_string;
+    os << simpleSelector.perform(&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;
+    }
+
+    if (pSimpleSelector) {
+      std::cerr << "[" << *pSimpleSelector << "]";
+    } else {
+      std::cerr << "NULL";
+    }
+
+    if (newline) {
+      std::cerr << std::endl;
+    }
+  }
+
+  // Print a string representation of a Compound_Selector
+    typedef std::pair<Compound_Selector*, Complex_Selector*> 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;
+
+    if (message) {
+      std::cerr << message;
+    }
+
+    if (pCompoundSelector) {
+      std::cerr << "[" << *pCompoundSelector << "]";
+    } else {
+      std::cerr << "NULL";
+    }
+
+    if (newline) {
+      std::cerr << std::endl;
+    }
+  }
+
+
+  std::ostream& operator<<(std::ostream& os, Complex_Selector& complexSelector) {
+    To_String to_string;
+
+    os << "[";
+    Complex_Selector* pIter = &complexSelector;
+    bool first = true;
+    while (pIter) {
+      if (pIter->combinator() != Complex_Selector::ANCESTOR_OF) {
+        if (!first) {
+          os << ", ";
+        }
+        first = false;
+        os << pIter->combinator();
+      }
+
+      if (!first) {
+        os << ", ";
+      }
+      first = false;
+
+      if (pIter->head()) {
+        os << pIter->head()->perform(&to_string);
+      } else {
+        os << "NULL_HEAD";
+      }
+
+      pIter = pIter->tail();
+    }
+    os << "]";
+
+    return os;
+  }
+
+
+  // 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;
+
+    if (message) {
+      std::cerr << message;
+    }
+
+    if (pComplexSelector) {
+      std::cerr << *pComplexSelector;
+    } else {
+      std::cerr << "NULL";
+    }
+
+    if (newline) {
+      std::cerr << std::endl;
+    }
+  }
+
+  static void printSelsNewSeqPairCollection(SelsNewSeqPairCollection& collection, const char* message=NULL, bool newline=true) {
+    To_String to_string;
+
+    if (message) {
+      std::cerr << message;
+    }
+    bool first = true;
+    std::cerr << "[";
+    for(SelsNewSeqPair& pair : collection) {
+      if (first) {
+        first = false;
+      } else {
+        std::cerr << ", ";
+      }
+      std::cerr << "[";
+      Compound_Selector* pSels = pair.first;
+      Complex_Selector* pNewSelector = pair.second;
+      std::cerr << "[" << *pSels << "], ";
+      printComplexSelector(pNewSelector, NULL, false);
+    }
+    std::cerr << "]";
+
+    if (newline) {
+      std::cerr << std::endl;
+    }
+  }
+
+  // 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;
+    }
+
+    // Convert to a deque of strings so we can sort since order doesn't matter in a set. This should cut down on
+    // the differences we see when debug printing.
+    typedef std::deque<std::string> SourceStrings;
+    SourceStrings sourceStrings;
+    for (SourcesSet::iterator iterator = sources.begin(), iteratorEnd = sources.end(); iterator != iteratorEnd; ++iterator) {
+      Complex_Selector* pSource = *iterator;
+      std::stringstream sstream;
+      sstream << complexSelectorToNode(pSource, ctx);
+      sourceStrings.push_back(sstream.str());
+    }
+
+    // Sort to get consistent output
+    std::sort(sourceStrings.begin(), sourceStrings.end());
+
+    std::cerr << "SourcesSet[";
+    for (SourceStrings::iterator iterator = sourceStrings.begin(), iteratorEnd = sourceStrings.end(); iterator != iteratorEnd; ++iterator) {
+      std::string source = *iterator;
+      if (iterator != sourceStrings.begin()) {
+        std::cerr << ", ";
+      }
+      std::cerr << source;
+    }
+    std::cerr << "]";
+
+    if (newline) {
+      std::cerr << std::endl;
+    }
+  }
+
+
+  std::ostream& operator<<(std::ostream& os, SubsetMapEntries& entries) {
+    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
+
+      if (iterator != entries.begin()) {
+        os << ", ";
+      }
+
+      os << "(";
+
+      if (pExtComplexSelector) {
+        std::cerr << *pExtComplexSelector;
+      } else {
+        std::cerr << "NULL";
+      }
+
+      os << " -> ";
+
+      if (pExtCompoundSelector) {
+        std::cerr << *pExtCompoundSelector;
+      } else {
+        std::cerr << "NULL";
+      }
+
+      os << ")";
+
+    }
+
+    os << "]";
+
+    return os;
+  }
+#endif
+
+  static bool parentSuperselector(Complex_Selector* pOne, Complex_Selector* 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*/);
+
+    pOne->set_innermost(&fakeParentContainer, Complex_Selector::ANCESTOR_OF);
+    pTwo->set_innermost(&fakeParentContainer, Complex_Selector::ANCESTOR_OF);
+
+    bool isSuperselector = pOne->is_superselector_of(pTwo);
+
+    pOne->clear_innermost();
+    pTwo->clear_innermost();
+
+    return isSuperselector;
+  }
+
+  void nodeToComplexSelectorDeque(const Node& node, ComplexSelectorDeque& out, Context& ctx) {
+    for (NodeDeque::iterator iter = node.collection()->begin(), iterEnd = node.collection()->end(); iter != iterEnd; iter++) {
+      Node& child = *iter;
+      out.push_back(nodeToComplexSelector(child, ctx));
+    }
+  }
+
+  Node complexSelectorDequeToNode(const ComplexSelectorDeque& deque, Context& ctx) {
+    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));
+    }
+
+    return result;
+  }
+
+  class LcsCollectionComparator {
+  public:
+    LcsCollectionComparator(Context& ctx) : mCtx(ctx) {}
+
+    Context& mCtx;
+
+    bool operator()(Complex_Selector* pOne, Complex_Selector* pTwo, Complex_Selector*& pOut) const {
+      /*
+      This code is based on the following block from ruby sass' subweave
+        do |s1, s2|
+          next s1 if s1 == s2
+          next unless s1.first.is_a?(SimpleSequence) && s2.first.is_a?(SimpleSequence)
+          next s2 if parent_superselector?(s1, s2)
+          next s1 if parent_superselector?(s2, s1)
+        end
+      */
+
+      if (selectors_equal(*pOne, *pTwo, true /*simpleSelectorOrderDependent*/)) {
+        pOut = pOne;
+        return true;
+      }
+
+      if (pOne->combinator() != Complex_Selector::ANCESTOR_OF || pTwo->combinator() != Complex_Selector::ANCESTOR_OF) {
+        return false;
+      }
+
+      if (parentSuperselector(pOne, pTwo, mCtx)) {
+        pOut = pTwo;
+        return true;
+      }
+
+      if (parentSuperselector(pTwo, pOne, mCtx)) {
+        pOut = pOne;
+        return true;
+      }
+
+      return false;
+    }
+  };
+
+
+  /*
+  This is the equivalent of ruby's Sass::Util.lcs_backtrace.
+
+  # Computes a single longest common subsequence for arrays x and y.
+  # Algorithm from http://en.wikipedia.org/wiki/Longest_common_subsequence_problem#Reading_out_an_LCS
+  */
+  void lcs_backtrace(const LCSTable& c, ComplexSelectorDeque& x, ComplexSelectorDeque& y, int i, int j, const LcsCollectionComparator& comparator, ComplexSelectorDeque& out) {
+    //DEBUG_PRINTLN(LCS, "LCSBACK: X=" << x << " Y=" << y << " I=" << i << " J=" << j)
+    // TODO: make printComplexSelectorDeque and use DEBUG_EXEC AND DEBUG_PRINTLN HERE to get equivalent output
+
+    if (i == 0 || j == 0) {
+      DEBUG_PRINTLN(LCS, "RETURNING EMPTY")
+      return;
+    }
+
+
+    Complex_Selector* pCompareOut = NULL;
+    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);
+      out.push_back(pCompareOut);
+      return;
+    }
+
+    if (c[i][j - 1] > c[i - 1][j]) {
+      DEBUG_PRINTLN(LCS, "RETURNING AFTER TABLE COMPARE")
+      lcs_backtrace(c, x, y, i, j - 1, comparator, out);
+      return;
+    }
+
+    DEBUG_PRINTLN(LCS, "FINAL RETURN")
+    lcs_backtrace(c, x, y, i - 1, j, comparator, out);
+    return;
+  }
+
+  /*
+  This is the equivalent of ruby's Sass::Util.lcs_table.
+
+  # Calculates the memoization table for the Least Common Subsequence algorithm.
+  # Algorithm from http://en.wikipedia.org/wiki/Longest_common_subsequence_problem#Computing_the_length_of_the_LCS
+  */
+  void lcs_table(const ComplexSelectorDeque& x, const ComplexSelectorDeque& y, const LcsCollectionComparator& comparator, LCSTable& out) {
+    //DEBUG_PRINTLN(LCS, "LCSTABLE: X=" << x << " Y=" << y)
+    // TODO: make printComplexSelectorDeque and use DEBUG_EXEC AND DEBUG_PRINTLN HERE to get equivalent output
+
+    LCSTable c(x.size(), std::vector<int>(y.size()));
+
+    // These shouldn't be necessary since the vector will be initialized to 0 already.
+    // x.size.times {|i| c[i][0] = 0}
+    // y.size.times {|j| c[0][j] = 0}
+
+    for (size_t i = 1; i < x.size(); i++) {
+      for (size_t j = 1; j < y.size(); j++) {
+        Complex_Selector* pCompareOut = NULL;
+
+        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]);
+        }
+      }
+    }
+
+    out = c;
+  }
+
+  /*
+  This is the equivalent of ruby's Sass::Util.lcs.
+
+  # Computes a single longest common subsequence for `x` and `y`.
+  # If there are more than one longest common subsequences,
+  # the one returned is that which starts first in `x`.
+
+  # @param x [NodeCollection]
+  # @param y [NodeCollection]
+  # @comparator An equality check between elements of `x` and `y`.
+  # @return [NodeCollection] The LCS
+
+  http://en.wikipedia.org/wiki/Longest_common_subsequence_problem
+  */
+  void lcs(ComplexSelectorDeque& x, ComplexSelectorDeque& y, const LcsCollectionComparator& comparator, Context& ctx, ComplexSelectorDeque& out) {
+    //DEBUG_PRINTLN(LCS, "LCS: X=" << x << " Y=" << y)
+    // TODO: make printComplexSelectorDeque and use DEBUG_EXEC AND DEBUG_PRINTLN HERE to get equivalent output
+
+    x.push_front(NULL);
+    y.push_front(NULL);
+
+    LCSTable table;
+    lcs_table(x, y, comparator, table);
+
+    return lcs_backtrace(table, x, y, static_cast<int>(x.size()) - 1, static_cast<int>(y.size()) - 1, comparator, out);
+  }
+
+
+  /*
+   This is the equivalent of ruby's Sequence.trim.
+
+   The following is the modified version of the ruby code that was more portable to C++. You
+   should be able to drop it into ruby 3.2.19 and get the same results from ruby sass.
+
+        # Avoid truly horrific quadratic behavior. TODO: I think there
+        # may be a way to get perfect trimming without going quadratic.
+        return seqses if seqses.size > 100
+
+        # Keep the results in a separate array so we can be sure we aren't
+        # comparing against an already-trimmed selector. This ensures that two
+        # identical selectors don't mutually trim one another.
+        result = seqses.dup
+
+        # This is n^2 on the sequences, but only comparing between
+        # separate sequences should limit the quadratic behavior.
+        seqses.each_with_index do |seqs1, i|
+          tempResult = []
+
+          for seq1 in seqs1 do
+            max_spec = 0
+            for seq in _sources(seq1) do
+              max_spec = [max_spec, seq.specificity].max
+            end
+
+
+            isMoreSpecificOuter = false
+            for seqs2 in result do
+              if seqs1.equal?(seqs2) then
+                next
+              end
+
+              # Second Law of Extend: the specificity of a generated selector
+              # should never be less than the specificity of the extending
+              # selector.
+              #
+              # See https://github.com/nex3/sass/issues/324.
+              isMoreSpecificInner = false
+              for seq2 in seqs2 do
+                isMoreSpecificInner = _specificity(seq2) >= max_spec && _superselector?(seq2, seq1)
+                if isMoreSpecificInner then
+                  break
+                end
+              end
+
+              if isMoreSpecificInner then
+                isMoreSpecificOuter = true
+                break
+              end
+            end
+
+            if !isMoreSpecificOuter then
+              tempResult.push(seq1)
+            end
+          end
+
+          result[i] = tempResult
+
+        end
+
+        result
+   */
+  /*
+   - IMPROVEMENT: We could probably work directly in the output trimmed deque.
+   */
+  static Node trim(Node& seqses, Context& ctx, bool isReplace) {
+    // See the comments in the above ruby code before embarking on understanding this function.
+
+    // Avoid poor performance in extreme cases.
+    if (seqses.collection()->size() > 100) {
+      return seqses;
+    }
+
+
+    DEBUG_PRINTLN(TRIM, "TRIM: " << seqses)
+
+
+    Node result = Node::createCollection();
+    result.plus(seqses);
+
+    DEBUG_PRINTLN(TRIM, "RESULT INITIAL: " << result)
+
+    // Normally we use the standard STL iterators, but in this case, we need to access the result collection by index since we're
+    // iterating the input collection, computing a value, and then setting the result in the output collection. We have to keep track
+    // of the index manually.
+    int toTrimIndex = 0;
+
+    for (NodeDeque::iterator seqsesIter = seqses.collection()->begin(), seqsesIterEnd = seqses.collection()->end(); seqsesIter != seqsesIterEnd; ++seqsesIter) {
+      Node& seqs1 = *seqsesIter;
+
+      DEBUG_PRINTLN(TRIM, "SEQS1: " << seqs1 << " " << toTrimIndex)
+
+      Node tempResult = Node::createCollection();
+      tempResult.got_line_feed = seqs1.got_line_feed;
+
+      for (NodeDeque::iterator seqs1Iter = seqs1.collection()->begin(), seqs1EndIter = seqs1.collection()->end(); seqs1Iter != seqs1EndIter; ++seqs1Iter) {
+        Node& seq1 = *seqs1Iter;
+
+        Complex_Selector* 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.
+        //
+        // TODO: I'm pretty sure there's a bug in the sources code. It was implemented for sass-spec's 182_test_nested_extend_loop test.
+        // While the test passes, I compared the state of each trim call to verify correctness. The last trim call had incorrect sources. We
+        // had an extra source that the ruby version did not have. Without a failing test case, this is going to be extra hard to find. My
+        // best guess at this point is that we're cloning an object somewhere and maintaining the sources when we shouldn't be. This is purely
+        // a guess though.
+        unsigned long maxSpecificity = isReplace ? pSeq1->specificity() : 0;
+        SourcesSet sources = pSeq1->sources();
+
+        DEBUG_PRINTLN(TRIM, "TRIM SEQ1: " << seq1)
+        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;
+          maxSpecificity = std::max(maxSpecificity, pCurrentSelector->specificity());
+        }
+
+        DEBUG_PRINTLN(TRIM, "MAX SPECIFICITY: " << maxSpecificity)
+
+        bool isMoreSpecificOuter = false;
+
+        int resultIndex = 0;
+
+        for (NodeDeque::iterator resultIter = result.collection()->begin(), resultIterEnd = result.collection()->end(); resultIter != resultIterEnd; ++resultIter) {
+          Node& seqs2 = *resultIter;
+
+          DEBUG_PRINTLN(TRIM, "SEQS1: " << seqs1)
+          DEBUG_PRINTLN(TRIM, "SEQS2: " << seqs2)
+
+          // Do not compare the same sequence to itself. The ruby call we're trying to
+          // emulate is: seqs1.equal?(seqs2). equal? is an object comparison, not an equivalency comparision.
+          // Since we have the same pointers in seqes and results, we can do a pointer comparision. seqs1 is
+          // derived from seqses and seqs2 is derived from result.
+          if (seqs1.collection() == seqs2.collection()) {
+            DEBUG_PRINTLN(TRIM, "CONTINUE")
+            continue;
+          }
+
+          bool isMoreSpecificInner = false;
+
+          for (NodeDeque::iterator seqs2Iter = seqs2.collection()->begin(), seqs2IterEnd = seqs2.collection()->end(); seqs2Iter != seqs2IterEnd; ++seqs2Iter) {
+            Node& seq2 = *seqs2Iter;
+
+            Complex_Selector* pSeq2 = nodeToComplexSelector(seq2, ctx);
+
+            DEBUG_PRINTLN(TRIM, "SEQ2 SPEC: " << pSeq2->specificity())
+            DEBUG_PRINTLN(TRIM, "IS SPEC: " << pSeq2->specificity() << " >= " << maxSpecificity << " " << (pSeq2->specificity() >= maxSpecificity ? "true" : "false"))
+            DEBUG_PRINTLN(TRIM, "IS SUPER: " << (pSeq2->is_superselector_of(pSeq1) ? "true" : "false"))
+
+            isMoreSpecificInner = pSeq2->specificity() >= maxSpecificity && pSeq2->is_superselector_of(pSeq1);
+
+            if (isMoreSpecificInner) {
+              DEBUG_PRINTLN(TRIM, "FOUND MORE SPECIFIC")
+              break;
+            }
+          }
+
+          // If we found something more specific, we're done. Let the outer loop know and stop iterating.
+          if (isMoreSpecificInner) {
+            isMoreSpecificOuter = true;
+            break;
+          }
+
+          resultIndex++;
+        }
+
+        if (!isMoreSpecificOuter) {
+          DEBUG_PRINTLN(TRIM, "PUSHING: " << seq1)
+          tempResult.collection()->push_back(seq1);
+        }
+
+      }
+
+      DEBUG_PRINTLN(TRIM, "RESULT BEFORE ASSIGN: " << result)
+      DEBUG_PRINTLN(TRIM, "TEMP RESULT: " << toTrimIndex << " " << tempResult)
+      (*result.collection())[toTrimIndex] = tempResult;
+
+      toTrimIndex++;
+
+      DEBUG_PRINTLN(TRIM, "RESULT: " << result)
+    }
+
+    return result;
+  }
+
+
+
+  static bool parentSuperselector(const Node& one, const Node& two, 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*/);
+
+    Complex_Selector* pOneWithFakeParent = nodeToComplexSelector(one, ctx);
+    pOneWithFakeParent->set_innermost(&fakeParentContainer, Complex_Selector::ANCESTOR_OF);
+    Complex_Selector* pTwoWithFakeParent = nodeToComplexSelector(two, ctx);
+    pTwoWithFakeParent->set_innermost(&fakeParentContainer, Complex_Selector::ANCESTOR_OF);
+
+    return pOneWithFakeParent->is_superselector_of(pTwoWithFakeParent);
+  }
+
+
+  class ParentSuperselectorChunker {
+  public:
+    ParentSuperselectorChunker(Node& lcs, Context& ctx) : mLcs(lcs), mCtx(ctx) {}
+    Node& mLcs;
+    Context& mCtx;
+
+    bool operator()(const Node& seq) const {
+      // {|s| parent_superselector?(s.first, lcs.first)}
+      if (seq.collection()->size() == 0) return false;
+      return parentSuperselector(seq.collection()->front(), mLcs.collection()->front(), mCtx);
+    }
+  };
+
+  class SubweaveEmptyChunker {
+  public:
+    bool operator()(const Node& seq) const {
+      // {|s| s.empty?}
+
+      return seq.collection()->empty();
+    }
+  };
+
+  /*
+  # Takes initial subsequences of `seq1` and `seq2` and returns all
+  # orderings of those subsequences. The initial subsequences are determined
+  # by a block.
+  #
+  # Destructively removes the initial subsequences of `seq1` and `seq2`.
+  #
+  # For example, given `(A B C | D E)` and `(1 2 | 3 4 5)` (with `|`
+  # denoting the boundary of the initial subsequence), this would return
+  # `[(A B C 1 2), (1 2 A B C)]`. The sequences would then be `(D E)` and
+  # `(3 4 5)`.
+  #
+  # @param seq1 [Array]
+  # @param seq2 [Array]
+  # @yield [a] Used to determine when to cut off the initial subsequences.
+  #   Called repeatedly for each sequence until it returns true.
+  # @yieldparam a [Array] A final subsequence of one input sequence after
+  #   cutting off some initial subsequence.
+  # @yieldreturn [Boolean] Whether or not to cut off the initial subsequence
+  #   here.
+  # @return [Array<Array>] All possible orderings of the initial subsequences.
+  def chunks(seq1, seq2)
+    chunk1 = []
+    chunk1 << seq1.shift until yield seq1
+    chunk2 = []
+    chunk2 << seq2.shift until yield seq2
+    return [] if chunk1.empty? && chunk2.empty?
+    return [chunk2] if chunk1.empty?
+    return [chunk1] if chunk2.empty?
+    [chunk1 + chunk2, chunk2 + chunk1]
+  end
+  */
+  template<typename ChunkerType>
+  static Node chunks(Node& seq1, Node& seq2, const ChunkerType& chunker) {
+    Node chunk1 = Node::createCollection();
+    while (seq1.collection()->size() && !chunker(seq1)) {
+      chunk1.collection()->push_back(seq1.collection()->front());
+      seq1.collection()->pop_front();
+    }
+
+    Node chunk2 = Node::createCollection();
+    while (!chunker(seq2)) {
+      chunk2.collection()->push_back(seq2.collection()->front());
+      seq2.collection()->pop_front();
+    }
+
+    if (chunk1.collection()->empty() && chunk2.collection()->empty()) {
+      DEBUG_PRINTLN(CHUNKS, "RETURNING BOTH EMPTY")
+      return Node::createCollection();
+    }
+
+    if (chunk1.collection()->empty()) {
+      Node chunk2Wrapper = Node::createCollection();
+      chunk2Wrapper.collection()->push_back(chunk2);
+      DEBUG_PRINTLN(CHUNKS, "RETURNING ONE EMPTY")
+      return chunk2Wrapper;
+    }
+
+    if (chunk2.collection()->empty()) {
+      Node chunk1Wrapper = Node::createCollection();
+      chunk1Wrapper.collection()->push_back(chunk1);
+      DEBUG_PRINTLN(CHUNKS, "RETURNING TWO EMPTY")
+      return chunk1Wrapper;
+    }
+
+    Node perms = Node::createCollection();
+
+    Node firstPermutation = Node::createCollection();
+    firstPermutation.collection()->insert(firstPermutation.collection()->end(), chunk1.collection()->begin(), chunk1.collection()->end());
+    firstPermutation.collection()->insert(firstPermutation.collection()->end(), chunk2.collection()->begin(), chunk2.collection()->end());
+    perms.collection()->push_back(firstPermutation);
+
+    Node secondPermutation = Node::createCollection();
+    secondPermutation.collection()->insert(secondPermutation.collection()->end(), chunk2.collection()->begin(), chunk2.collection()->end());
+    secondPermutation.collection()->insert(secondPermutation.collection()->end(), chunk1.collection()->begin(), chunk1.collection()->end());
+    perms.collection()->push_back(secondPermutation);
+
+    DEBUG_PRINTLN(CHUNKS, "RETURNING PERM")
+
+    return perms;
+  }
+
+
+  static Node groupSelectors(Node& seq, Context& ctx) {
+    Node newSeq = Node::createCollection();
+
+    Node tail = Node::createCollection();
+    tail.plus(seq);
+
+    while (!tail.collection()->empty()) {
+      Node head = Node::createCollection();
+
+      do {
+        head.collection()->push_back(tail.collection()->front());
+        tail.collection()->pop_front();
+      } while (!tail.collection()->empty() && (head.collection()->back().isCombinator() || tail.collection()->front().isCombinator()));
+
+      newSeq.collection()->push_back(head);
+    }
+
+    return newSeq;
+  }
+
+
+  static void getAndRemoveInitialOps(Node& seq, Node& ops) {
+    NodeDeque& seqCollection = *(seq.collection());
+    NodeDeque& opsCollection = *(ops.collection());
+
+    while (seqCollection.size() > 0 && seqCollection.front().isCombinator()) {
+      opsCollection.push_back(seqCollection.front());
+      seqCollection.pop_front();
+    }
+  }
+
+
+  static void getAndRemoveFinalOps(Node& seq, Node& ops) {
+    NodeDeque& seqCollection = *(seq.collection());
+    NodeDeque& opsCollection = *(ops.collection());
+
+    while (seqCollection.size() > 0 && seqCollection.back().isCombinator()) {
+      opsCollection.push_back(seqCollection.back()); // Purposefully reversed to match ruby code
+      seqCollection.pop_back();
+    }
+  }
+
+
+  /*
+      def merge_initial_ops(seq1, seq2)
+        ops1, ops2 = [], []
+        ops1 << seq1.shift while seq1.first.is_a?(String)
+        ops2 << seq2.shift while seq2.first.is_a?(String)
+
+        newline = false
+        newline ||= !!ops1.shift if ops1.first == "\n"
+        newline ||= !!ops2.shift if ops2.first == "\n"
+
+        # If neither sequence is a subsequence of the other, they cannot be
+        # merged successfully
+        lcs = Sass::Util.lcs(ops1, ops2)
+        return unless lcs == ops1 || lcs == ops2
+        return (newline ? ["\n"] : []) + (ops1.size > ops2.size ? ops1 : ops2)
+      end
+  */
+  static Node mergeInitialOps(Node& seq1, Node& seq2, Context& ctx) {
+    Node ops1 = Node::createCollection();
+    Node ops2 = Node::createCollection();
+
+    getAndRemoveInitialOps(seq1, ops1);
+    getAndRemoveInitialOps(seq2, ops2);
+
+    // TODO: Do we have this information available to us?
+    // newline = false
+    // newline ||= !!ops1.shift if ops1.first == "\n"
+    // newline ||= !!ops2.shift if ops2.first == "\n"
+
+    // If neither sequence is a subsequence of the other, they cannot be merged successfully
+    DefaultLcsComparator lcsDefaultComparator;
+    Node opsLcs = lcs(ops1, ops2, lcsDefaultComparator, ctx);
+
+    if (!(opsLcs == ops1 || opsLcs == ops2)) {
+      return Node::createNil();
+    }
+
+    // TODO: more newline logic
+    // return (newline ? ["\n"] : []) + (ops1.size > ops2.size ? ops1 : ops2)
+
+    return (ops1.collection()->size() > ops2.collection()->size() ? ops1 : ops2);
+  }
+
+
+  /*
+      def merge_final_ops(seq1, seq2, res = [])
+
+
+        # This code looks complicated, but it's actually just a bunch of special
+        # cases for interactions between different combinators.
+        op1, op2 = ops1.first, ops2.first
+        if op1 && op2
+          sel1 = seq1.pop
+          sel2 = seq2.pop
+          if op1 == '~' && op2 == '~'
+            if sel1.superselector?(sel2)
+              res.unshift sel2, '~'
+            elsif sel2.superselector?(sel1)
+              res.unshift sel1, '~'
+            else
+              merged = sel1.unify(sel2.members, sel2.subject?)
+              res.unshift [
+                [sel1, '~', sel2, '~'],
+                [sel2, '~', sel1, '~'],
+                ([merged, '~'] if merged)
+              ].compact
+            end
+          elsif (op1 == '~' && op2 == '+') || (op1 == '+' && op2 == '~')
+            if op1 == '~'
+              tilde_sel, plus_sel = sel1, sel2
+            else
+              tilde_sel, plus_sel = sel2, sel1
+            end
+
+            if tilde_sel.superselector?(plus_sel)
+              res.unshift plus_sel, '+'
+            else
+              merged = plus_sel.unify(tilde_sel.members, tilde_sel.subject?)
+              res.unshift [
+                [tilde_sel, '~', plus_sel, '+'],
+                ([merged, '+'] if merged)
+              ].compact
+            end
+          elsif op1 == '>' && %w[~ +].include?(op2)
+            res.unshift sel2, op2
+            seq1.push sel1, op1
+          elsif op2 == '>' && %w[~ +].include?(op1)
+            res.unshift sel1, op1
+            seq2.push sel2, op2
+          elsif op1 == op2
+            return unless merged = sel1.unify(sel2.members, sel2.subject?)
+            res.unshift merged, op1
+          else
+            # Unknown selector combinators can't be unified
+            return
+          end
+          return merge_final_ops(seq1, seq2, res)
+        elsif op1
+          seq2.pop if op1 == '>' && seq2.last && seq2.last.superselector?(seq1.last)
+          res.unshift seq1.pop, op1
+          return merge_final_ops(seq1, seq2, res)
+        else # op2
+          seq1.pop if op2 == '>' && seq1.last && seq1.last.superselector?(seq2.last)
+          res.unshift seq2.pop, op2
+          return merge_final_ops(seq1, seq2, res)
+        end
+      end
+  */
+  static Node mergeFinalOps(Node& seq1, Node& seq2, Context& ctx, Node& res) {
+
+    Node ops1 = Node::createCollection();
+    Node ops2 = Node::createCollection();
+
+    getAndRemoveFinalOps(seq1, ops1);
+    getAndRemoveFinalOps(seq2, ops2);
+
+    // TODO: do we have newlines to remove?
+    // ops1.reject! {|o| o == "\n"}
+    // ops2.reject! {|o| o == "\n"}
+
+    if (ops1.collection()->empty() && ops2.collection()->empty()) {
+      return res;
+    }
+
+    if (ops1.collection()->size() > 1 || ops2.collection()->size() > 1) {
+      DefaultLcsComparator lcsDefaultComparator;
+      Node opsLcs = lcs(ops1, ops2, lcsDefaultComparator, ctx);
+
+      // 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)) {
+        return Node::createNil();
+      }
+
+      if (ops1.collection()->size() > ops2.collection()->size()) {
+        res.collection()->insert(res.collection()->begin(), ops1.collection()->rbegin(), ops1.collection()->rend());
+      } else {
+        res.collection()->insert(res.collection()->begin(), ops2.collection()->rbegin(), ops2.collection()->rend());
+      }
+
+      return res;
+    }
+
+    if (!ops1.collection()->empty() && !ops2.collection()->empty()) {
+
+      Node op1 = ops1.collection()->front();
+      Node op2 = ops2.collection()->front();
+
+      Node sel1 = seq1.collection()->back();
+      seq1.collection()->pop_back();
+
+      Node sel2 = seq2.collection()->back();
+      seq2.collection()->pop_back();
+
+      if (op1.combinator() == Complex_Selector::PRECEDES && op2.combinator() == Complex_Selector::PRECEDES) {
+
+        if (sel1.selector()->is_superselector_of(sel2.selector())) {
+
+          res.collection()->push_front(op1 /*PRECEDES - could have been op2 as well*/);
+          res.collection()->push_front(sel2);
+
+        } else if (sel2.selector()->is_superselector_of(sel1.selector())) {
+
+          res.collection()->push_front(op1 /*PRECEDES - could have been op2 as well*/);
+          res.collection()->push_front(sel1);
+
+        } else {
+
+          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
+          // 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);
+          pMergedWrapper->head(pMerged);
+
+          DEBUG_EXEC(ALL, printCompoundSelector(pMerged, "MERGED: "))
+
+          Node newRes = Node::createCollection();
+
+          Node firstPerm = Node::createCollection();
+          firstPerm.collection()->push_back(sel1);
+          firstPerm.collection()->push_back(Node::createCombinator(Complex_Selector::PRECEDES));
+          firstPerm.collection()->push_back(sel2);
+          firstPerm.collection()->push_back(Node::createCombinator(Complex_Selector::PRECEDES));
+          newRes.collection()->push_back(firstPerm);
+
+          Node secondPerm = Node::createCollection();
+          secondPerm.collection()->push_back(sel2);
+          secondPerm.collection()->push_back(Node::createCombinator(Complex_Selector::PRECEDES));
+          secondPerm.collection()->push_back(sel1);
+          secondPerm.collection()->push_back(Node::createCombinator(Complex_Selector::PRECEDES));
+          newRes.collection()->push_back(secondPerm);
+
+          if (pMerged) {
+            Node mergedPerm = Node::createCollection();
+            mergedPerm.collection()->push_back(Node::createSelector(pMergedWrapper, ctx));
+            mergedPerm.collection()->push_back(Node::createCombinator(Complex_Selector::PRECEDES));
+            newRes.collection()->push_back(mergedPerm);
+          }
+
+          res.collection()->push_front(newRes);
+
+          DEBUG_PRINTLN(ALL, "RESULT: " << res)
+
+        }
+
+      } else if (((op1.combinator() == Complex_Selector::PRECEDES && op2.combinator() == Complex_Selector::ADJACENT_TO)) || ((op1.combinator() == Complex_Selector::ADJACENT_TO && op2.combinator() == Complex_Selector::PRECEDES))) {
+
+          Node tildeSel = sel1;
+          Node tildeOp = op1;
+          Node plusSel = sel2;
+          Node plusOp = op2;
+          if (op1.combinator() != Complex_Selector::PRECEDES) {
+            tildeSel = sel2;
+            tildeOp = op2;
+            plusSel = sel1;
+            plusOp = op1;
+          }
+
+          if (tildeSel.selector()->is_superselector_of(plusSel.selector())) {
+
+            res.collection()->push_front(plusOp);
+            res.collection()->push_front(plusSel);
+
+          } else {
+
+            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
+            // 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);
+            pMergedWrapper->head(pMerged);
+
+            DEBUG_EXEC(ALL, printCompoundSelector(pMerged, "MERGED: "))
+
+            Node newRes = Node::createCollection();
+
+            Node firstPerm = Node::createCollection();
+            firstPerm.collection()->push_back(tildeSel);
+            firstPerm.collection()->push_back(Node::createCombinator(Complex_Selector::PRECEDES));
+            firstPerm.collection()->push_back(plusSel);
+            firstPerm.collection()->push_back(Node::createCombinator(Complex_Selector::ADJACENT_TO));
+            newRes.collection()->push_back(firstPerm);
+
+            if (pMerged) {
+              Node mergedPerm = Node::createCollection();
+              mergedPerm.collection()->push_back(Node::createSelector(pMergedWrapper, ctx));
+              mergedPerm.collection()->push_back(Node::createCombinator(Complex_Selector::ADJACENT_TO));
+              newRes.collection()->push_back(mergedPerm);
+            }
+
+            res.collection()->push_front(newRes);
+
+            DEBUG_PRINTLN(ALL, "RESULT: " << res)
+
+          }
+      } else if (op1.combinator() == Complex_Selector::PARENT_OF && (op2.combinator() == Complex_Selector::PRECEDES || op2.combinator() == Complex_Selector::ADJACENT_TO)) {
+
+        res.collection()->push_front(op2);
+        res.collection()->push_front(sel2);
+
+        seq1.collection()->push_back(sel1);
+        seq1.collection()->push_back(op1);
+
+      } else if (op2.combinator() == Complex_Selector::PARENT_OF && (op1.combinator() == Complex_Selector::PRECEDES || op1.combinator() == Complex_Selector::ADJACENT_TO)) {
+
+        res.collection()->push_front(op1);
+        res.collection()->push_front(sel1);
+
+        seq2.collection()->push_back(sel2);
+        seq2.collection()->push_back(op2);
+
+      } else if (op1.combinator() == op2.combinator()) {
+
+        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
+        // 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);
+        pMergedWrapper->head(pMerged);
+
+        DEBUG_EXEC(ALL, printCompoundSelector(pMerged, "MERGED: "))
+
+        if (!pMerged) {
+          return Node::createNil();
+        }
+
+        res.collection()->push_front(op1);
+        res.collection()->push_front(Node::createSelector(pMergedWrapper, ctx));
+
+        DEBUG_PRINTLN(ALL, "RESULT: " << res)
+
+      } else {
+        return Node::createNil();
+      }
+
+      return mergeFinalOps(seq1, seq2, ctx, res);
+
+    } else if (!ops1.collection()->empty()) {
+
+      Node op1 = ops1.collection()->front();
+
+      if (op1.combinator() == Complex_Selector::PARENT_OF && !seq2.collection()->empty() && seq2.collection()->back().selector()->is_superselector_of(seq1.collection()->back().selector())) {
+        seq2.collection()->pop_back();
+      }
+
+      // TODO: consider unshift(NodeCollection, Node)
+      res.collection()->push_front(op1);
+      res.collection()->push_front(seq1.collection()->back());
+      seq1.collection()->pop_back();
+
+      return mergeFinalOps(seq1, seq2, ctx, res);
+
+    } else { // !ops2.collection()->empty()
+
+      Node op2 = ops2.collection()->front();
+
+      if (op2.combinator() == Complex_Selector::PARENT_OF && !seq1.collection()->empty() && seq1.collection()->back().selector()->is_superselector_of(seq2.collection()->back().selector())) {
+        seq1.collection()->pop_back();
+      }
+
+      res.collection()->push_front(op2);
+      res.collection()->push_front(seq2.collection()->back());
+      seq2.collection()->pop_back();
+
+      return mergeFinalOps(seq1, seq2, ctx, res);
+
+    }
+
+  }
+
+
+  /*
+    This is the equivalent of ruby's Sequence.subweave.
+
+    Here is the original subweave code for reference during porting.
+
+      def subweave(seq1, seq2)
+        return [seq2] if seq1.empty?
+        return [seq1] if seq2.empty?
+
+        seq1, seq2 = seq1.dup, seq2.dup
+        return unless init = merge_initial_ops(seq1, seq2)
+        return unless fin = merge_final_ops(seq1, seq2)
+        seq1 = group_selectors(seq1)
+        seq2 = group_selectors(seq2)
+        lcs = Sass::Util.lcs(seq2, seq1) do |s1, s2|
+          next s1 if s1 == s2
+          next unless s1.first.is_a?(SimpleSequence) && s2.first.is_a?(SimpleSequence)
+          next s2 if parent_superselector?(s1, s2)
+          next s1 if parent_superselector?(s2, s1)
+        end
+
+        diff = [[init]]
+        until lcs.empty?
+          diff << chunks(seq1, seq2) {|s| parent_superselector?(s.first, lcs.first)} << [lcs.shift]
+          seq1.shift
+          seq2.shift
+        end
+        diff << chunks(seq1, seq2) {|s| s.empty?}
+        diff += fin.map {|sel| sel.is_a?(Array) ? sel : [sel]}
+        diff.reject! {|c| c.empty?}
+
+        result = Sass::Util.paths(diff).map {|p| p.flatten}.reject {|p| path_has_two_subjects?(p)}
+
+        result
+      end
+  */
+  Node Extend::subweave(Node& one, Node& two, Context& ctx) {
+    // Check for the simple cases
+    if (one.collection()->size() == 0) {
+      Node out = Node::createCollection();
+      out.collection()->push_back(two);
+      return out;
+    }
+    if (two.collection()->size() == 0) {
+      Node out = Node::createCollection();
+      out.collection()->push_back(one);
+      return out;
+    }
+
+
+
+    Node seq1 = Node::createCollection();
+    seq1.plus(one);
+    Node seq2 = Node::createCollection();
+    seq2.plus(two);
+
+    DEBUG_PRINTLN(SUBWEAVE, "SUBWEAVE ONE: " << seq1)
+    DEBUG_PRINTLN(SUBWEAVE, "SUBWEAVE TWO: " << seq2)
+
+    Node init = mergeInitialOps(seq1, seq2, ctx);
+    if (init.isNil()) {
+      return Node::createNil();
+    }
+
+    DEBUG_PRINTLN(SUBWEAVE, "INIT: " << init)
+
+    Node res = Node::createCollection();
+    Node fin = mergeFinalOps(seq1, seq2, ctx, res);
+    if (fin.isNil()) {
+      return Node::createNil();
+    }
+
+    DEBUG_PRINTLN(SUBWEAVE, "FIN: " << fin)
+
+
+    // Moving this line up since fin isn't modified between now and when it happened before
+    // fin.map {|sel| sel.is_a?(Array) ? sel : [sel]}
+
+    for (NodeDeque::iterator finIter = fin.collection()->begin(), finEndIter = fin.collection()->end();
+           finIter != finEndIter; ++finIter) {
+
+      Node& childNode = *finIter;
+
+      if (!childNode.isCollection()) {
+        Node wrapper = Node::createCollection();
+        wrapper.collection()->push_back(childNode);
+        childNode = wrapper;
+      }
+
+    }
+
+    DEBUG_PRINTLN(SUBWEAVE, "FIN MAPPED: " << fin)
+
+
+
+    Node groupSeq1 = groupSelectors(seq1, ctx);
+    DEBUG_PRINTLN(SUBWEAVE, "SEQ1: " << groupSeq1)
+
+    Node groupSeq2 = groupSelectors(seq2, ctx);
+    DEBUG_PRINTLN(SUBWEAVE, "SEQ2: " << groupSeq2)
+
+
+    ComplexSelectorDeque groupSeq1Converted;
+    nodeToComplexSelectorDeque(groupSeq1, groupSeq1Converted, ctx);
+
+    ComplexSelectorDeque groupSeq2Converted;
+    nodeToComplexSelectorDeque(groupSeq2, groupSeq2Converted, ctx);
+
+    ComplexSelectorDeque out;
+    LcsCollectionComparator collectionComparator(ctx);
+    lcs(groupSeq2Converted, groupSeq1Converted, collectionComparator, ctx, out);
+    Node seqLcs = complexSelectorDequeToNode(out, ctx);
+
+    DEBUG_PRINTLN(SUBWEAVE, "SEQLCS: " << seqLcs)
+
+
+    Node initWrapper = Node::createCollection();
+    initWrapper.collection()->push_back(init);
+    Node diff = Node::createCollection();
+    diff.collection()->push_back(initWrapper);
+
+    DEBUG_PRINTLN(SUBWEAVE, "DIFF INIT: " << diff)
+
+
+    while (!seqLcs.collection()->empty()) {
+      ParentSuperselectorChunker superselectorChunker(seqLcs, ctx);
+      Node chunksResult = chunks(groupSeq1, groupSeq2, superselectorChunker);
+      diff.collection()->push_back(chunksResult);
+
+      Node lcsWrapper = Node::createCollection();
+      lcsWrapper.collection()->push_back(seqLcs.collection()->front());
+      seqLcs.collection()->pop_front();
+      diff.collection()->push_back(lcsWrapper);
+
+      if (groupSeq1.collection()->size()) groupSeq1.collection()->pop_front();
+      if (groupSeq2.collection()->size()) groupSeq2.collection()->pop_front();
+    }
+
+    DEBUG_PRINTLN(SUBWEAVE, "DIFF POST LCS: " << diff)
+
+
+    DEBUG_PRINTLN(SUBWEAVE, "CHUNKS: ONE=" << groupSeq1 << " TWO=" << groupSeq2)
+
+
+    SubweaveEmptyChunker emptyChunker;
+    Node chunksResult = chunks(groupSeq1, groupSeq2, emptyChunker);
+    diff.collection()->push_back(chunksResult);
+
+
+    DEBUG_PRINTLN(SUBWEAVE, "DIFF POST CHUNKS: " << diff)
+
+
+    diff.collection()->insert(diff.collection()->end(), fin.collection()->begin(), fin.collection()->end());
+
+    DEBUG_PRINTLN(SUBWEAVE, "DIFF POST FIN MAPPED: " << diff)
+
+    // JMA - filter out the empty nodes (use a new collection, since iterator erase() invalidates the old collection)
+    Node diffFiltered = Node::createCollection();
+    for (NodeDeque::iterator diffIter = diff.collection()->begin(), diffEndIter = diff.collection()->end();
+           diffIter != diffEndIter; ++diffIter) {
+      Node& node = *diffIter;
+      if (node.collection() && !node.collection()->empty()) {
+        diffFiltered.collection()->push_back(node);
+      }
+    }
+    diff = diffFiltered;
+
+    DEBUG_PRINTLN(SUBWEAVE, "DIFF POST REJECT: " << diff)
+
+
+    Node pathsResult = paths(diff, ctx);
+
+    DEBUG_PRINTLN(SUBWEAVE, "PATHS: " << pathsResult)
+
+
+    // We're flattening in place
+    for (NodeDeque::iterator pathsIter = pathsResult.collection()->begin(), pathsEndIter = pathsResult.collection()->end();
+      pathsIter != pathsEndIter; ++pathsIter) {
+
+      Node& child = *pathsIter;
+      child = flatten(child, ctx);
+    }
+
+    DEBUG_PRINTLN(SUBWEAVE, "FLATTENED: " << pathsResult)
+
+
+    /*
+      TODO: implement
+      rejected = mapped.reject {|p| path_has_two_subjects?(p)}
+      $stderr.puts "REJECTED: #{rejected}"
+     */
+
+
+    return pathsResult;
+
+  }
+  /*
+  // disabled to avoid clang warning [-Wunused-function]
+  static Node subweaveNaive(const Node& one, const Node& two, Context& ctx) {
+    Node out = Node::createCollection();
+
+    // Check for the simple cases
+    if (one.isNil()) {
+      out.collection()->push_back(two.clone(ctx));
+    } else if (two.isNil()) {
+      out.collection()->push_back(one.clone(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);
+      firstPerm.plus(twoCloned);
+      out.collection()->push_back(firstPerm);
+
+      Node secondPerm = two.clone(ctx);
+      Node oneCloned = one.clone(ctx);
+      secondPerm.plus(oneCloned );
+      out.collection()->push_back(secondPerm);
+    }
+
+    return out;
+  }
+  */
+
+
+  /*
+   This is the equivalent of ruby's Sequence.weave.
+
+   The following is the modified version of the ruby code that was more portable to C++. You
+   should be able to drop it into ruby 3.2.19 and get the same results from ruby sass.
+
+      def weave(path)
+        # This function works by moving through the selector path left-to-right,
+        # building all possible prefixes simultaneously. These prefixes are
+        # `befores`, while the remaining parenthesized suffixes is `afters`.
+        befores = [[]]
+        afters = path.dup
+
+        until afters.empty?
+          current = afters.shift.dup
+          last_current = [current.pop]
+
+          tempResult = []
+
+          for before in befores do
+            sub = subweave(before, current)
+            if sub.nil?
+              next
+            end
+
+            for seqs in sub do
+              tempResult.push(seqs + last_current)
+            end
+          end
+
+          befores = tempResult
+
+        end
+
+        return befores
+      end
+   */
+  /*
+      def weave(path)
+        befores = [[]]
+        afters = path.dup
+
+        until afters.empty?
+          current = afters.shift.dup
+
+          last_current = [current.pop]
+
+
+          tempResult = []
+
+          for before in befores do
+            sub = subweave(before, current)
+
+            if sub.nil?
+              next []
+            end
+
+
+            for seqs in sub do
+              toPush = seqs + last_current
+
+              tempResult.push(seqs + last_current)
+            end
+
+          end
+
+          befores = tempResult
+
+        end
+
+        return befores
+      end
+  */
+  static Node weave(Node& path, Context& ctx) {
+
+    DEBUG_PRINTLN(WEAVE, "WEAVE: " << path)
+
+    Node befores = Node::createCollection();
+    befores.collection()->push_back(Node::createCollection());
+
+    Node afters = Node::createCollection();
+    afters.plus(path);
+
+    while (!afters.collection()->empty()) {
+      Node current = afters.collection()->front().clone(ctx);
+      afters.collection()->pop_front();
+      DEBUG_PRINTLN(WEAVE, "CURRENT: " << current)
+
+      Node last_current = Node::createCollection();
+      last_current.collection()->push_back(current.collection()->back());
+      current.collection()->pop_back();
+      DEBUG_PRINTLN(WEAVE, "CURRENT POST POP: " << current)
+      DEBUG_PRINTLN(WEAVE, "LAST CURRENT: " << last_current)
+
+      Node tempResult = Node::createCollection();
+
+      for (NodeDeque::iterator beforesIter = befores.collection()->begin(), beforesEndIter = befores.collection()->end(); beforesIter != beforesEndIter; beforesIter++) {
+        Node& before = *beforesIter;
+
+        Node sub = Extend::subweave(before, current, ctx);
+
+        DEBUG_PRINTLN(WEAVE, "SUB: " << sub)
+
+        if (sub.isNil()) {
+          return Node::createCollection();
+        }
+
+        for (NodeDeque::iterator subIter = sub.collection()->begin(), subEndIter = sub.collection()->end(); subIter != subEndIter; subIter++) {
+          Node& seqs = *subIter;
+
+          Node toPush = Node::createCollection();
+          toPush.plus(seqs);
+          toPush.plus(last_current);
+
+          tempResult.collection()->push_back(toPush);
+
+        }
+      }
+
+      befores = tempResult;
+
+    }
+
+    return befores;
+  }
+
+
+
+  // This forward declaration is needed since extendComplexSelector calls extendCompoundSelector, which may recursively
+  // call extendComplexSelector again.
+  static Node extendComplexSelector(
+    Complex_Selector* pComplexSelector,
+    Context& ctx,
+    ExtensionSubsetMap& subset_map,
+    std::set<Compound_Selector> seen, bool isReplace, bool isOriginal);
+
+
+
+  /*
+   This is the equivalent of ruby's SimpleSequence.do_extend.
+
+    // TODO: I think I have some modified ruby code to put here. Check.
+  */
+  /*
+   ISSUES:
+   - Previous TODO: Do we need to group the results by extender?
+   - What does subject do in?: next unless unified = seq.members.last.unify(self_without_sel, subject?)
+   - IMPROVEMENT: The search for uniqueness at the end is not ideal since it's has to loop over everything...
+   - IMPROVEMENT: Check if the final search for uniqueness is doing anything that extendComplexSelector isn't already doing...
+   */
+  template<typename KeyType>
+  class GroupByToAFunctor {
+  public:
+    KeyType operator()(ExtensionPair& extPair) const {
+      Complex_Selector* pSelector = extPair.first;
+      return *pSelector;
+    }
+  };
+  static Node extendCompoundSelector(
+    Compound_Selector* pSelector,
+    Context& ctx,
+    ExtensionSubsetMap& subset_map,
+    std::set<Compound_Selector> seen, bool isReplace) {
+
+    DEBUG_EXEC(EXTEND_COMPOUND, printCompoundSelector(pSelector, "EXTEND COMPOUND: "))
+    // TODO: Ruby has another loop here to skip certain members?
+
+    Node extendedSelectors = Node::createCollection();
+    // extendedSelectors.got_line_feed = true;
+
+    To_String to_string;
+
+    SubsetMapEntries entries = subset_map.get_v(pSelector->to_str_vec());
+
+    typedef std::vector<std::pair<Complex_Selector, std::vector<ExtensionPair> > > GroupedByToAResult;
+
+    GroupByToAFunctor<Complex_Selector> extPairKeyFunctor;
+    GroupedByToAResult arr;
+    group_by_to_a(entries, extPairKeyFunctor, arr);
+
+    typedef std::pair<Compound_Selector*, Complex_Selector*> SelsNewSeqPair;
+    typedef std::vector<SelsNewSeqPair> SelsNewSeqPairCollection;
+
+
+    SelsNewSeqPairCollection holder;
+
+
+    for (GroupedByToAResult::iterator groupedIter = arr.begin(), groupedIterEnd = arr.end(); groupedIter != groupedIterEnd; groupedIter++) {
+      std::pair<Complex_Selector, std::vector<ExtensionPair> >& groupedPair = *groupedIter;
+
+      Complex_Selector& 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());
+      for (std::vector<ExtensionPair>::iterator groupIter = group.begin(), groupIterEnd = group.end(); groupIter != groupIterEnd; groupIter++) {
+        ExtensionPair& pair = *groupIter;
+        Compound_Selector* pCompound = pair.second;
+        for (size_t index = 0; index < pCompound->length(); index++) {
+          Simple_Selector* pSimpleSelector = (*pCompound)[index];
+          (*pSels) << pSimpleSelector;
+        }
+      }
+
+      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
+
+      // 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);
+
+      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;
+
+      if (!pInnermostCompoundSelector) {
+        pInnermostCompoundSelector = SASS_MEMORY_NEW(ctx.mem, Compound_Selector, pSelector->pstate());
+      }
+
+      pUnifiedSelector = pInnermostCompoundSelector->unify_with(pSelectorWithoutExtendSelectors, ctx);
+
+
+      DEBUG_EXEC(EXTEND_COMPOUND, printCompoundSelector(pInnermostCompoundSelector, "LHS: "))
+      DEBUG_EXEC(EXTEND_COMPOUND, printCompoundSelector(pSelectorWithoutExtendSelectors, "RHS: "))
+      DEBUG_EXEC(EXTEND_COMPOUND, printCompoundSelector(pUnifiedSelector, "UNIFIED: "))
+
+      // RUBY: next unless unified
+      if (!pUnifiedSelector || pUnifiedSelector->length() == 0) {
+        continue;
+      }
+
+      // TODO: implement the parent directive match (if necessary based on test failures)
+      // next if group.map {|e, _| check_directives_match!(e, parent_directives)}.none?
+
+      // TODO: This seems a little fishy to me. See if it causes any problems. From the ruby, we should be able to just
+      // 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* pNewInnerMost = SASS_MEMORY_NEW(ctx.mem, Complex_Selector, pSelector->pstate(), Complex_Selector::ANCESTOR_OF, pUnifiedSelector, NULL);
+
+      Complex_Selector::Combinator combinator = pNewSelector->clear_innermost();
+      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.";
+      }
+      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.";
+      }
+#endif
+
+
+      // if (pSelector && pSelector->has_line_feed()) pNewInnerMost->has_line_feed(true);
+      // Set the sources on our new Complex_Selector to the sources of this simple sequence plus the thing we're extending.
+      DEBUG_PRINTLN(EXTEND_COMPOUND, "SOURCES SETTING ON NEW SEQ: " << complexSelectorToNode(pNewSelector, ctx))
+
+      DEBUG_EXEC(EXTEND_COMPOUND, SourcesSet oldSet = pNewSelector->sources(); printSourcesSet(oldSet, ctx, "SOURCES NEW SEQ BEGIN: "))
+
+      SourcesSet newSourcesSet = pSelector->sources();
+      DEBUG_EXEC(EXTEND_COMPOUND, printSourcesSet(newSourcesSet, ctx, "SOURCES THIS EXTEND: "))
+
+      newSourcesSet.insert(pExtComplexSelector);
+      DEBUG_EXEC(EXTEND_COMPOUND, printSourcesSet(newSourcesSet, ctx, "SOURCES WITH NEW SOURCE: "))
+
+      // RUBY: new_seq.add_sources!(sources + [seq])
+      pNewSelector->addSources(newSourcesSet, ctx);
+
+      DEBUG_EXEC(EXTEND_COMPOUND, SourcesSet newSet = pNewSelector->sources(); printSourcesSet(newSet, ctx, "SOURCES ON NEW SELECTOR AFTER ADD: "))
+      DEBUG_EXEC(EXTEND_COMPOUND, printSourcesSet(pSelector->sources(), ctx, "SOURCES THIS EXTEND WHICH SHOULD BE SAME STILL: "))
+
+
+      if (pSels->has_line_feed()) pNewSelector->has_line_feed(true);;
+
+      holder.push_back(std::make_pair(pSels, pNewSelector));
+    }
+
+
+    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;
+
+
+      // RUBY??: next [] if seen.include?(sels)
+      if (seen.find(*pSels) != seen.end()) {
+        continue;
+      }
+
+
+      std::set<Compound_Selector> recurseSeen(seen);
+      recurseSeen.insert(*pSels);
+
+
+      DEBUG_PRINTLN(EXTEND_COMPOUND, "RECURSING DO EXTEND: " << complexSelectorToNode(pNewSelector, ctx))
+      Node recurseExtendedSelectors = extendComplexSelector(pNewSelector, ctx, subset_map, recurseSeen, isReplace, false); // !:isOriginal
+
+      DEBUG_PRINTLN(EXTEND_COMPOUND, "RECURSING DO EXTEND RETURN: " << recurseExtendedSelectors)
+
+      for (NodeDeque::iterator iterator = recurseExtendedSelectors.collection()->begin(), endIterator = recurseExtendedSelectors.collection()->end();
+           iterator != endIterator; ++iterator) {
+        Node& newSelector = *iterator;
+
+//        DEBUG_PRINTLN(EXTEND_COMPOUND, "EXTENDED AT THIS POINT: " << extendedSelectors)
+//        DEBUG_PRINTLN(EXTEND_COMPOUND, "SELECTOR EXISTS ALREADY: " << newSelector << " " << extendedSelectors.contains(newSelector, false /*simpleSelectorOrderDependent*/));
+
+        if (!extendedSelectors.contains(newSelector, false /*simpleSelectorOrderDependent*/)) {
+//          DEBUG_PRINTLN(EXTEND_COMPOUND, "ADDING NEW SELECTOR")
+          extendedSelectors.collection()->push_back(newSelector);
+        }
+      }
+    }
+
+    DEBUG_EXEC(EXTEND_COMPOUND, printCompoundSelector(pSelector, "EXTEND COMPOUND END: "))
+
+    return extendedSelectors;
+  }
+
+
+  static bool complexSelectorHasExtension(
+    Complex_Selector* pComplexSelector,
+    Context& ctx,
+    ExtensionSubsetMap& subset_map) {
+
+    bool hasExtension = false;
+
+    Complex_Selector* pIter = pComplexSelector;
+
+    while (!hasExtension && pIter) {
+      Compound_Selector* pHead = pIter->head();
+
+      if (pHead) {
+        SubsetMapEntries entries = subset_map.get_v(pHead->to_str_vec());
+        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.second->media_block() == 0) continue;
+          if (pComplexSelector->media_block() &&
+              ext.second->media_block()->media_queries() &&
+              pComplexSelector->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));
+            if (query_left == query_right) continue;
+          }
+
+          // fail if one goes across media block boundaries
+          std::stringstream err;
+          std::string cwd(Sass::File::get_cwd());
+          ParserState pstate(ext.second->pstate());
+          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 << " on line " << pstate.line+1 << " of " << rel_path << "\n";
+          error(err.str(), pComplexSelector->pstate());
+        }
+        if (entries.size() > 0) hasExtension = true;
+      }
+
+      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;
+  }
+
+
+  /*
+   This is the equivalent of ruby's Sequence.do_extend.
+
+   // TODO: I think I have some modified ruby code to put here. Check.
+   */
+  /*
+   ISSUES:
+   - check to automatically include combinators doesn't transfer over to libsass' data model where
+     the combinator and compound selector are one unit
+     next [[sseq_or_op]] unless sseq_or_op.is_a?(SimpleSequence)
+   */
+  static Node extendComplexSelector(
+    Complex_Selector* pComplexSelector,
+    Context& ctx,
+    ExtensionSubsetMap& subset_map,
+    std::set<Compound_Selector> seen, bool isReplace, bool isOriginal) {
+
+    Node complexSelector = complexSelectorToNode(pComplexSelector, ctx);
+    DEBUG_PRINTLN(EXTEND_COMPLEX, "EXTEND COMPLEX: " << complexSelector)
+
+    Node extendedNotExpanded = Node::createCollection();
+
+    for (NodeDeque::iterator complexSelIter = complexSelector.collection()->begin(),
+                             complexSelIterEnd = complexSelector.collection()->end();
+         complexSelIter != complexSelIterEnd; ++complexSelIter)
+    {
+
+      Node& sseqOrOp = *complexSelIter;
+
+      DEBUG_PRINTLN(EXTEND_COMPLEX, "LOOP: " << sseqOrOp)
+
+      // If it's not a selector (meaning it's a combinator), just include it automatically
+      // RUBY: next [[sseq_or_op]] unless sseq_or_op.is_a?(SimpleSequence)
+      if (!sseqOrOp.isSelector()) {
+        // Wrap our Combinator in two collections to match ruby. This is essentially making a collection Node
+        // with one collection child. The collection child represents a Complex_Selector that is only a combinator.
+        Node outer = Node::createCollection();
+        Node inner = Node::createCollection();
+        outer.collection()->push_back(inner);
+        inner.collection()->push_back(sseqOrOp);
+        extendedNotExpanded.collection()->push_back(outer);
+        continue;
+      }
+
+      Compound_Selector* 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);
+      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();
+
+      // RUBY: extended.first.add_sources!([self]) if original && !has_placeholder?
+      if (isOriginal && !pComplexSelector->has_placeholder()) {
+        SourcesSet srcset;
+        srcset.insert(pComplexSelector);
+        pJustCurrentCompoundSelector->addSources(srcset, ctx);
+        DEBUG_PRINTLN(EXTEND_COMPLEX, "ADD SOURCES: " << *pComplexSelector)
+      }
+
+      bool isSuperselector = false;
+      for (NodeDeque::iterator iterator = extended.collection()->begin(), endIterator = extended.collection()->end();
+           iterator != endIterator; ++iterator) {
+        Node& childNode = *iterator;
+        Complex_Selector* pExtensionSelector = nodeToComplexSelector(childNode, ctx);
+        if (pExtensionSelector->is_superselector_of(pJustCurrentCompoundSelector)) {
+          isSuperselector = true;
+          break;
+        }
+      }
+
+      if (!isSuperselector) {
+        if (sseqOrOp.got_line_feed) pJustCurrentCompoundSelector->has_line_feed(sseqOrOp.got_line_feed);
+        extended.collection()->push_front(complexSelectorToNode(pJustCurrentCompoundSelector, ctx));
+      }
+
+      DEBUG_PRINTLN(EXTEND_COMPLEX, "CHOICES UNSHIFTED: " << extended)
+
+      // Aggregate our current extensions
+      extendedNotExpanded.collection()->push_back(extended);
+    }
+
+
+    DEBUG_PRINTLN(EXTEND_COMPLEX, "EXTENDED NOT EXPANDED: " << extendedNotExpanded)
+
+
+
+    // Ruby Equivalent: paths
+    Node paths = Sass::paths(extendedNotExpanded, ctx);
+
+    DEBUG_PRINTLN(EXTEND_COMPLEX, "PATHS: " << paths)
+
+
+
+    // Ruby Equivalent: weave
+    Node weaves = Node::createCollection();
+
+    for (NodeDeque::iterator pathsIter = paths.collection()->begin(), pathsEndIter = paths.collection()->end(); pathsIter != pathsEndIter; ++pathsIter) {
+      Node& path = *pathsIter;
+      Node weaved = weave(path, ctx);
+      weaved.got_line_feed = path.got_line_feed;
+      weaves.collection()->push_back(weaved);
+    }
+
+    DEBUG_PRINTLN(EXTEND_COMPLEX, "WEAVES: " << weaves)
+
+
+
+    // Ruby Equivalent: trim
+    Node trimmed = trim(weaves, ctx, isReplace);
+
+    DEBUG_PRINTLN(EXTEND_COMPLEX, "TRIMMED: " << trimmed)
+
+
+    // Ruby Equivalent: flatten
+    Node extendedSelectors = flatten(trimmed, ctx, 1);
+
+    DEBUG_PRINTLN(EXTEND_COMPLEX, ">>>>> EXTENDED: " << extendedSelectors)
+
+
+    DEBUG_PRINTLN(EXTEND_COMPLEX, "EXTEND COMPLEX END: " << complexSelector)
+
+
+    return extendedSelectors;
+  }
+
+
+
+  /*
+   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) {
+
+    To_String to_string(&ctx);
+
+    Selector_List* pNewSelectors = SASS_MEMORY_NEW(ctx.mem, Selector_List, pSelectorList->pstate(), pSelectorList->length());
+
+    extendedSomething = false;
+
+    for (size_t index = 0, length = pSelectorList->length(); index < length; index++) {
+      Complex_Selector* 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;
+        continue;
+      }
+
+      extendedSomething = true;
+
+      std::set<Compound_Selector> seen;
+
+      Node extendedSelectors = extendComplexSelector(pSelector, ctx, subset_map, seen, isReplace, true);
+      if (!pSelector->has_placeholder()) {
+        if (!extendedSelectors.contains(complexSelectorToNode(pSelector, ctx), true /*simpleSelectorOrderDependent*/)) {
+          *pNewSelectors << pSelector;
+        }
+      }
+
+      for (NodeDeque::iterator iterator = extendedSelectors.collection()->begin(), iteratorBegin = extendedSelectors.collection()->begin(), iteratorEnd = extendedSelectors.collection()->end(); iterator != iteratorEnd; ++iterator) {
+        // When it is a replace, skip the first one, unless there is only one
+        if(isReplace && iterator == iteratorBegin && extendedSelectors.collection()->size() > 1 ) continue;
+
+        Node& childNode = *iterator;
+        *pNewSelectors << nodeToComplexSelector(childNode, ctx);
+      }
+    }
+
+    return pNewSelectors;
+
+  }
+
+
+  bool shouldExtendBlock(Block* 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:
+    //
+    //    .a {
+    //      .b {
+    //        x: y;
+    //      }
+    //    }
+    //
+    // We end up visiting two rulesets (one with the selector .a and the other with the selector .a .b).
+    // In this case, we don't want to try to pull rules onto .a since they won't get output anyway since
+    // 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];
+
+      if (typeid(*stm) == typeid(Ruleset)) {
+        // Do nothing. This doesn't count as a statement that causes extension since we'll iterate over this rule set in a future visit and try to extend it.
+      }
+      else {
+        return true;
+      }
+    }
+
+    return false;
+
+  }
+
+
+  // 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);
+
+    DEBUG_PRINTLN(EXTEND_OBJECT, "FOUND SELECTOR: " << static_cast<Selector_List*>(pObject->selector())->perform(&to_string))
+
+    // Ruby sass seems to filter nodes that don't have any content well before we get here. I'm not sure the repercussions
+    // of doing so, so for now, let's just not extend things that won't be output later.
+    if (!shouldExtendBlock(pObject->block())) {
+      DEBUG_PRINTLN(EXTEND_OBJECT, "RETURNING WITHOUT EXTEND ATTEMPT")
+      return;
+    }
+
+    bool extendedSomething = false;
+    Selector_List* pNewSelectorList = Extend::extendSelectorList(static_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))
+      pNewSelectorList->remove_parent_selectors();
+      pObject->selector(pNewSelectorList);
+    } else {
+      DEBUG_PRINTLN(EXTEND_OBJECT, "EXTEND DID NOT TRY TO EXTEND ANYTHING")
+    }
+  }
+
+
+
+  Extend::Extend(Context& ctx, ExtensionSubsetMap& ssm)
+  : ctx(ctx), subset_map(ssm)
+  { }
+
+  void Extend::operator()(Block* b)
+  {
+    for (size_t i = 0, L = b->length(); i < L; ++i) {
+      (*b)[i]->perform(this);
+    }
+  }
+
+  void Extend::operator()(Ruleset* pRuleset)
+  {
+    extendObjectWithSelectorAndBlock(pRuleset, ctx, subset_map);
+    pRuleset->block()->perform(this);
+  }
+
+  void Extend::operator()(Supports_Block* pFeatureBlock)
+  {
+    pFeatureBlock->block()->perform(this);
+  }
+
+  void Extend::operator()(Media_Block* pMediaBlock)
+  {
+    pMediaBlock->block()->perform(this);
+  }
+
+  void Extend::operator()(At_Rule* a)
+  {
+    // Selector_List* ls = dynamic_cast<Selector_List*>(a->selector());
+    // selector_stack.push_back(ls);
+    if (a->block()) a->block()->perform(this);
+    // exp.selector_stack.pop_back();
+  }
+}
diff --git a/libsass/src/extend.hpp b/libsass/src/extend.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/extend.hpp
@@ -0,0 +1,44 @@
+#ifndef SASS_EXTEND_H
+#define SASS_EXTEND_H
+
+#include <string>
+
+#include "ast.hpp"
+#include "operation.hpp"
+#include "subset_map.hpp"
+
+namespace Sass {
+
+  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;
+
+    void fallback_impl(AST_Node* 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();
+
+    void operator()(Block*);
+    void operator()(Ruleset*);
+    void operator()(Supports_Block*);
+    void operator()(Media_Block*);
+    void operator()(At_Rule*);
+
+    template <typename U>
+    void fallback(U x) { return fallback_impl(x); }
+  };
+
+}
+
+#endif
diff --git a/libsass/src/file.cpp b/libsass/src/file.cpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/file.cpp
@@ -0,0 +1,407 @@
+#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)
+#else
+#include <unistd.h>
+#endif
+#ifdef _MSC_VER
+#define NOMINMAX
+#endif
+
+#include <iostream>
+#include <fstream>
+#include <cctype>
+#include <vector>
+#include <algorithm>
+#include <sys/stat.h>
+#include "file.hpp"
+#include "context.hpp"
+#include "prelexer.hpp"
+#include "utf8_string.hpp"
+#include "sass2scss.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
+#ifndef FS_CASE_SENSITIVE
+#ifdef _WIN32
+#define FS_CASE_SENSITIVE 0
+#else
+#define FS_CASE_SENSITIVE 1
+#endif
+#endif
+
+namespace Sass {
+  namespace File {
+
+    // return the current directory
+    // always with forward slashes
+    std::string get_cwd()
+    {
+      const size_t wd_len = 1024;
+      char wd[wd_len];
+      std::string cwd = getcwd(wd, wd_len);
+      #ifdef _WIN32
+        //convert backslashes to forward slashes
+        replace(cwd.begin(), cwd.end(), '\\', '/');
+      #endif
+      if (cwd[cwd.length() - 1] != '/') cwd += '/';
+      return cwd;
+    }
+
+    // test if path exists and is a file
+    bool file_exists(const std::string& path)
+    {
+      #ifdef _WIN32
+        std::wstring wpath = UTF_8::convert_to_utf16(path);
+        DWORD dwAttrib = GetFileAttributesW(wpath.c_str());
+        return (dwAttrib != INVALID_FILE_ATTRIBUTES &&
+               (!(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)));
+      #else
+        struct stat st_buf;
+        return (stat (path.c_str(), &st_buf) == 0) &&
+               (!S_ISDIR (st_buf.st_mode));
+      #endif
+    }
+
+    // return if given path is absolute
+    // works with *nix and windows paths
+    bool is_absolute_path(const std::string& path)
+    {
+      #ifdef _WIN32
+        if (path.length() >= 2 && isalpha(path[0]) && path[1] == ':') return true;
+      #endif
+      size_t i = 0;
+      // check if we have a protocol
+      if (path[i] && Prelexer::is_alpha(path[i])) {
+        // skip over all alphanumeric characters
+        while (path[i] && Prelexer::is_alnum(path[i])) ++i;
+        i = i && path[i] == ':' ? i + 1 : 0;
+      }
+      return path[i] == '/';
+    }
+
+    // helper function to find the last directory seperator
+    inline size_t find_last_folder_separator(const std::string& path, size_t limit = std::string::npos)
+    {
+      size_t pos = std::string::npos;
+      size_t pos_p = path.find_last_of('/', limit);
+      #ifdef _WIN32
+        size_t pos_w = path.find_last_of('\\', limit);
+      #else
+        size_t pos_w = std::string::npos;
+      #endif
+      if (pos_p != std::string::npos && pos_w != std::string::npos) {
+        pos = std::max(pos_p, pos_w);
+      }
+      else if (pos_p != std::string::npos) {
+        pos = pos_p;
+      }
+      else {
+        pos = pos_w;
+      }
+      return pos;
+    }
+
+    // return only the directory part of path
+    std::string dir_name(const std::string& path)
+    {
+      size_t pos = find_last_folder_separator(path);
+      if (pos == std::string::npos) return "";
+      else return path.substr(0, pos+1);
+    }
+
+    // return only the filename part of path
+    std::string base_name(const std::string& path)
+    {
+      size_t pos = find_last_folder_separator(path);
+      if (pos == std::string::npos) return path;
+      else return path.substr(pos+1);
+    }
+
+    // do a logical clean up of the path
+    // no physical check on the filesystem
+    std::string make_canonical_path (std::string path)
+    {
+
+      // declarations
+      size_t pos;
+
+      #ifdef _WIN32
+        //convert backslashes to forward slashes
+        replace(path.begin(), path.end(), '\\', '/');
+      #endif
+
+      pos = 0; // remove all self references inside the path string
+      while((pos = path.find("/./", pos)) != std::string::npos) path.erase(pos, 2);
+
+      pos = 0; // remove all leading and trailing self references
+      while(path.length() > 1 && path.substr(0, 2) == "./") path.erase(0, 2);
+      while((pos = path.length()) > 1 && path.substr(pos - 2) == "/.") path.erase(pos - 2);
+
+
+      size_t proto = 0;
+      // check if we have a protocol
+      if (path[proto] && Prelexer::is_alpha(path[proto])) {
+        // skip over all alphanumeric characters
+        while (path[proto] && Prelexer::is_alnum(path[proto++])) {}
+        // then skip over the mandatory colon
+        if (proto && path[proto] == ':') ++ proto;
+      }
+
+      // then skip over start slashes
+      while (path[proto++] == '/') {}
+
+      pos = proto; // collapse multiple delimiters into a single one
+      while((pos = path.find("//", pos)) != std::string::npos) path.erase(pos, 1);
+
+      return path;
+
+    }
+
+    // join two path segments cleanly together
+    // but only if right side is not absolute yet
+    std::string join_paths(std::string l, std::string r)
+    {
+
+      #ifdef _WIN32
+        // convert Windows backslashes to URL forward slashes
+        replace(l.begin(), l.end(), '\\', '/');
+        replace(r.begin(), r.end(), '\\', '/');
+      #endif
+
+      if (l.empty()) return r;
+      if (r.empty()) return l;
+
+      if (is_absolute_path(r)) return r;
+      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);
+        l = l.substr(0, pos == std::string::npos ? pos : pos + 1);
+      }
+
+      return l + r;
+    }
+
+    std::string path_for_console(const std::string& rel_path, const std::string& abs_path, const std::string& orig_path)
+    {
+      // magic algorith goes here!!
+
+      // if the file is outside this directory show the absolute path
+      if (rel_path.substr(0, 3) == "../") {
+        return orig_path;
+      }
+      // this seems to work most of the time
+      return abs_path == orig_path ? abs_path : rel_path;
+    }
+
+    // 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));
+    }
+
+    // create a path that is relative to the given base directory
+    // path and base will first be resolved against cwd to make them absolute
+    std::string abs2rel(const std::string& path, const std::string& base, const std::string& cwd)
+    {
+
+      std::string abs_path = rel2abs(path, cwd);
+      std::string abs_base = rel2abs(base, cwd);
+
+      size_t proto = 0;
+      // check if we have a protocol
+      if (path[proto] && Prelexer::is_alpha(path[proto])) {
+        // skip over all alphanumeric characters
+        while (path[proto] && Prelexer::is_alnum(path[proto++])) {}
+        // then skip over the mandatory colon
+        if (proto && path[proto] == ':') ++ proto;
+      }
+
+      // distinguish between windows absolute paths and valid protocols
+      // we assume that protocols must at least have two chars to be valid
+      if (proto && path[proto++] == '/' && proto > 3) return path;
+
+      #ifdef _WIN32
+        // absolute link must have a drive letter, and we know that we
+        // can only create relative links if both are on the same drive
+        if (abs_base[0] != abs_path[0]) return abs_path;
+      #endif
+
+      std::string stripped_uri = "";
+      std::string stripped_base = "";
+
+      size_t index = 0;
+      size_t minSize = std::min(abs_path.size(), abs_base.size());
+      for (size_t i = 0; i < minSize; ++i) {
+        #ifdef FS_CASE_SENSITIVE
+          if (abs_path[i] != abs_base[i]) break;
+        #else
+          // compare the charactes in a case insensitive manner
+          // windows fs is only case insensitive in ascii ranges
+          if (tolower(abs_path[i]) != tolower(abs_base[i])) break;
+        #endif
+        if (abs_path[i] == '/') index = i + 1;
+      }
+      for (size_t i = index; i < abs_path.size(); ++i) {
+        stripped_uri += abs_path[i];
+      }
+      for (size_t i = index; i < abs_base.size(); ++i) {
+        stripped_base += abs_base[i];
+      }
+
+      size_t left = 0;
+      size_t directories = 0;
+      for (size_t right = 0; right < stripped_base.size(); ++right) {
+        if (stripped_base[right] == '/') {
+          if (stripped_base.substr(left, 2) != "..") {
+            ++directories;
+          }
+          else if (directories > 1) {
+            --directories;
+          }
+          else {
+            directories = 0;
+          }
+          left = right + 1;
+        }
+      }
+
+      std::string result = "";
+      for (size_t i = 0; i < directories; ++i) {
+        result += "../";
+      }
+      result += stripped_uri;
+
+      return result;
+    }
+
+    // Resolution order for ambiguous imports:
+    // (1) filename as given
+    // (2) underscore + given
+    // (3) underscore + given + extension
+    // (4) given + extension
+    std::vector<Include> resolve_includes(const std::string& root, const std::string& file)
+    {
+      std::string filename = join_paths(root, file);
+      // supported extensions
+      const std::vector<std::string> exts = {
+        ".scss", ".sass", ".css"
+      };
+      // split the filename
+      std::string base(dir_name(file));
+      std::string name(base_name(file));
+      std::vector<Include> includes;
+      // create full path (maybe relative)
+      std::string rel_path(join_paths(base, name));
+      std::string abs_path(join_paths(root, rel_path));
+      if (file_exists(abs_path)) includes.push_back({{ rel_path, root }, abs_path });
+      // next test variation with underscore
+      rel_path = join_paths(base, "_" + name);
+      abs_path = join_paths(root, rel_path);
+      if (file_exists(abs_path)) includes.push_back({{ rel_path, root }, abs_path });
+      // next test exts plus underscore
+      for(auto ext : exts) {
+        rel_path = join_paths(base, "_" + name + ext);
+        abs_path = join_paths(root, rel_path);
+        if (file_exists(abs_path)) includes.push_back({{ rel_path, root }, abs_path });
+      }
+      // next test plain name with exts
+      for(auto ext : exts) {
+        rel_path = join_paths(base, name + ext);
+        abs_path = join_paths(root, rel_path);
+        if (file_exists(abs_path)) includes.push_back({{ rel_path, root }, abs_path });
+      }
+      // nothing found
+      return includes;
+    }
+
+    // helper function to resolve a filename
+    std::string find_file(const std::string& file, const std::vector<std::string> paths)
+    {
+      // search in every include path for a match
+      for (size_t i = 0, S = paths.size(); i < S; ++i)
+      {
+        std::vector<Include> resolved(resolve_includes(paths[i], file));
+        if (resolved.size()) return resolved[0].abs_path;
+      }
+      // nothing found
+      return std::string("");
+    }
+
+    // inc paths can be directly passed from C code
+    std::string find_file(const std::string& file, const char* paths[])
+    {
+      if (paths == 0) return std::string("");
+      std::vector<std::string> includes(0);
+      // includes.push_back(".");
+      const char** it = paths;
+      while (it && *it) {
+        includes.push_back(*it);
+        ++it;
+      }
+      return find_file(file, includes);
+    }
+
+    // try to load the given filename
+    // returned memory must be freed
+    // will auto convert .sass files
+    char* read_file(const std::string& path)
+    {
+      #ifdef _WIN32
+        BYTE* pBuffer;
+        DWORD dwBytes;
+        // windows unicode filepaths are encoded in utf16
+        std::wstring wpath = UTF_8::convert_to_utf16(path);
+        HANDLE hFile = CreateFileW(wpath.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
+        if (hFile == INVALID_HANDLE_VALUE) return 0;
+        DWORD dwFileLength = GetFileSize(hFile, NULL);
+        if (dwFileLength == INVALID_FILE_SIZE) return 0;
+        // allocate an extra byte for the null char
+        pBuffer = (BYTE*)malloc((dwFileLength+1)*sizeof(BYTE));
+        ReadFile(hFile, pBuffer, dwFileLength, &dwBytes, NULL);
+        pBuffer[dwFileLength] = '\0';
+        CloseHandle(hFile);
+        // just convert from unsigned char*
+        char* contents = (char*) pBuffer;
+      #else
+        struct stat st;
+        if (stat(path.c_str(), &st) == -1 || S_ISDIR(st.st_mode)) return 0;
+        std::ifstream file(path.c_str(), std::ios::in | std::ios::binary | std::ios::ate);
+        char* contents = 0;
+        if (file.is_open()) {
+          size_t size = file.tellg();
+          // allocate an extra byte for the null char
+          contents = (char*) malloc((size+1)*sizeof(char));
+          file.seekg(0, std::ios::beg);
+          file.read(contents, size);
+          contents[size] = '\0';
+          file.close();
+        }
+      #endif
+      std::string extension;
+      if (path.length() > 5) {
+        extension = path.substr(path.length() - 5, 5);
+      }
+      for(size_t i=0; i<extension.size();++i)
+        extension[i] = tolower(extension[i]);
+      if (extension == ".sass" && contents != 0) {
+        char * converted = sass2scss(contents, SASS2SCSS_PRETTIFY_1 | SASS2SCSS_KEEP_COMMENT);
+        free(contents); // free the indented contents
+        return converted; // should be freed by caller
+      } else {
+        return contents;
+      }
+    }
+
+  }
+}
diff --git a/libsass/src/file.hpp b/libsass/src/file.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/file.hpp
@@ -0,0 +1,123 @@
+#ifndef SASS_FILE_H
+#define SASS_FILE_H
+
+#include <string>
+#include <vector>
+
+namespace Sass {
+
+  class Block;
+  class Context;
+
+  namespace File {
+
+    // return the current directory
+    // always with forward slashes
+    std::string get_cwd();
+
+    // test if path exists and is a file
+    bool file_exists(const std::string& file);
+
+    // return if given path is absolute
+    // works with *nix and windows paths
+    bool is_absolute_path(const std::string& path);
+
+    // return only the directory part of path
+    std::string dir_name(const std::string& path);
+
+    // return only the filename part of path
+    std::string base_name(const std::string&);
+
+    // do a locigal clean up of the path
+    // no physical check on the filesystem
+    std::string make_canonical_path (std::string path);
+
+    // join two path segments cleanly together
+    // but only if right side is not absolute yet
+    std::string join_paths(std::string root, std::string name);
+
+    // if the relative path is outside of the cwd we want want to
+    // show the absolute path in console messages
+    std::string path_for_console(const std::string& rel_path, const std::string& abs_path, const std::string& orig_path);
+
+    // 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 = get_cwd());
+
+    // create a path that is relative to the given base directory
+    // path and base will first be resolved against cwd to make them absolute
+    std::string abs2rel(const std::string& path, const std::string& base = ".", const std::string& cwd = get_cwd());
+
+    // helper function to resolve a filename
+    std::string find_file(const std::string& file, const std::vector<std::string> paths);
+    // inc paths can be directly passed from C code
+    std::string find_file(const std::string& file, const char** paths);
+
+    // try to load the given filename
+    // returned memory must be freed
+    // will auto convert .sass files
+    char* read_file(const std::string& file);
+
+  }
+
+  // requested import
+  class Importer {
+    public:
+      // requested import path
+      std::string imp_path;
+      // parent context path
+      std::string ctx_path;
+      // base derived from context path
+      // this really just acts as a cache
+      std::string base_path;
+    public:
+      Importer(std::string imp_path, std::string ctx_path)
+      : imp_path(File::make_canonical_path(imp_path)),
+        ctx_path(File::make_canonical_path(ctx_path)),
+        base_path(File::dir_name(ctx_path))
+      { }
+  };
+
+  // a resolved include (final import)
+  class Include : public Importer {
+    public:
+      // resolved absolute path
+      std::string abs_path;
+    public:
+      Include(const Importer& imp, std::string abs_path)
+      : Importer(imp), abs_path(abs_path)
+      { }
+  };
+
+  // a loaded resource
+  class Resource {
+    public:
+      // the file contents
+      char* contents;
+      // conected sourcemap
+      char* srcmap;
+    public:
+      Resource(char* contents, char* srcmap)
+      : contents(contents), srcmap(srcmap)
+      { }
+  };
+
+  // parsed stylesheet from loaded resource
+  class StyleSheet : public Resource {
+    public:
+      // parsed root block
+      Block* root;
+    public:
+      StyleSheet(const Resource& res, Block* root)
+      : Resource(res), root(root)
+      { }
+  };
+
+  namespace File {
+
+    std::vector<Include> resolve_includes(const std::string& root, const std::string& file);
+
+  }
+
+}
+
+#endif
diff --git a/libsass/src/functions.cpp b/libsass/src/functions.cpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/functions.cpp
@@ -0,0 +1,1923 @@
+#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"
+#include "util.hpp"
+#include "expand.hpp"
+#include "utf8_string.hpp"
+#include "sass/base.h"
+#include "utf8.h"
+
+#include <cstdlib>
+#include <cmath>
+#include <cctype>
+#include <sstream>
+#include <string>
+#include <iomanip>
+#include <iostream>
+#include <random>
+#include <set>
+
+#ifdef __MINGW32__
+#include "windows.h"
+#include "wincrypt.h"
+#endif
+
+#define ARG(argname, argtype) get_arg<argtype>(argname, env, sig, pstate, backtrace)
+#define ARGR(argname, argtype, lo, hi) get_arg_r(argname, env, sig, pstate, lo, hi, backtrace)
+#define ARGM(argname, argtype, ctx) get_arg_m(argname, env, sig, pstate, backtrace, ctx)
+
+namespace Sass {
+  using std::stringstream;
+  using std::endl;
+
+  Definition* 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,
+                           ParserState("[built-in function]"),
+                           sig,
+                           name,
+                           params,
+                           func,
+                           false);
+  }
+
+  Definition* make_c_function(Sass_Function_Entry c_func, Context& ctx)
+  {
+    using namespace Prelexer;
+
+    const char* sig = sass_function_get_signature(c_func);
+    Parser sig_parser = Parser::from_c_str(sig, ctx, ParserState("[c function]"));
+    // allow to overload generic callback plus @warn, @error and @debug with custom functions
+    sig_parser.lex < alternatives < identifier, exactly <'*'>,
+                                    exactly < Constants::warn_kwd >,
+                                    exactly < Constants::error_kwd >,
+                                    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,
+                           ParserState("[c function]"),
+                           sig,
+                           name,
+                           params,
+                           c_func,
+                           false, true);
+  }
+
+  std::string function_name(Signature sig)
+  {
+    std::string str(sig);
+    return str.substr(0, str.find('('));
+  }
+
+  namespace Functions {
+
+    inline void handle_utf8_error (const ParserState& pstate, Backtrace* backtrace)
+    {
+      try {
+       throw;
+      }
+      catch (utf8::invalid_code_point) {
+        std::string msg("utf8::invalid_code_point");
+        error(msg, pstate, backtrace);
+      }
+      catch (utf8::not_enough_room) {
+        std::string msg("utf8::not_enough_room");
+        error(msg, pstate, backtrace);
+      }
+      catch (utf8::invalid_utf8) {
+        std::string msg("utf8::invalid_utf8");
+        error(msg, pstate, backtrace);
+      }
+      catch (...) { throw; }
+    }
+
+    template <typename T>
+    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]);
+      if (!val) {
+        std::string msg("argument `");
+        msg += argname;
+        msg += "` of `";
+        msg += sig;
+        msg += "` must be a ";
+        msg += T::type_name();
+        error(msg, pstate, backtrace);
+      }
+      return val;
+    }
+
+    Map* 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]);
+      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);
+
+      // 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)
+    {
+      // Minimal error handling -- the expectation is that built-ins will be written correctly!
+      Number* val = get_arg<Number>(argname, env, sig, pstate, backtrace);
+      double v = val->value();
+      if (!(lo <= v && v <= hi)) {
+        std::stringstream msg;
+        msg << "argument `" << argname << "` of `" << sig << "` must be between ";
+        msg << lo << " and " << hi;
+        error(msg.str(), pstate, backtrace);
+      }
+      return val;
+    }
+
+    #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);
+
+    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);
+      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);
+      }
+      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;
+    }
+
+    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);
+      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;
+    }
+
+    #ifdef __MINGW32__
+    uint64_t GetSeed()
+    {
+      HCRYPTPROV hp = 0;
+      BYTE rb[8];
+      CryptAcquireContext(&hp, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
+      CryptGenRandom(hp, sizeof(rb), rb);
+      CryptReleaseContext(hp, 0);
+
+      uint64_t seed;
+      memcpy(&seed, &rb[0], sizeof(seed));
+
+      return seed;
+    }
+    #else
+    static std::random_device rd;
+    uint64_t GetSeed()
+    {
+      return rd();
+    }
+    #endif
+
+    // note: the performance of many  implementations of
+    // random_device degrades sharply once the entropy pool
+    // is exhausted. For practical use, random_device is
+    // generally only used to seed a PRNG such as mt19937.
+    static std::mt19937 rand(static_cast<unsigned int>(GetSeed()));
+
+    // features
+    static std::set<std::string> features {
+      "global-variable-shadowing",
+      "extend-selector-pseudoclass",
+      "at-error",
+      "units-level-3"
+    };
+
+    ////////////////
+    // RGB FUNCTIONS
+    ////////////////
+
+    inline double color_num(Number* n) {
+      if (n->unit() == "%") {
+        return std::min(std::max(n->value() * 255 / 100.0, 0.0), 255.0);
+      } else {
+        return std::min(std::max(n->value(), 0.0), 255.0);
+      }
+    }
+
+    inline double alpha_num(Number* n) {
+      if (n->unit() == "%") {
+        return std::min(std::max(n->value(), 0.0), 100.0);
+      } else {
+        return std::min(std::max(n->value(), 0.0), 1.0);
+      }
+    }
+
+    Signature rgb_sig = "rgb($red, $green, $blue)";
+    BUILT_IN(rgb)
+    {
+      return SASS_MEMORY_NEW(ctx.mem, Color,
+                             pstate,
+                             color_num(ARG("$red",   Number)),
+                             color_num(ARG("$green", Number)),
+                             color_num(ARG("$blue",  Number)));
+    }
+
+    Signature rgba_4_sig = "rgba($red, $green, $blue, $alpha)";
+    BUILT_IN(rgba_4)
+    {
+      return SASS_MEMORY_NEW(ctx.mem, Color,
+                             pstate,
+                             color_num(ARG("$red",   Number)),
+                             color_num(ARG("$green", Number)),
+                             color_num(ARG("$blue",  Number)),
+                             alpha_num(ARG("$alpha", Number)));
+    }
+
+    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);
+      new_c->a(alpha_num(ARG("$alpha", Number)));
+      new_c->disp("");
+      return new_c;
+    }
+
+    Signature red_sig = "red($color)";
+    BUILT_IN(red)
+    { return SASS_MEMORY_NEW(ctx.mem, 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()); }
+
+    Signature blue_sig = "blue($color)";
+    BUILT_IN(blue)
+    { return SASS_MEMORY_NEW(ctx.mem, 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);
+
+      double p = weight->value()/100;
+      double w = 2*p - 1;
+      double a = color1->a() - color2->a();
+
+      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,
+                             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()),
+                             color1->a()*p + color2->a()*(1-p));
+    }
+
+    ////////////////
+    // HSL FUNCTIONS
+    ////////////////
+
+    // RGB to HSL helper function
+    struct HSL { double h; double s; double l; };
+    HSL rgb_to_hsl(double r, double g, double b)
+    {
+
+      // Algorithm from http://en.wikipedia.org/wiki/wHSL_and_HSV#Conversion_from_RGB_to_HSL_or_HSV
+      r /= 255.0; g /= 255.0; b /= 255.0;
+
+      double max = std::max(r, std::max(g, b));
+      double min = std::min(r, std::min(g, b));
+      double delta = max - min;
+
+      double h = 0, s = 0, l = (max + min) / 2.0;
+
+      if (max == min) {
+        h = s = 0; // achromatic
+      }
+      else {
+        if (l < 0.5) s = delta / (max + min);
+        else         s = delta / (2.0 - max - min);
+
+        if      (r == max) h = (g - b) / delta + (g < b ? 6 : 0);
+        else if (g == max) h = (b - r) / delta + 2;
+        else if (b == max) h = (r - g) / delta + 4;
+      }
+
+      HSL hsl_struct;
+      hsl_struct.h = h / 6 * 360;
+      hsl_struct.s = s * 100;
+      hsl_struct.l = l * 100;
+
+      return hsl_struct;
+    }
+
+    // hue to RGB helper function
+    double h_to_rgb(double m1, double m2, double h) {
+      while (h < 0) h += 1;
+      while (h > 1) h -= 1;
+      if (h*6.0 < 1) return m1 + (m2 - m1)*h*6;
+      if (h*2.0 < 1) return m2;
+      if (h*3.0 < 2) return m1 + (m2 - m1) * (2.0/3.0 - h)*6;
+      return m1;
+    }
+
+    Color* hsla_impl(double h, double s, double l, double a, Context& ctx, ParserState pstate)
+    {
+      h /= 360.0;
+      s /= 100.0;
+      l /= 100.0;
+
+      if (l < 0) l = 0;
+      if (s < 0) s = 0;
+      if (l > 1) l = 1;
+      if (s > 1) s = 1;
+      while (h < 0) h += 1;
+      while (h > 1) h -= 1;
+
+      // Algorithm from the CSS3 spec: http://www.w3.org/TR/css3-color/#hsl-color.
+      double m2;
+      if (l <= 0.5) m2 = l*(s+1.0);
+      else m2 = (l+s)-(l*s);
+      double m1 = (l*2.0)-m2;
+      // round the results -- consider moving this into the Color constructor
+      double r = (h_to_rgb(m1, m2, h + 1.0/3.0) * 255.0);
+      double g = (h_to_rgb(m1, m2, h) * 255.0);
+      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);
+    }
+
+    Signature hsl_sig = "hsl($hue, $saturation, $lightness)";
+    BUILT_IN(hsl)
+    {
+      return hsla_impl(ARG("$hue", Number)->value(),
+                       ARG("$saturation", Number)->value(),
+                       ARG("$lightness",  Number)->value(),
+                       1.0,
+                       ctx,
+                       pstate);
+    }
+
+    Signature hsla_sig = "hsla($hue, $saturation, $lightness, $alpha)";
+    BUILT_IN(hsla)
+    {
+      return hsla_impl(ARG("$hue", Number)->value(),
+                       ARG("$saturation", Number)->value(),
+                       ARG("$lightness",  Number)->value(),
+                       ARG("$alpha",  Number)->value(),
+                       ctx,
+                       pstate);
+    }
+
+    Signature hue_sig = "hue($color)";
+    BUILT_IN(hue)
+    {
+      Color* 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");
+    }
+
+    Signature saturation_sig = "saturation($color)";
+    BUILT_IN(saturation)
+    {
+      Color* 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, "%");
+    }
+
+    Signature lightness_sig = "lightness($color)";
+    BUILT_IN(lightness)
+    {
+      Color* 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, "%");
+    }
+
+    Signature adjust_hue_sig = "adjust-hue($color, $degrees)";
+    BUILT_IN(adjust_hue)
+    {
+      Color* rgb_color = ARG("$color", Color);
+      Number* degrees = ARG("$degrees", Number);
+      HSL hsl_color = rgb_to_hsl(rgb_color->r(),
+                                 rgb_color->g(),
+                                 rgb_color->b());
+      return hsla_impl(hsl_color.h + degrees->value(),
+                       hsl_color.s,
+                       hsl_color.l,
+                       rgb_color->a(),
+                       ctx,
+                       pstate);
+    }
+
+    Signature lighten_sig = "lighten($color, $amount)";
+    BUILT_IN(lighten)
+    {
+      Color* rgb_color = ARG("$color", Color);
+      Number* amount = ARGR("$amount", Number, 0, 100);
+      HSL hsl_color = rgb_to_hsl(rgb_color->r(),
+                                 rgb_color->g(),
+                                 rgb_color->b());
+      //Check lightness is not negative before lighten it
+      double hslcolorL = hsl_color.l;
+      if (hslcolorL < 0) {
+        hslcolorL = 0;
+      }
+
+      return hsla_impl(hsl_color.h,
+                       hsl_color.s,
+                       hslcolorL + amount->value(),
+                       rgb_color->a(),
+                       ctx,
+                       pstate);
+    }
+
+    Signature darken_sig = "darken($color, $amount)";
+    BUILT_IN(darken)
+    {
+      Color* rgb_color = ARG("$color", Color);
+      Number* amount = ARGR("$amount", Number, 0, 100);
+      HSL hsl_color = rgb_to_hsl(rgb_color->r(),
+                                 rgb_color->g(),
+                                 rgb_color->b());
+
+      //Check lightness if not over 100, before darken it
+      double hslcolorL = hsl_color.l;
+      if (hslcolorL > 100) {
+        hslcolorL = 100;
+      }
+
+      return hsla_impl(hsl_color.h,
+                       hsl_color.s,
+                       hslcolorL - amount->value(),
+                       rgb_color->a(),
+                       ctx,
+                       pstate);
+    }
+
+    Signature saturate_sig = "saturate($color, $amount: false)";
+    BUILT_IN(saturate)
+    {
+      // CSS3 filter function overload: pass literal through directly
+      Number* amount = dynamic_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) + ")");
+      }
+
+      ARGR("$amount", Number, 0, 100);
+      Color* rgb_color = ARG("$color", Color);
+      HSL hsl_color = rgb_to_hsl(rgb_color->r(),
+                                 rgb_color->g(),
+                                 rgb_color->b());
+
+      double hslcolorS = hsl_color.s + amount->value();
+
+      // Saturation cannot be below 0 or above 100
+      if (hslcolorS < 0) {
+        hslcolorS = 0;
+      }
+      if (hslcolorS > 100) {
+        hslcolorS = 100;
+      }
+
+      return hsla_impl(hsl_color.h,
+                       hslcolorS,
+                       hsl_color.l,
+                       rgb_color->a(),
+                       ctx,
+                       pstate);
+    }
+
+    Signature desaturate_sig = "desaturate($color, $amount)";
+    BUILT_IN(desaturate)
+    {
+      Color* rgb_color = ARG("$color", Color);
+      Number* amount = ARGR("$amount", Number, 0, 100);
+      HSL hsl_color = rgb_to_hsl(rgb_color->r(),
+                                 rgb_color->g(),
+                                 rgb_color->b());
+
+      double hslcolorS = hsl_color.s - amount->value();
+
+      // Saturation cannot be below 0 or above 100
+      if (hslcolorS <= 0) {
+        hslcolorS = 0;
+      }
+      if (hslcolorS > 100) {
+        hslcolorS = 100;
+      }
+
+      return hsla_impl(hsl_color.h,
+                       hslcolorS,
+                       hsl_color.l,
+                       rgb_color->a(),
+                       ctx,
+                       pstate);
+    }
+
+    Signature grayscale_sig = "grayscale($color)";
+    BUILT_IN(grayscale)
+    {
+      // CSS3 filter function overload: pass literal through directly
+      Number* amount = dynamic_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) + ")");
+      }
+
+      Color* rgb_color = ARG("$color", Color);
+      HSL hsl_color = rgb_to_hsl(rgb_color->r(),
+                                 rgb_color->g(),
+                                 rgb_color->b());
+      return hsla_impl(hsl_color.h,
+                       0.0,
+                       hsl_color.l,
+                       rgb_color->a(),
+                       ctx,
+                       pstate);
+    }
+
+    Signature complement_sig = "complement($color)";
+    BUILT_IN(complement)
+    {
+      Color* rgb_color = ARG("$color", Color);
+      HSL hsl_color = rgb_to_hsl(rgb_color->r(),
+                                 rgb_color->g(),
+                                 rgb_color->b());
+      return hsla_impl(hsl_color.h - 180.0,
+                       hsl_color.s,
+                       hsl_color.l,
+                       rgb_color->a(),
+                       ctx,
+                       pstate);
+    }
+
+    Signature invert_sig = "invert($color)";
+    BUILT_IN(invert)
+    {
+      // CSS3 filter function overload: pass literal through directly
+      Number* amount = dynamic_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) + ")");
+      }
+
+      Color* rgb_color = ARG("$color", Color);
+      return SASS_MEMORY_NEW(ctx.mem, Color,
+                             pstate,
+                             255 - rgb_color->r(),
+                             255 - rgb_color->g(),
+                             255 - rgb_color->b(),
+                             rgb_color->a());
+    }
+
+    ////////////////////
+    // OPACITY FUNCTIONS
+    ////////////////////
+    Signature alpha_sig = "alpha($color)";
+    Signature opacity_sig = "opacity($color)";
+    BUILT_IN(alpha)
+    {
+      String_Constant* ie_kwd = dynamic_cast<String_Constant*>(env["$color"]);
+      if (ie_kwd) {
+        return SASS_MEMORY_NEW(ctx.mem, String_Quoted, pstate, "alpha(" + ie_kwd->value() + ")");
+      }
+
+      // CSS3 filter function overload: pass literal through directly
+      Number* amount = dynamic_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(ctx.mem, 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);
+      double amount = ARGR("$amount", Number, 0, 1)->value();
+      double alpha = std::min(color->a() + amount, 1.0);
+      return SASS_MEMORY_NEW(ctx.mem, Color,
+                             pstate,
+                             color->r(),
+                             color->g(),
+                             color->b(),
+                             alpha);
+    }
+
+    Signature transparentize_sig = "transparentize($color, $amount)";
+    Signature fade_out_sig = "fade-out($color, $amount)";
+    BUILT_IN(transparentize)
+    {
+      Color* 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,
+                             pstate,
+                             color->r(),
+                             color->g(),
+                             color->b(),
+                             alpha);
+    }
+
+    ////////////////////////
+    // OTHER COLOR FUNCTIONS
+    ////////////////////////
+
+    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"]);
+
+      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);
+      }
+      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,
+                               pstate,
+                               color->r() + rr,
+                               color->g() + gg,
+                               color->b() + bb,
+                               color->a() + aa);
+      }
+      if (hsl) {
+        HSL hsl_struct = rgb_to_hsl(color->r(), color->g(), color->b());
+        double ss = s ? ARGR("$saturation", Number, -100, 100)->value() : 0;
+        double ll = l ? ARGR("$lightness",  Number, -100, 100)->value() : 0;
+        double aa = a ? ARGR("$alpha",      Number, -1, 1)->value() : 0;
+        return hsla_impl(hsl_struct.h + (h ? h->value() : 0),
+                         hsl_struct.s + ss,
+                         hsl_struct.l + ll,
+                         color->a() + aa,
+                         ctx,
+                         pstate);
+      }
+      if (a) {
+        return SASS_MEMORY_NEW(ctx.mem, Color,
+                               pstate,
+                               color->r(),
+                               color->g(),
+                               color->b(),
+                               color->a() + (a ? a->value() : 0));
+      }
+      error("not enough arguments for `adjust-color`", pstate);
+      // unreachable
+      return color;
+    }
+
+    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"]);
+
+      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);
+      }
+      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,
+                               pstate,
+                               color->r() + rscale * (rscale > 0.0 ? 255 - color->r() : color->r()),
+                               color->g() + gscale * (gscale > 0.0 ? 255 - color->g() : color->g()),
+                               color->b() + bscale * (bscale > 0.0 ? 255 - color->b() : color->b()),
+                               color->a() + ascale * (ascale > 0.0 ? 1.0 - color->a() : color->a()));
+      }
+      if (hsl) {
+        double hscale = (h ? ARGR("$hue",        Number, -100.0, 100.0)->value() : 0.0) / 100.0;
+        double sscale = (s ? ARGR("$saturation", Number, -100.0, 100.0)->value() : 0.0) / 100.0;
+        double lscale = (l ? ARGR("$lightness",  Number, -100.0, 100.0)->value() : 0.0) / 100.0;
+        double ascale = (a ? ARGR("$alpha",      Number, -100.0, 100.0)->value() : 0.0) / 100.0;
+        HSL hsl_struct = rgb_to_hsl(color->r(), color->g(), color->b());
+        hsl_struct.h += hscale * (hscale > 0.0 ? 360.0 - hsl_struct.h : hsl_struct.h);
+        hsl_struct.s += sscale * (sscale > 0.0 ? 100.0 - hsl_struct.s : hsl_struct.s);
+        hsl_struct.l += lscale * (lscale > 0.0 ? 100.0 - hsl_struct.l : hsl_struct.l);
+        double alpha = color->a() + ascale * (ascale > 0.0 ? 1.0 - color->a() : color->a());
+        return hsla_impl(hsl_struct.h, hsl_struct.s, hsl_struct.l, alpha, ctx, pstate);
+      }
+      if (a) {
+        double ascale = (a ? ARGR("$alpha", Number, -100.0, 100.0)->value() : 0.0) / 100.0;
+        return SASS_MEMORY_NEW(ctx.mem, 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);
+      // unreachable
+      return color;
+    }
+
+    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"]);
+
+      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);
+      }
+      if (rgb) {
+        return SASS_MEMORY_NEW(ctx.mem, Color,
+                               pstate,
+                               r ? ARGR("$red",   Number, 0, 255)->value() : color->r(),
+                               g ? ARGR("$green", Number, 0, 255)->value() : color->g(),
+                               b ? ARGR("$blue",  Number, 0, 255)->value() : color->b(),
+                               a ? ARGR("$alpha", Number, 0, 255)->value() : color->a());
+      }
+      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 (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();
+        return hsla_impl(hsl_struct.h, hsl_struct.s, hsl_struct.l, alpha, ctx, pstate);
+      }
+      if (a) {
+        double alpha = a ? ARGR("$alpha", Number, 0, 1.0)->value() : color->a();
+        return SASS_MEMORY_NEW(ctx.mem, Color,
+                               pstate,
+                               color->r(),
+                               color->g(),
+                               color->b(),
+                               alpha);
+      }
+      error("not enough arguments for `change-color`", pstate);
+      // unreachable
+      return color;
+    }
+
+    template <size_t range>
+    static double cap_channel(double c) {
+      if      (c > range) return range;
+      else if (c < 0)     return 0;
+      else                return c;
+    }
+
+    Signature ie_hex_str_sig = "ie-hex-str($color)";
+    BUILT_IN(ie_hex_str)
+    {
+      Color* 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());
+      double a = cap_channel<1>   (c->a()) * 255;
+
+      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));
+
+      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);
+    }
+
+    ///////////////////
+    // STRING FUNCTIONS
+    ///////////////////
+
+    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());
+        // remember if the string was quoted (color tokens)
+        result->sass_fix_1291(string_quoted->quote_mark() != 0);
+        return result;
+      }
+      else if (dynamic_cast<String_Constant*>(arg)) {
+        return (Expression*) arg;
+      }
+      else {
+        To_String to_string(&ctx, false, true);
+        std::string val(arg->perform(&to_string));
+        val = dynamic_cast<Null*>(arg) ? "null" : val;
+
+        deprecated_function("Passing " + val + ", a non-string value, to unquote()", pstate);
+        return (Expression*) 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);
+      return result;
+    }
+
+
+    Signature str_length_sig = "str-length($string)";
+    BUILT_IN(str_length)
+    {
+      size_t len = std::string::npos;
+      try {
+        String_Constant* s = ARG("$string", String_Constant);
+        len = UTF_8::code_point_count(s->value(), 0, s->value().size());
+
+      }
+      // handle any invalid utf8 errors
+      // 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);
+    }
+
+    Signature str_insert_sig = "str-insert($string, $insert, $index)";
+    BUILT_IN(str_insert)
+    {
+      std::string str;
+      try {
+        String_Constant* s = ARG("$string", String_Constant);
+        str = s->value();
+        str = unquote(str);
+        String_Constant* i = ARG("$insert", String_Constant);
+        std::string ins = i->value();
+        ins = unquote(ins);
+        Number* ind = ARG("$index", Number);
+        double index = ind->value();
+        size_t len = UTF_8::code_point_count(str, 0, str.size());
+
+        if (index > 0 && index <= len) {
+          // positive and within string length
+          str.insert(UTF_8::offset_at_position(str, static_cast<size_t>(index) - 1), ins);
+        }
+        else if (index > len) {
+          // positive and past string length
+          str += ins;
+        }
+        else if (index == 0) {
+          str = ins + str;
+        }
+        else if (std::abs(index) <= len) {
+          // negative and within string length
+          index += len + 1;
+          str.insert(UTF_8::offset_at_position(str, static_cast<size_t>(index)), ins);
+        }
+        else {
+          // negative and past string length
+          str = ins + str;
+        }
+
+        if (String_Quoted* ss = dynamic_cast<String_Quoted*>(s)) {
+          if (ss->quote_mark()) str = quote(str);
+        }
+      }
+      // handle any invalid utf8 errors
+      // other errors will be re-thrown
+      catch (...) { handle_utf8_error(pstate, backtrace); }
+      return SASS_MEMORY_NEW(ctx.mem, String_Quoted, pstate, str);
+    }
+
+    Signature str_index_sig = "str-index($string, $substring)";
+    BUILT_IN(str_index)
+    {
+      size_t index = std::string::npos;
+      try {
+        String_Constant* s = ARG("$string", String_Constant);
+        String_Constant* t = ARG("$substring", String_Constant);
+        std::string str = s->value();
+        str = unquote(str);
+        std::string substr = t->value();
+        substr = unquote(substr);
+
+        size_t c_index = str.find(substr);
+        if(c_index == std::string::npos) {
+          return SASS_MEMORY_NEW(ctx.mem, Null, pstate);
+        }
+        index = UTF_8::code_point_count(str, 0, c_index) + 1;
+      }
+      // handle any invalid utf8 errors
+      // 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);
+    }
+
+    Signature str_slice_sig = "str-slice($string, $start-at, $end-at:-1)";
+    BUILT_IN(str_slice)
+    {
+      std::string newstr;
+      try {
+        String_Constant* s = ARG("$string", String_Constant);
+        double start_at = ARG("$start-at", Number)->value();
+        double end_at = ARG("$end-at", Number)->value();
+
+        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 (end_at > size) { end_at = (double)size; }
+        if (start_at < 0) { start_at += size + 1; }
+        else if (start_at == 0) { ++ start_at; }
+
+        if (start_at <= end_at)
+        {
+          std::string::iterator start = str.begin();
+          utf8::advance(start, start_at - 1, str.end());
+          std::string::iterator end = start;
+          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->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);
+    }
+
+    Signature to_upper_case_sig = "to-upper-case($string)";
+    BUILT_IN(to_upper_case)
+    {
+      String_Constant* s = ARG("$string", String_Constant);
+      std::string str = s->value();
+
+      for (size_t i = 0, L = str.length(); i < L; ++i) {
+        if (Sass::Util::isAscii(str[i])) {
+          str[i] = std::toupper(str[i]);
+        }
+      }
+
+      if (String_Quoted* ss = dynamic_cast<String_Quoted*>(s)) {
+        String_Quoted* cpy = SASS_MEMORY_NEW(ctx.mem, String_Quoted, *ss);
+        cpy->value(str);
+        return cpy;
+      } else {
+        return SASS_MEMORY_NEW(ctx.mem, 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);
+      std::string str = s->value();
+
+      for (size_t i = 0, L = str.length(); i < L; ++i) {
+        if (Sass::Util::isAscii(str[i])) {
+          str[i] = std::tolower(str[i]);
+        }
+      }
+
+      if (String_Quoted* ss = dynamic_cast<String_Quoted*>(s)) {
+        String_Quoted* cpy = SASS_MEMORY_NEW(ctx.mem, String_Quoted, *ss);
+        cpy->value(str);
+        return cpy;
+      } else {
+        return SASS_MEMORY_NEW(ctx.mem, String_Quoted, pstate, str);
+      }
+    }
+
+    ///////////////////
+    // NUMBER FUNCTIONS
+    ///////////////////
+
+    Signature percentage_sig = "percentage($number)";
+    BUILT_IN(percentage)
+    {
+      Number* 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, "%");
+    }
+
+    Signature round_sig = "round($number)";
+    BUILT_IN(round)
+    {
+      Number* n = ARG("$number", Number);
+      Number* r = SASS_MEMORY_NEW(ctx.mem, Number, *n);
+      r->pstate(pstate);
+      r->value(Sass::round(r->value()));
+      return r;
+    }
+
+    Signature ceil_sig = "ceil($number)";
+    BUILT_IN(ceil)
+    {
+      Number* n = ARG("$number", Number);
+      Number* r = SASS_MEMORY_NEW(ctx.mem, Number, *n);
+      r->pstate(pstate);
+      r->value(std::ceil(r->value()));
+      return r;
+    }
+
+    Signature floor_sig = "floor($number)";
+    BUILT_IN(floor)
+    {
+      Number* n = ARG("$number", Number);
+      Number* r = SASS_MEMORY_NEW(ctx.mem, Number, *n);
+      r->pstate(pstate);
+      r->value(std::floor(r->value()));
+      return r;
+    }
+
+    Signature abs_sig = "abs($number)";
+    BUILT_IN(abs)
+    {
+      Number* n = ARG("$number", Number);
+      Number* r = SASS_MEMORY_NEW(ctx.mem, Number, *n);
+      r->pstate(pstate);
+      r->value(std::abs(r->value()));
+      return r;
+    }
+
+    Signature min_sig = "min($numbers...)";
+    BUILT_IN(min)
+    {
+      List* arglist = ARG("$numbers", List);
+      Number* least = 0;
+      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);
+        if (least) {
+          if (Eval::lt(xi, least)) least = xi;
+        } else least = xi;
+      }
+      return least;
+    }
+
+    Signature max_sig = "max($numbers...)";
+    BUILT_IN(max)
+    {
+      List* arglist = ARG("$numbers", List);
+      Number* greatest = 0;
+      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);
+        if (greatest) {
+          if (Eval::lt(greatest, xi)) greatest = xi;
+        } else greatest = xi;
+      }
+      return greatest;
+    }
+
+    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);
+      if (l) {
+        double v = l->value();
+        if (v < 1) {
+          stringstream err;
+          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`";
+          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);
+      }
+      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);
+      } else if (v) {
+        throw Exception::InvalidArgumentType(pstate, "random", "$limit", "number", v);
+      } else {
+        throw Exception::InvalidArgumentType(pstate, "random", "$limit", "number");
+      }
+      return 0;
+    }
+
+    /////////////////
+    // LIST FUNCTIONS
+    /////////////////
+
+    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());
+      }
+      Expression* 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));
+      }
+      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());
+        } else {
+          return SASS_MEMORY_NEW(ctx.mem, Number, pstate, 1);
+        }
+      }
+
+      List* list = dynamic_cast<List*>(env["$list"]);
+      return SASS_MEMORY_NEW(ctx.mem, Number,
+                             pstate,
+                             (double)(list ? list->size() : 1));
+    }
+
+    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"])) {
+        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);
+        return (*sl)[static_cast<int>(index)]->perform(&listize);
+      }
+      List* l = dynamic_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);
+      }
+      size_t len = m ? m->length() : l->length();
+      bool empty = m ? m->empty() : l->empty();
+      if (empty) error("argument `$list` of `" + std::string(sig) + "` must not be empty", pstate);
+      double index = std::floor(n->value() < 0 ? len + n->value() : n->value() - 1);
+      if (index < 0 || index > len - 1) error("index out of bounds for `" + std::string(sig) + "`", pstate);
+
+      if (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;
+      }
+      else {
+        return l->value_at_index(static_cast<int>(index));
+      }
+    }
+
+    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);
+      if (!l) {
+        l = SASS_MEMORY_NEW(ctx.mem, List, pstate, 1);
+        *l << ARG("$list", Expression);
+      }
+      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());
+      for (size_t i = 0, L = l->length(); i < L; ++i) {
+        *result << ((i == index) ? v : (*l)[i]);
+      }
+      return result;
+    }
+
+    Signature index_sig = "index($list, $value)";
+    BUILT_IN(index)
+    {
+      List* l = dynamic_cast<List*>(env["$list"]);
+      Expression* v = ARG("$value", Expression);
+      if (!l) {
+        l = SASS_MEMORY_NEW(ctx.mem, List, pstate, 1);
+        *l << ARG("$list", Expression);
+      }
+      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));
+      }
+      return SASS_MEMORY_NEW(ctx.mem, 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);
+      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);
+        sep_val = (l2 ? l2->separator() : SASS_SPACE);
+      }
+      if (!l2) {
+        l2 = SASS_MEMORY_NEW(ctx.mem, List, pstate, 1);
+        *l2 << ARG("$list2", Expression);
+      }
+      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;
+    }
+
+    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));
+      }
+      String_Constant* sep = ARG("$separator", String_Constant);
+      if (!l) {
+        l = SASS_MEMORY_NEW(ctx.mem, List, pstate, 1);
+        *l << ARG("$list", Expression);
+      }
+      List* result = SASS_MEMORY_NEW(ctx.mem, List, pstate, l->length() + 1, l->separator());
+      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);
+
+      } else {
+        *result << v;
+      }
+      return result;
+    }
+
+    Signature zip_sig = "zip($lists...)";
+    BUILT_IN(zip)
+    {
+      List* arglist = SASS_MEMORY_NEW(ctx.mem, List, *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));
+        if (!ith) {
+          ith = SASS_MEMORY_NEW(ctx.mem, List, pstate, 1);
+          *ith << arglist->value_at_index(i);
+          if (arglist->is_arglist()) {
+            ((Argument*)(*arglist)[i])->value(ith);
+          } else {
+            (*arglist)[i] = ith;
+          }
+        }
+        shortest = (i ? std::min(shortest, ith->length()) : ith->length());
+      }
+      List* zippers = SASS_MEMORY_NEW(ctx.mem, 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);
+        for (size_t j = 0; j < L; ++j) {
+          *zipper << (*static_cast<List*>(arglist->value_at_index(j)))[i];
+        }
+        *zippers << zipper;
+      }
+      return zippers;
+    }
+
+    Signature list_separator_sig = "list_separator($list)";
+    BUILT_IN(list_separator)
+    {
+      List* l = dynamic_cast<List*>(env["$list"]);
+      if (!l) {
+        l = SASS_MEMORY_NEW(ctx.mem, List, pstate, 1);
+        *l << ARG("$list", Expression);
+      }
+      return SASS_MEMORY_NEW(ctx.mem, String_Quoted,
+                               pstate,
+                               l->separator() == SASS_COMMA ? "comma" : "space");
+    }
+
+    /////////////////
+    // MAP FUNCTIONS
+    /////////////////
+
+    Signature map_get_sig = "map-get($map, $key)";
+    BUILT_IN(map_get)
+    {
+      Map* m = ARGM("$map", Map, ctx);
+      Expression* v = ARG("$key", Expression);
+      try {
+        return m->at(v);
+      } catch (const std::out_of_range&) {
+        return SASS_MEMORY_NEW(ctx.mem, Null, pstate);
+      }
+      catch (...) { throw; }
+    }
+
+    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));
+    }
+
+    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);
+      for ( auto key : m->keys()) {
+        *result << key;
+      }
+      return result;
+    }
+
+    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);
+      for ( auto key : m->keys()) {
+        *result << m->at(key);
+      }
+      return result;
+    }
+
+    Signature map_merge_sig = "map-merge($map1, $map2)";
+    BUILT_IN(map_merge)
+    {
+      Map* m1 = ARGM("$map1", Map, ctx);
+      Map* 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;
+      return result;
+    }
+
+    Signature map_remove_sig = "map-remove($map, $keys...)";
+    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);
+      for (auto key : m->keys()) {
+        remove = false;
+        for (size_t j = 0, K = arglist->length(); j < K && !remove; ++j) {
+          remove = Eval::eq(key, arglist->value_at_index(j));
+        }
+        if (!remove) *result << std::make_pair(key, m->at(key));
+      }
+      return result;
+    }
+
+    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);
+      for (size_t i = arglist->size(), L = arglist->length(); i < L; ++i) {
+        std::string name = std::string(((Argument*)(*arglist)[i])->name());
+        name = name.erase(0, 1); // sanitize name (remove dollar sign)
+        *result << std::make_pair(SASS_MEMORY_NEW(ctx.mem, String_Quoted,
+                 pstate, name),
+                 ((Argument*)(*arglist)[i])->value());
+      }
+      return result;
+    }
+
+    //////////////////////////
+    // INTROSPECTION FUNCTIONS
+    //////////////////////////
+
+    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());
+    }
+
+    Signature unit_sig = "unit($number)";
+    BUILT_IN(unit)
+    { return SASS_MEMORY_NEW(ctx.mem, 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()); }
+
+    Signature comparable_sig = "comparable($number-1, $number-2)";
+    BUILT_IN(comparable)
+    {
+      Number* n1 = ARG("$number-1", Number);
+      Number* n2 = ARG("$number-2", Number);
+      if (n1->is_unitless() || n2->is_unitless()) {
+        return SASS_MEMORY_NEW(ctx.mem, Boolean, pstate, true);
+      }
+      Number tmp_n2(*n2);
+      tmp_n2.normalize(n1->find_convertible_unit());
+      return SASS_MEMORY_NEW(ctx.mem, Boolean, pstate, n1->unit() == tmp_n2.unit());
+    }
+
+    Signature variable_exists_sig = "variable-exists($name)";
+    BUILT_IN(variable_exists)
+    {
+      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);
+      }
+      else {
+        return SASS_MEMORY_NEW(ctx.mem, Boolean, pstate, false);
+      }
+    }
+
+    Signature global_variable_exists_sig = "global-variable-exists($name)";
+    BUILT_IN(global_variable_exists)
+    {
+      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);
+      }
+      else {
+        return SASS_MEMORY_NEW(ctx.mem, Boolean, pstate, false);
+      }
+    }
+
+    Signature function_exists_sig = "function-exists($name)";
+    BUILT_IN(function_exists)
+    {
+      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);
+      }
+      else {
+        return SASS_MEMORY_NEW(ctx.mem, Boolean, pstate, false);
+      }
+    }
+
+    Signature mixin_exists_sig = "mixin-exists($name)";
+    BUILT_IN(mixin_exists)
+    {
+      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);
+      }
+      else {
+        return SASS_MEMORY_NEW(ctx.mem, Boolean, pstate, false);
+      }
+    }
+
+    Signature feature_exists_sig = "feature-exists($name)";
+    BUILT_IN(feature_exists)
+    {
+      std::string s = unquote(ARG("$name", String_Constant)->value());
+
+      if(features.find(s) == features.end()) {
+        return SASS_MEMORY_NEW(ctx.mem, Boolean, pstate, false);
+      }
+      else {
+        return SASS_MEMORY_NEW(ctx.mem, Boolean, pstate, true);
+      }
+    }
+
+    Signature call_sig = "call($name, $args...)";
+    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));
+
+      Arguments* args = SASS_MEMORY_NEW(ctx.mem, 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;
+      // 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);
+        // if (params && params->has_rest_parameter()) {
+        //   Parameter* p = param_size > i ? (*params)[i] : 0;
+        //   List* list = dynamic_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);
+        } else {
+          *args << SASS_MEMORY_NEW(ctx.mem, Argument, pstate, expr);
+        }
+      }
+      Function_Call* func = SASS_MEMORY_NEW(ctx.mem, Function_Call, pstate, name, args);
+      Expand expand(ctx, &d_env, backtrace);
+      return func->perform(&expand.eval);
+
+    }
+
+    ////////////////////
+    // BOOLEAN FUNCTIONS
+    ////////////////////
+
+    Signature not_sig = "not($value)";
+    BUILT_IN(sass_not)
+    { return SASS_MEMORY_NEW(ctx.mem, 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);
+      }
+    }
+
+    ////////////////
+    // URL FUNCTIONS
+    ////////////////
+
+    Signature image_url_sig = "image-url($path, $only-path: false, $cache-buster: false)";
+    BUILT_IN(image_url)
+    {
+      error("`image_url` has been removed from libsass because it's not part of the Sass spec", pstate);
+      return 0; // suppress warning, error will exit anyway
+    }
+
+    //////////////////////////
+    // MISCELLANEOUS FUNCTIONS
+    //////////////////////////
+
+    Signature inspect_sig = "inspect($value)";
+    BUILT_IN(inspect)
+    {
+      Expression* 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");
+      } else if (v->concrete_type() == Expression::STRING) {
+        return v;
+      } else {
+        bool parentheses = v->concrete_type() == Expression::MAP ||
+                           v->concrete_type() == Expression::LIST;
+        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);
+      }
+      // return v;
+    }
+    Signature selector_nest_sig = "selector-nest($selectors...)";
+    BUILT_IN(selector_nest)
+    {
+      To_String to_string(&ctx, false);
+      List* arglist = ARG("$selectors", List);
+
+      // Not enough parameters
+      if( arglist->length() == 0 )
+        error("$selectors: At least one selector must be passed", pstate);
+
+      // Parse args into vector of selectors
+      std::vector<Selector_List*> parsedSelectors;
+      for (size_t i = 0, L = arglist->length(); i < L; ++i) {
+        Expression* exp = dynamic_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);
+      }
+
+      // Nothing to do
+      if( parsedSelectors.empty() ) {
+        return SASS_MEMORY_NEW(ctx.mem, 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;
+      ++itr;
+
+      for(;itr != parsedSelectors.end(); ++itr) {
+        Selector_List* child = *itr;
+        std::vector<Complex_Selector*> exploded;
+        Selector_List* rv = child->parentize(result, ctx);
+        for (size_t m = 0, mLen = rv->length(); m < mLen; ++m) {
+          exploded.push_back((*rv)[m]);
+        }
+        result->elements(exploded);
+      }
+
+      Listize listize(ctx);
+      return result->perform(&listize);
+    }
+
+    Signature selector_append_sig = "selector-append($selectors...)";
+    BUILT_IN(selector_append)
+    {
+      To_String to_string;
+      List* arglist = ARG("$selectors", List);
+
+      // Not enough parameters
+      if( arglist->length() == 0 )
+        error("$selectors: At least one selector must be passed", pstate);
+
+      // Parse args into vector of selectors
+      std::vector<Selector_List*> parsedSelectors;
+      for (size_t i = 0, L = arglist->length(); i < L; ++i) {
+        Expression* exp = dynamic_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);
+      }
+
+      // Nothing to do
+      if( parsedSelectors.empty() ) {
+        return SASS_MEMORY_NEW(ctx.mem, 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;
+      ++itr;
+
+      for(;itr != parsedSelectors.end(); ++itr) {
+        Selector_List* child = *itr;
+        std::vector<Complex_Selector*> newElements;
+
+        // For every COMPLEX_SELECTOR in `result`
+        // For every COMPLEX_SELECTOR in `child`
+          // let parentSeqClone equal a copy of result->elements[i]
+          // let childSeq equal child->elements[j]
+          // Append all of childSeq head elements into parentSeqClone
+          // Set the innermost tail of parentSeqClone, to childSeq's tail
+        // 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();
+
+            // 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 += "`";
+              error(msg, pstate, backtrace);
+            }
+
+            // Cannot be a Universal selector
+            Type_Selector* pType = dynamic_cast<Type_Selector*>(base->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 += "`";
+              error(msg, pstate, backtrace);
+            }
+
+            // TODO: Add check for namespace stuff
+
+            // append any selectors in childSeq's head
+            *(parentSeqClone->innermost()->head()) += (base->head());
+
+            // Set parentSeqClone new tail
+            parentSeqClone->innermost()->tail( base->tail() );
+
+            newElements.push_back(parentSeqClone);
+          }
+        }
+
+        result->elements(newElements);
+      }
+
+      Listize listize(ctx);
+      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* result = selector1->unify_with(selector2, ctx);
+      Listize listize(ctx);
+      return result->perform(&listize);
+    }
+
+    Signature simple_selectors_sig = "simple-selectors($selector)";
+    BUILT_IN(simple_selectors)
+    {
+      Compound_Selector* sel = ARGSEL("$selector", Compound_Selector, p_contextualize);
+
+      To_String to_string;
+      List* l = SASS_MEMORY_NEW(ctx.mem, 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) ;
+
+        *l << SASS_MEMORY_NEW(ctx.mem, String_Quoted, ss->pstate(), ss_string);
+      }
+
+      return l;
+    }
+
+    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);
+
+      ExtensionSubsetMap subset_map;
+      extender->populate_extends(extendee, ctx, subset_map);
+
+      bool extendedSomething;
+      Selector_List* result = Extend::extendSelectorList(selector, ctx, subset_map, false, extendedSomething);
+
+      Listize listize(ctx);
+      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;
+      replacement->populate_extends(original, ctx, subset_map);
+
+      bool extendedSomething;
+      Selector_List* result = Extend::extendSelectorList(selector, ctx, subset_map, true, extendedSomething);
+
+      Listize listize(ctx);
+      return result->perform(&listize);
+    }
+
+    Signature selector_parse_sig = "selector-parse($selector)";
+    BUILT_IN(selector_parse)
+    {
+      Selector_List* sel = ARGSEL("$selector", Selector_List, p_contextualize);
+
+      Listize listize(ctx);
+      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);
+      bool result = sel_sup->is_superselector_of(sel_sub);
+      return SASS_MEMORY_NEW(ctx.mem, Boolean, pstate, result);
+    }
+
+    Signature unique_id_sig = "unique-id()";
+    BUILT_IN(unique_id)
+    {
+      std::stringstream ss;
+      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());
+    }
+
+  }
+}
diff --git a/libsass/src/functions.hpp b/libsass/src/functions.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/functions.hpp
@@ -0,0 +1,197 @@
+#ifndef SASS_FUNCTIONS_H
+#define SASS_FUNCTIONS_H
+
+#include "position.hpp"
+#include "environment.hpp"
+#include "sass/functions.h"
+
+#define BUILT_IN(name) Expression*\
+name(Env& env, Env& d_env, Context& ctx, Signature sig, ParserState pstate, Backtrace* backtrace)
+
+namespace Sass {
+  class Context;
+  struct Backtrace;
+  class AST_Node;
+  class Expression;
+  class Definition;
+  typedef Environment<AST_Node*> Env;
+  typedef const char* Signature;
+  typedef Expression* (*Native_Function)(Env&, Env&, Context&, Signature, ParserState, Backtrace*);
+
+  Definition* make_native_function(Signature, Native_Function, Context& ctx);
+  Definition* make_c_function(Sass_Function_Entry c_func, Context& ctx);
+
+  std::string function_name(Signature);
+
+  namespace Functions {
+
+    extern Signature rgb_sig;
+    extern Signature rgba_4_sig;
+    extern Signature rgba_2_sig;
+    extern Signature red_sig;
+    extern Signature green_sig;
+    extern Signature blue_sig;
+    extern Signature mix_sig;
+    extern Signature hsl_sig;
+    extern Signature hsla_sig;
+    extern Signature hue_sig;
+    extern Signature saturation_sig;
+    extern Signature lightness_sig;
+    extern Signature adjust_hue_sig;
+    extern Signature lighten_sig;
+    extern Signature darken_sig;
+    extern Signature saturate_sig;
+    extern Signature desaturate_sig;
+    extern Signature grayscale_sig;
+    extern Signature complement_sig;
+    extern Signature invert_sig;
+    extern Signature alpha_sig;
+    extern Signature opacity_sig;
+    extern Signature opacify_sig;
+    extern Signature fade_in_sig;
+    extern Signature transparentize_sig;
+    extern Signature fade_out_sig;
+    extern Signature adjust_color_sig;
+    extern Signature scale_color_sig;
+    extern Signature change_color_sig;
+    extern Signature ie_hex_str_sig;
+    extern Signature unquote_sig;
+    extern Signature quote_sig;
+    extern Signature str_length_sig;
+    extern Signature str_insert_sig;
+    extern Signature str_index_sig;
+    extern Signature str_slice_sig;
+    extern Signature to_upper_case_sig;
+    extern Signature to_lower_case_sig;
+    extern Signature percentage_sig;
+    extern Signature round_sig;
+    extern Signature ceil_sig;
+    extern Signature floor_sig;
+    extern Signature abs_sig;
+    extern Signature min_sig;
+    extern Signature max_sig;
+    extern Signature inspect_sig;
+    extern Signature random_sig;
+    extern Signature length_sig;
+    extern Signature nth_sig;
+    extern Signature index_sig;
+    extern Signature join_sig;
+    extern Signature append_sig;
+    extern Signature zip_sig;
+    extern Signature list_separator_sig;
+    extern Signature type_of_sig;
+    extern Signature unit_sig;
+    extern Signature unitless_sig;
+    extern Signature comparable_sig;
+    extern Signature variable_exists_sig;
+    extern Signature global_variable_exists_sig;
+    extern Signature function_exists_sig;
+    extern Signature mixin_exists_sig;
+    extern Signature feature_exists_sig;
+    extern Signature call_sig;
+    extern Signature not_sig;
+    extern Signature if_sig;
+    extern Signature image_url_sig;
+    extern Signature map_get_sig;
+    extern Signature map_merge_sig;
+    extern Signature map_remove_sig;
+    extern Signature map_keys_sig;
+    extern Signature map_values_sig;
+    extern Signature map_has_key_sig;
+    extern Signature keywords_sig;
+    extern Signature set_nth_sig;
+    extern Signature unique_id_sig;
+    extern Signature selector_nest_sig;
+    extern Signature selector_append_sig;
+    extern Signature selector_extend_sig;
+    extern Signature selector_replace_sig;
+    extern Signature selector_unify_sig;
+    extern Signature is_superselector_sig;
+    extern Signature simple_selectors_sig;
+    extern Signature selector_parse_sig;
+
+    BUILT_IN(rgb);
+    BUILT_IN(rgba_4);
+    BUILT_IN(rgba_2);
+    BUILT_IN(red);
+    BUILT_IN(green);
+    BUILT_IN(blue);
+    BUILT_IN(mix);
+    BUILT_IN(hsl);
+    BUILT_IN(hsla);
+    BUILT_IN(hue);
+    BUILT_IN(saturation);
+    BUILT_IN(lightness);
+    BUILT_IN(adjust_hue);
+    BUILT_IN(lighten);
+    BUILT_IN(darken);
+    BUILT_IN(saturate);
+    BUILT_IN(desaturate);
+    BUILT_IN(grayscale);
+    BUILT_IN(complement);
+    BUILT_IN(invert);
+    BUILT_IN(alpha);
+    BUILT_IN(opacify);
+    BUILT_IN(transparentize);
+    BUILT_IN(adjust_color);
+    BUILT_IN(scale_color);
+    BUILT_IN(change_color);
+    BUILT_IN(ie_hex_str);
+    BUILT_IN(sass_unquote);
+    BUILT_IN(sass_quote);
+    BUILT_IN(str_length);
+    BUILT_IN(str_insert);
+    BUILT_IN(str_index);
+    BUILT_IN(str_slice);
+    BUILT_IN(to_upper_case);
+    BUILT_IN(to_lower_case);
+    BUILT_IN(percentage);
+    BUILT_IN(round);
+    BUILT_IN(ceil);
+    BUILT_IN(floor);
+    BUILT_IN(abs);
+    BUILT_IN(min);
+    BUILT_IN(max);
+    BUILT_IN(inspect);
+    BUILT_IN(random);
+    BUILT_IN(length);
+    BUILT_IN(nth);
+    BUILT_IN(index);
+    BUILT_IN(join);
+    BUILT_IN(append);
+    BUILT_IN(zip);
+    BUILT_IN(list_separator);
+    BUILT_IN(type_of);
+    BUILT_IN(unit);
+    BUILT_IN(unitless);
+    BUILT_IN(comparable);
+    BUILT_IN(variable_exists);
+    BUILT_IN(global_variable_exists);
+    BUILT_IN(function_exists);
+    BUILT_IN(mixin_exists);
+    BUILT_IN(feature_exists);
+    BUILT_IN(call);
+    BUILT_IN(sass_not);
+    BUILT_IN(sass_if);
+    BUILT_IN(image_url);
+    BUILT_IN(map_get);
+    BUILT_IN(map_merge);
+    BUILT_IN(map_remove);
+    BUILT_IN(map_keys);
+    BUILT_IN(map_values);
+    BUILT_IN(map_has_key);
+    BUILT_IN(keywords);
+    BUILT_IN(set_nth);
+    BUILT_IN(unique_id);
+    BUILT_IN(selector_nest);
+    BUILT_IN(selector_append);
+    BUILT_IN(selector_extend);
+    BUILT_IN(selector_replace);
+    BUILT_IN(selector_unify);
+    BUILT_IN(is_superselector);
+    BUILT_IN(simple_selectors);
+    BUILT_IN(selector_parse);
+  }
+}
+
+#endif
diff --git a/libsass/src/inspect.cpp b/libsass/src/inspect.cpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/inspect.cpp
@@ -0,0 +1,851 @@
+#include <cmath>
+#include <string>
+#include <iostream>
+#include <iomanip>
+#include <stdint.h>
+#include <stdint.h>
+
+#include "ast.hpp"
+#include "inspect.hpp"
+#include "context.hpp"
+#include "listize.hpp"
+#include "color_maps.hpp"
+#include "utf8/checked.h"
+
+namespace Sass {
+
+  Inspect::Inspect(Emitter emi)
+  : Emitter(emi)
+  { }
+  Inspect::~Inspect() { }
+
+  // statements
+  void Inspect::operator()(Block* block)
+  {
+    if (!block->is_root()) {
+      add_open_mapping(block);
+      append_scope_opener();
+    }
+    if (output_style() == SASS_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 (!block->is_root()) {
+      append_scope_closer();
+      add_close_mapping(block);
+    }
+
+  }
+
+  void Inspect::operator()(Ruleset* ruleset)
+  {
+    ruleset->selector()->perform(this);
+    ruleset->block()->perform(this);
+  }
+
+  void Inspect::operator()(Keyframe_Rule* rule)
+  {
+    if (rule->selector()) rule->selector()->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)
+  {
+    append_indentation();
+    append_token("::BUBBLE", bubble);
+    append_scope_opener();
+    bubble->node()->perform(this);
+    append_scope_closer();
+  }
+
+  void Inspect::operator()(Media_Block* media_block)
+  {
+    append_indentation();
+    append_token("@media", media_block);
+    append_mandatory_space();
+    in_media_block = true;
+    media_block->media_queries()->perform(this);
+    in_media_block = false;
+    media_block->block()->perform(this);
+  }
+
+  void Inspect::operator()(Supports_Block* feature_block)
+  {
+    append_indentation();
+    append_token("@supports", feature_block);
+    append_mandatory_space();
+    feature_block->condition()->perform(this);
+    feature_block->block()->perform(this);
+  }
+
+  void Inspect::operator()(At_Root_Block* at_root_block)
+  {
+    append_indentation();
+    append_token("@at-root ", at_root_block);
+    append_mandatory_space();
+    if(at_root_block->expression()) at_root_block->expression()->perform(this);
+    at_root_block->block()->perform(this);
+  }
+
+  void Inspect::operator()(At_Rule* at_rule)
+  {
+    append_indentation();
+    append_token(at_rule->keyword(), at_rule);
+    if (at_rule->selector()) {
+      append_mandatory_space();
+      bool was_wrapped = in_wrapped;
+      in_wrapped = true;
+      at_rule->selector()->perform(this);
+      in_wrapped = was_wrapped;
+    }
+    if (at_rule->value()) {
+      append_mandatory_space();
+      at_rule->value()->perform(this);
+    }
+    if (at_rule->block()) {
+      at_rule->block()->perform(this);
+    }
+    else {
+      append_delimiter();
+    }
+  }
+
+  void Inspect::operator()(Declaration* dec)
+  {
+    if (dec->value()->concrete_type() == Expression::NULL_VAL) return;
+    bool was_decl = in_declaration;
+    in_declaration = true;
+    if (output_style() == SASS_STYLE_NESTED)
+      indentation += dec->tabs();
+    append_indentation();
+    dec->property()->perform(this);
+    append_colon_separator();
+
+    if (dec->value()->concrete_type() == Expression::SELECTOR) {
+      Listize listize(*ctx);
+      dec->value()->perform(&listize)->perform(this);
+    } else {
+      dec->value()->perform(this);
+    }
+
+    if (dec->is_important()) {
+      append_optional_space();
+      append_string("!important");
+    }
+    append_delimiter();
+    if (output_style() == SASS_STYLE_NESTED)
+      indentation -= dec->tabs();
+    in_declaration = was_decl;
+  }
+
+  void Inspect::operator()(Assignment* assn)
+  {
+    append_token(assn->variable(), assn);
+    append_colon_separator();
+    assn->value()->perform(this);
+    if (assn->is_default()) {
+      append_optional_space();
+      append_string("!default");
+    }
+    append_delimiter();
+  }
+
+  void Inspect::operator()(Import* 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);
+      }
+      append_delimiter();
+      for (size_t i = 1, S = import->urls().size(); i < S; ++i) {
+        append_mandatory_linefeed();
+        append_token("@import", import);
+        append_mandatory_space();
+
+        if (String_Quoted* strq = dynamic_cast<String_Quoted*>(import->urls()[i])) {
+          strq->is_delayed(false);
+        }
+
+        import->urls()[i]->perform(this);
+        if (import->media_queries()) {
+          append_mandatory_space();
+          import->media_queries()->perform(this);
+        }
+        append_delimiter();
+      }
+    }
+  }
+
+  void Inspect::operator()(Import_Stub* import)
+  {
+    append_indentation();
+    append_token("@import", import);
+    append_mandatory_space();
+    append_string(import->imp_path());
+    append_delimiter();
+  }
+
+  void Inspect::operator()(Warning* warning)
+  {
+    append_indentation();
+    append_token("@warn", warning);
+    append_mandatory_space();
+    warning->message()->perform(this);
+    append_delimiter();
+  }
+
+  void Inspect::operator()(Error* error)
+  {
+    append_indentation();
+    append_token("@error", error);
+    append_mandatory_space();
+    error->message()->perform(this);
+    append_delimiter();
+  }
+
+  void Inspect::operator()(Debug* debug)
+  {
+    append_indentation();
+    append_token("@debug", debug);
+    append_mandatory_space();
+    debug->value()->perform(this);
+    append_delimiter();
+  }
+
+  void Inspect::operator()(Comment* comment)
+  {
+    in_comment = true;
+    comment->text()->perform(this);
+    in_comment = false;
+  }
+
+  void Inspect::operator()(If* cond)
+  {
+    append_indentation();
+    append_token("@if", cond);
+    append_mandatory_space();
+    cond->predicate()->perform(this);
+    cond->block()->perform(this);
+    if (cond->alternative()) {
+      append_optional_linefeed();
+      append_indentation();
+      append_string("else");
+      cond->alternative()->perform(this);
+    }
+  }
+
+  void Inspect::operator()(For* loop)
+  {
+    append_indentation();
+    append_token("@for", loop);
+    append_mandatory_space();
+    append_string(loop->variable());
+    append_string(" from ");
+    loop->lower_bound()->perform(this);
+    append_string(loop->is_inclusive() ? " through " : " to ");
+    loop->upper_bound()->perform(this);
+    loop->block()->perform(this);
+  }
+
+  void Inspect::operator()(Each* loop)
+  {
+    append_indentation();
+    append_token("@each", loop);
+    append_mandatory_space();
+    append_string(loop->variables()[0]);
+    for (size_t i = 1, L = loop->variables().size(); i < L; ++i) {
+      append_comma_separator();
+      append_string(loop->variables()[i]);
+    }
+    append_string(" in ");
+    loop->list()->perform(this);
+    loop->block()->perform(this);
+  }
+
+  void Inspect::operator()(While* loop)
+  {
+    append_indentation();
+    append_token("@while", loop);
+    append_mandatory_space();
+    loop->predicate()->perform(this);
+    loop->block()->perform(this);
+  }
+
+  void Inspect::operator()(Return* ret)
+  {
+    append_indentation();
+    append_token("@return", ret);
+    append_mandatory_space();
+    ret->value()->perform(this);
+    append_delimiter();
+  }
+
+  void Inspect::operator()(Extension* extend)
+  {
+    append_indentation();
+    append_token("@extend", extend);
+    append_mandatory_space();
+    extend->selector()->perform(this);
+    append_delimiter();
+  }
+
+  void Inspect::operator()(Definition* def)
+  {
+    append_indentation();
+    if (def->type() == Definition::MIXIN) {
+      append_token("@mixin", def);
+      append_mandatory_space();
+    } else {
+      append_token("@function", def);
+      append_mandatory_space();
+    }
+    append_string(def->name());
+    def->parameters()->perform(this);
+    def->block()->perform(this);
+  }
+
+  void Inspect::operator()(Mixin_Call* call)
+  {
+    append_indentation();
+    append_token("@include", call);
+    append_mandatory_space();
+    append_string(call->name());
+    if (call->arguments()) {
+      call->arguments()->perform(this);
+    }
+    if (call->block()) {
+      append_optional_space();
+      call->block()->perform(this);
+    }
+    if (!call->block()) append_delimiter();
+  }
+
+  void Inspect::operator()(Content* content)
+  {
+    append_indentation();
+    append_token("@content", content);
+    append_delimiter();
+  }
+
+  void Inspect::operator()(Map* map)
+  {
+    if (map->empty()) return;
+    if (map->is_invisible()) return;
+    bool items_output = false;
+    append_string("(");
+    for (auto key : map->keys()) {
+      if (items_output) append_comma_separator();
+      key->perform(this);
+      append_colon_separator();
+      map->at(key)->perform(this);
+      items_output = true;
+    }
+    append_string(")");
+  }
+
+  void Inspect::operator()(List* list)
+  {
+    std::string sep(list->separator() == SASS_SPACE ? " " : ",");
+    if ((output_style() != SASS_STYLE_COMPRESSED || in_debug) && 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 && (
+        (list->separator() == SASS_SPACE && in_space_array) ||
+        (list->separator() == SASS_COMMA && in_comma_array)
+    )) {
+      append_string("(");
+    }
+
+    if (list->separator() == SASS_SPACE) in_space_array = true;
+    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 (items_output) {
+        append_string(sep);
+      }
+      if (items_output && sep != " ")
+        append_optional_space();
+      list_item->perform(this);
+      items_output = true;
+    }
+
+    in_comma_array = was_comma_array;
+    in_space_array = was_space_array;
+    if (!in_declaration && (
+        (list->separator() == SASS_SPACE && in_space_array) ||
+        (list->separator() == SASS_COMMA && in_comma_array)
+    )) {
+      append_string(")");
+    }
+
+  }
+
+  void Inspect::operator()(Binary_Expression* expr)
+  {
+    expr->left()->perform(this);
+    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;
+      default: break; // shouldn't get here
+    }
+    expr->right()->perform(this);
+  }
+
+  void Inspect::operator()(Unary_Expression* expr)
+  {
+    if (expr->type() == Unary_Expression::PLUS) append_string("+");
+    else                                        append_string("-");
+    expr->operand()->perform(this);
+  }
+
+  void Inspect::operator()(Function_Call* call)
+  {
+    append_token(call->name(), call);
+    call->arguments()->perform(this);
+  }
+
+  void Inspect::operator()(Function_Call_Schema* call)
+  {
+    call->name()->perform(this);
+    call->arguments()->perform(this);
+  }
+
+  void Inspect::operator()(Variable* var)
+  {
+    append_token(var->name(), var);
+  }
+
+  void Inspect::operator()(Textual* txt)
+  {
+    append_token(txt->value(), txt);
+  }
+
+  void Inspect::operator()(Number* 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));
+    // output the final token
+    append_token(res, n);
+  }
+
+  void Inspect::operator()(Color* 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);
+  }
+
+  void Inspect::operator()(Boolean* 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);
+  }
+
+  void Inspect::operator()(String_Schema* ss)
+  {
+    // Evaluation should turn these into String_Constants,
+    // so this method is only for inspection purposes.
+    for (size_t i = 0, L = ss->length(); i < L; ++i) {
+      if ((*ss)[i]->is_interpolant()) append_string("#{");
+      (*ss)[i]->perform(this);
+      if ((*ss)[i]->is_interpolant()) append_string("}");
+    }
+  }
+
+  void Inspect::operator()(String_Constant* 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);
+  }
+
+  void Inspect::operator()(String_Quoted* 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);
+  }
+  void Inspect::operator()(Supports_Operator* so)
+  {
+
+    if (so->needs_parens(so->left())) append_string("(");
+    so->left()->perform(this);
+    if (so->needs_parens(so->left())) append_string(")");
+
+    if (so->operand() == Supports_Operator::AND) {
+      append_mandatory_space();
+      append_token("and", so);
+      append_mandatory_space();
+    } else if (so->operand() == Supports_Operator::OR) {
+      append_mandatory_space();
+      append_token("or", so);
+      append_mandatory_space();
+    }
+
+    if (so->needs_parens(so->right())) append_string("(");
+    so->right()->perform(this);
+    if (so->needs_parens(so->right())) append_string(")");
+  }
+
+  void Inspect::operator()(Supports_Negation* sn)
+  {
+    append_token("not", sn);
+    append_mandatory_space();
+    if (sn->needs_parens(sn->condition())) append_string("(");
+    sn->condition()->perform(this);
+    if (sn->needs_parens(sn->condition())) append_string(")");
+  }
+
+  void Inspect::operator()(Supports_Declaration* sd)
+  {
+    append_string("(");
+    sd->feature()->perform(this);
+    append_string(": ");
+    sd->value()->perform(this);
+    append_string(")");
+  }
+
+  void Inspect::operator()(Supports_Interpolation* sd)
+  {
+    sd->value()->perform(this);
+  }
+
+  void Inspect::operator()(Media_Query* mq)
+  {
+    size_t i = 0;
+    if (mq->media_type()) {
+      if      (mq->is_negated())    append_string("not ");
+      else if (mq->is_restricted()) append_string("only ");
+      mq->media_type()->perform(this);
+    }
+    else {
+      (*mq)[i++]->perform(this);
+    }
+    for (size_t L = mq->length(); i < L; ++i) {
+      append_string(" and ");
+      (*mq)[i]->perform(this);
+    }
+  }
+
+  void Inspect::operator()(Media_Query_Expression* mqe)
+  {
+    if (mqe->is_interpolated()) {
+      mqe->feature()->perform(this);
+    }
+    else {
+      append_string("(");
+      mqe->feature()->perform(this);
+      if (mqe->value()) {
+        append_string(": "); // verified
+        mqe->value()->perform(this);
+      }
+      append_string(")");
+    }
+  }
+
+  void Inspect::operator()(At_Root_Expression* 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(")");
+    }
+  }
+
+  void Inspect::operator()(Null* 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);
+  }
+
+  // parameters and arguments
+  void Inspect::operator()(Parameter* p)
+  {
+    append_token(p->name(), p);
+    if (p->default_value()) {
+      append_colon_separator();
+      p->default_value()->perform(this);
+    }
+    else if (p->is_rest_parameter()) {
+      append_string("...");
+    }
+  }
+
+  void Inspect::operator()(Parameters* p)
+  {
+    append_string("(");
+    if (!p->empty()) {
+      (*p)[0]->perform(this);
+      for (size_t i = 1, L = p->length(); i < L; ++i) {
+        append_comma_separator();
+        (*p)[i]->perform(this);
+      }
+    }
+    append_string(")");
+  }
+
+  void Inspect::operator()(Argument* a)
+  {
+    if (!a->name().empty()) {
+      append_token(a->name(), a);
+      append_colon_separator();
+    }
+    // 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);
+    if (a->is_rest_argument()) {
+      append_string("...");
+    }
+  }
+
+  void Inspect::operator()(Arguments* a)
+  {
+    append_string("(");
+    if (!a->empty()) {
+      (*a)[0]->perform(this);
+      for (size_t i = 1, L = a->length(); i < L; ++i) {
+        append_string(", "); // verified
+        // Sass Bug? append_comma_separator();
+        (*a)[i]->perform(this);
+      }
+    }
+    append_string(")");
+  }
+
+  void Inspect::operator()(Selector_Schema* s)
+  {
+    s->contents()->perform(this);
+  }
+
+  void Inspect::operator()(Parent_Selector* p)
+  {
+    append_string("&");
+  }
+
+  void Inspect::operator()(Selector_Placeholder* s)
+  {
+    append_token(s->name(), s);
+    if (s->has_line_break()) append_optional_linefeed();
+    if (s->has_line_break()) append_indentation();
+
+  }
+
+  void Inspect::operator()(Type_Selector* s)
+  {
+    append_token(s->ns_name(), s);
+  }
+
+  void Inspect::operator()(Selector_Qualifier* 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)
+  {
+    append_string("[");
+    add_open_mapping(s);
+    append_token(s->ns_name(), s);
+    if (!s->matcher().empty()) {
+      append_string(s->matcher());
+      if (s->value()) {
+        s->value()->perform(this);
+      }
+    }
+    add_close_mapping(s);
+    append_string("]");
+  }
+
+  void Inspect::operator()(Pseudo_Selector* s)
+  {
+    append_token(s->ns_name(), s);
+    if (s->expression()) {
+      append_string("(");
+      s->expression()->perform(this);
+      append_string(")");
+    }
+  }
+
+  void Inspect::operator()(Wrapped_Selector* s)
+  {
+    bool was = in_wrapped;
+    in_wrapped = true;
+    append_token(s->name(), s);
+    append_string("(");
+    bool was_comma_array = in_comma_array;
+    in_comma_array = false;
+    s->selector()->perform(this);
+    in_comma_array = was_comma_array;
+    append_string(")");
+    in_wrapped = was;
+  }
+
+  void Inspect::operator()(Compound_Selector* 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) {
+        append_optional_linefeed();
+      }
+    }
+  }
+
+  void Inspect::operator()(Complex_Selector* c)
+  {
+    Compound_Selector*           head = c->head();
+    Complex_Selector*            tail = c->tail();
+    Complex_Selector::Combinator comb = c->combinator();
+
+    if (c->has_line_feed()) {
+      if (!(c->has_parent_ref())) {
+        append_optional_linefeed();
+        append_indentation();
+      }
+    }
+
+    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;
+
+    switch (comb) {
+      case Complex_Selector::ANCESTOR_OF:
+        if (is_tail) append_mandatory_space();
+      break;
+      case Complex_Selector::PARENT_OF:
+        append_optional_space();
+        append_string(">");
+        append_optional_space();
+      break;
+      case Complex_Selector::ADJACENT_TO:
+        append_optional_space();
+        append_string("+");
+        append_optional_space();
+      break;
+      case Complex_Selector::REFERENCE:
+        append_mandatory_space();
+        append_string("/");
+        c->reference()->perform(this);
+        append_string("/");
+        append_mandatory_space();
+      break;
+      case Complex_Selector::PRECEDES:
+        if (is_empty) append_optional_space();
+        else append_mandatory_space();
+        append_string("~");
+        if (tail) append_mandatory_space();
+        else append_optional_space();
+      break;
+    }
+    if (tail && comb != Complex_Selector::ANCESTOR_OF) {
+      if (c->has_line_break()) append_optional_linefeed();
+    }
+    if (tail) tail->perform(this);
+    if (!tail && c->has_line_break()) {
+      if (output_style() == SASS_STYLE_COMPACT) {
+        append_mandatory_space();
+      }
+    }
+  }
+
+  void Inspect::operator()(Selector_List* g)
+  {
+    if (g->empty()) return;
+
+    bool was_comma_array = in_comma_array;
+    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;
+      (*g)[i]->perform(this);
+      if (i < L - 1) {
+        scheduled_space = 0;
+        append_comma_separator();
+      }
+    }
+
+    in_comma_array = was_comma_array;
+    if (!in_declaration && in_comma_array) {
+      append_string(")");
+    }
+
+  }
+
+  void Inspect::fallback_impl(AST_Node* n)
+  {
+  }
+
+}
diff --git a/libsass/src/inspect.hpp b/libsass/src/inspect.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/inspect.hpp
@@ -0,0 +1,98 @@
+#ifndef SASS_INSPECT_H
+#define SASS_INSPECT_H
+
+#include "position.hpp"
+#include "operation.hpp"
+#include "emitter.hpp"
+
+namespace Sass {
+  class Context;
+
+  class Inspect : public Operation_CRTP<void, Inspect>, public Emitter {
+  protected:
+    // import all the class-specific methods and override as desired
+    using Operation_CRTP<void, Inspect>::operator();
+
+    void fallback_impl(AST_Node* n);
+
+  public:
+
+    Inspect(Emitter emi);
+    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*);
+    // 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);
+    // parameters and arguments
+    virtual void operator()(Parameter*);
+    virtual void operator()(Parameters*);
+    virtual void operator()(Argument*);
+    virtual void operator()(Arguments*);
+    // selectors
+    virtual void operator()(Selector_Schema*);
+    virtual void operator()(Selector_Placeholder*);
+    virtual void operator()(Type_Selector*);
+    virtual void operator()(Selector_Qualifier*);
+    virtual void operator()(Attribute_Selector*);
+    virtual void operator()(Pseudo_Selector*);
+    virtual void operator()(Wrapped_Selector*);
+    virtual void operator()(Compound_Selector*);
+    virtual void operator()(Complex_Selector*);
+    virtual void operator()(Selector_List*);
+
+    // template <typename U>
+    // void fallback(U x) { fallback_impl(reinterpret_cast<AST_Node*>(x)); }
+  };
+
+}
+#endif
diff --git a/libsass/src/json.cpp b/libsass/src/json.cpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/json.cpp
@@ -0,0 +1,1398 @@
+/*
+  Copyright (C) 2011 Joseph A. Adams (joeyadams3.14159@gmail.com)
+  All rights reserved.
+
+  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 the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+  THE SOFTWARE.
+*/
+
+#ifdef _MSC_VER
+#define _CRT_SECURE_NO_WARNINGS
+#define _CRT_NONSTDC_NO_DEPRECATE
+#endif
+
+#include "json.hpp"
+
+#include <assert.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(_MSC_VER) && _MSC_VER < 1900
+#include <stdarg.h>
+#ifdef snprintf
+#undef snprintf
+#endif
+extern "C" int snprintf(char *, size_t, const char *, ...);
+#endif
+
+#define out_of_memory() do {                    \
+    fprintf(stderr, "Out of memory.\n");    \
+    exit(EXIT_FAILURE);                     \
+  } while (0)
+
+/* Sadly, strdup is not portable. */
+static char *json_strdup(const char *str)
+{
+  char *ret = (char*) malloc(strlen(str) + 1);
+  if (ret == NULL)
+    out_of_memory();
+  strcpy(ret, str);
+  return ret;
+}
+
+/* String buffer */
+
+typedef struct
+{
+  char *cur;
+  char *end;
+  char *start;
+} SB;
+
+static void sb_init(SB *sb)
+{
+  sb->start = (char*) malloc(17);
+  if (sb->start == NULL)
+    out_of_memory();
+  sb->cur = sb->start;
+  sb->end = sb->start + 16;
+}
+
+/* sb and need may be evaluated multiple times. */
+#define sb_need(sb, need) do {                  \
+    if ((sb)->end - (sb)->cur < (need))     \
+      sb_grow(sb, need);                  \
+  } while (0)
+
+static void sb_grow(SB *sb, int need)
+{
+  size_t length = sb->cur - sb->start;
+  size_t alloc = sb->end - sb->start;
+
+  do {
+    alloc *= 2;
+  } while (alloc < length + need);
+
+  sb->start = (char*) realloc(sb->start, alloc + 1);
+  if (sb->start == NULL)
+    out_of_memory();
+  sb->cur = sb->start + length;
+  sb->end = sb->start + alloc;
+}
+
+static void sb_put(SB *sb, const char *bytes, int count)
+{
+  sb_need(sb, count);
+  memcpy(sb->cur, bytes, count);
+  sb->cur += count;
+}
+
+#define sb_putc(sb, c) do {         \
+    if ((sb)->cur >= (sb)->end) \
+      sb_grow(sb, 1);         \
+    *(sb)->cur++ = (c);         \
+  } while (0)
+
+static void sb_puts(SB *sb, const char *str)
+{
+  sb_put(sb, str, (int)strlen(str));
+}
+
+static char *sb_finish(SB *sb)
+{
+  *sb->cur = 0;
+  assert(sb->start <= sb->cur && strlen(sb->start) == (size_t)(sb->cur - sb->start));
+  return sb->start;
+}
+
+static void sb_free(SB *sb)
+{
+  free(sb->start);
+}
+
+/*
+ * Unicode helper functions
+ *
+ * These are taken from the ccan/charset module and customized a bit.
+ * Putting them here means the compiler can (choose to) inline them,
+ * and it keeps ccan/json from having a dependency.
+ *
+ * We use uint32_t Type for Unicode codepoints.
+ * We need our own because wchar_t might be 16 bits.
+ */
+
+/*
+ * Validate a single UTF-8 character starting at @s.
+ * The string must be null-terminated.
+ *
+ * If it's valid, return its length (1 thru 4).
+ * If it's invalid or clipped, return 0.
+ *
+ * This function implements the syntax given in RFC3629, which is
+ * the same as that given in The Unicode Standard, Version 6.0.
+ *
+ * It has the following properties:
+ *
+ *  * All codepoints U+0000..U+10FFFF may be encoded,
+ *    except for U+D800..U+DFFF, which are reserved
+ *    for UTF-16 surrogate pair encoding.
+ *  * UTF-8 byte sequences longer than 4 bytes are not permitted,
+ *    as they exceed the range of Unicode.
+ *  * The sixty-six Unicode "non-characters" are permitted
+ *    (namely, U+FDD0..U+FDEF, U+xxFFFE, and U+xxFFFF).
+ */
+static int utf8_validate_cz(const char *s)
+{
+  unsigned char c = *s++;
+
+  if (c <= 0x7F) {        /* 00..7F */
+    return 1;
+  } else if (c <= 0xC1) { /* 80..C1 */
+    /* Disallow overlong 2-byte sequence. */
+    return 0;
+  } else if (c <= 0xDF) { /* C2..DF */
+    /* Make sure subsequent byte is in the range 0x80..0xBF. */
+    if (((unsigned char)*s++ & 0xC0) != 0x80)
+      return 0;
+
+    return 2;
+  } else if (c <= 0xEF) { /* E0..EF */
+    /* Disallow overlong 3-byte sequence. */
+    if (c == 0xE0 && (unsigned char)*s < 0xA0)
+      return 0;
+
+    /* Disallow U+D800..U+DFFF. */
+    if (c == 0xED && (unsigned char)*s > 0x9F)
+      return 0;
+
+    /* Make sure subsequent bytes are in the range 0x80..0xBF. */
+    if (((unsigned char)*s++ & 0xC0) != 0x80)
+      return 0;
+    if (((unsigned char)*s++ & 0xC0) != 0x80)
+      return 0;
+
+    return 3;
+  } else if (c <= 0xF4) { /* F0..F4 */
+    /* Disallow overlong 4-byte sequence. */
+    if (c == 0xF0 && (unsigned char)*s < 0x90)
+      return 0;
+
+    /* Disallow codepoints beyond U+10FFFF. */
+    if (c == 0xF4 && (unsigned char)*s > 0x8F)
+      return 0;
+
+    /* Make sure subsequent bytes are in the range 0x80..0xBF. */
+    if (((unsigned char)*s++ & 0xC0) != 0x80)
+      return 0;
+    if (((unsigned char)*s++ & 0xC0) != 0x80)
+      return 0;
+    if (((unsigned char)*s++ & 0xC0) != 0x80)
+      return 0;
+
+    return 4;
+  } else {                /* F5..FF */
+    return 0;
+  }
+}
+
+/* Validate a null-terminated UTF-8 string. */
+static bool utf8_validate(const char *s)
+{
+  int len;
+
+  for (; *s != 0; s += len) {
+    len = utf8_validate_cz(s);
+    if (len == 0)
+      return false;
+  }
+
+  return true;
+}
+
+/*
+ * Read a single UTF-8 character starting at @s,
+ * returning the length, in bytes, of the character read.
+ *
+ * This function assumes input is valid UTF-8,
+ * and that there are enough characters in front of @s.
+ */
+static int utf8_read_char(const char *s, uint32_t *out)
+{
+  const unsigned char *c = (const unsigned char*) s;
+
+  assert(utf8_validate_cz(s));
+
+  if (c[0] <= 0x7F) {
+    /* 00..7F */
+    *out = c[0];
+    return 1;
+  } else if (c[0] <= 0xDF) {
+    /* C2..DF (unless input is invalid) */
+    *out = ((uint32_t)c[0] & 0x1F) << 6 |
+           ((uint32_t)c[1] & 0x3F);
+    return 2;
+  } else if (c[0] <= 0xEF) {
+    /* E0..EF */
+    *out = ((uint32_t)c[0] &  0xF) << 12 |
+           ((uint32_t)c[1] & 0x3F) << 6  |
+           ((uint32_t)c[2] & 0x3F);
+    return 3;
+  } else {
+    /* F0..F4 (unless input is invalid) */
+    *out = ((uint32_t)c[0] &  0x7) << 18 |
+           ((uint32_t)c[1] & 0x3F) << 12 |
+           ((uint32_t)c[2] & 0x3F) << 6  |
+           ((uint32_t)c[3] & 0x3F);
+    return 4;
+  }
+}
+
+/*
+ * Write a single UTF-8 character to @s,
+ * returning the length, in bytes, of the character written.
+ *
+ * @unicode must be U+0000..U+10FFFF, but not U+D800..U+DFFF.
+ *
+ * This function will write up to 4 bytes to @out.
+ */
+static int utf8_write_char(uint32_t unicode, char *out)
+{
+  unsigned char *o = (unsigned char*) out;
+
+  assert(unicode <= 0x10FFFF && !(unicode >= 0xD800 && unicode <= 0xDFFF));
+
+  if (unicode <= 0x7F) {
+    /* U+0000..U+007F */
+    *o++ = unicode;
+    return 1;
+  } else if (unicode <= 0x7FF) {
+    /* U+0080..U+07FF */
+    *o++ = 0xC0 | unicode >> 6;
+    *o++ = 0x80 | (unicode & 0x3F);
+    return 2;
+  } else if (unicode <= 0xFFFF) {
+    /* U+0800..U+FFFF */
+    *o++ = 0xE0 | unicode >> 12;
+    *o++ = 0x80 | (unicode >> 6 & 0x3F);
+    *o++ = 0x80 | (unicode & 0x3F);
+    return 3;
+  } else {
+    /* U+10000..U+10FFFF */
+    *o++ = 0xF0 | unicode >> 18;
+    *o++ = 0x80 | (unicode >> 12 & 0x3F);
+    *o++ = 0x80 | (unicode >> 6 & 0x3F);
+    *o++ = 0x80 | (unicode & 0x3F);
+    return 4;
+  }
+}
+
+/*
+ * Compute the Unicode codepoint of a UTF-16 surrogate pair.
+ *
+ * @uc should be 0xD800..0xDBFF, and @lc should be 0xDC00..0xDFFF.
+ * If they aren't, this function returns false.
+ */
+static bool from_surrogate_pair(uint16_t uc, uint16_t lc, uint32_t *unicode)
+{
+  if (uc >= 0xD800 && uc <= 0xDBFF && lc >= 0xDC00 && lc <= 0xDFFF) {
+    *unicode = 0x10000 + ((((uint32_t)uc & 0x3FF) << 10) | (lc & 0x3FF));
+    return true;
+  } else {
+    return false;
+  }
+}
+
+/*
+ * Construct a UTF-16 surrogate pair given a Unicode codepoint.
+ *
+ * @unicode must be U+10000..U+10FFFF.
+ */
+static void to_surrogate_pair(uint32_t unicode, uint16_t *uc, uint16_t *lc)
+{
+  uint32_t n;
+
+  assert(unicode >= 0x10000 && unicode <= 0x10FFFF);
+
+  n = unicode - 0x10000;
+  *uc = ((n >> 10) & 0x3FF) | 0xD800;
+  *lc = (n & 0x3FF) | 0xDC00;
+}
+
+static bool is_space        (const char *c);
+static bool is_digit        (const char *c);
+static bool parse_value     (const char **sp, JsonNode        **out);
+static bool parse_string    (const char **sp, char            **out);
+static bool parse_number    (const char **sp, double           *out);
+static bool parse_array     (const char **sp, JsonNode        **out);
+static bool parse_object    (const char **sp, JsonNode        **out);
+static bool parse_hex16     (const char **sp, uint16_t         *out);
+
+static bool expect_literal  (const char **sp, const char *str);
+static void skip_space      (const char **sp);
+
+static void emit_value              (SB *out, const JsonNode *node);
+static void emit_value_indented     (SB *out, const JsonNode *node, const char *space, int indent_level);
+static void emit_string             (SB *out, const char *str);
+static void emit_number             (SB *out, double num);
+static void emit_array              (SB *out, const JsonNode *array);
+static void emit_array_indented     (SB *out, const JsonNode *array, const char *space, int indent_level);
+static void emit_object             (SB *out, const JsonNode *object);
+static void emit_object_indented    (SB *out, const JsonNode *object, const char *space, int indent_level);
+
+static int write_hex16(char *out, uint16_t val);
+
+static JsonNode *mknode(JsonTag tag);
+static void append_node(JsonNode *parent, JsonNode *child);
+static void prepend_node(JsonNode *parent, JsonNode *child);
+static void append_member(JsonNode *object, char *key, JsonNode *value);
+
+/* Assertion-friendly validity checks */
+static bool tag_is_valid(unsigned int tag);
+static bool number_is_valid(const char *num);
+
+JsonNode *json_decode(const char *json)
+{
+  const char *s = json;
+  JsonNode *ret;
+
+  skip_space(&s);
+  if (!parse_value(&s, &ret))
+    return NULL;
+
+  skip_space(&s);
+  if (*s != 0) {
+    json_delete(ret);
+    return NULL;
+  }
+
+  return ret;
+}
+
+char *json_encode(const JsonNode *node)
+{
+  return json_stringify(node, NULL);
+}
+
+char *json_encode_string(const char *str)
+{
+  SB sb;
+  sb_init(&sb);
+
+  emit_string(&sb, str);
+
+  return sb_finish(&sb);
+}
+
+char *json_stringify(const JsonNode *node, const char *space)
+{
+  SB sb;
+  sb_init(&sb);
+
+  if (space != NULL)
+    emit_value_indented(&sb, node, space, 0);
+  else
+    emit_value(&sb, node);
+
+  return sb_finish(&sb);
+}
+
+void json_delete(JsonNode *node)
+{
+  if (node != NULL) {
+    json_remove_from_parent(node);
+
+    switch (node->tag) {
+      case JSON_STRING:
+        free(node->string_);
+        break;
+      case JSON_ARRAY:
+      case JSON_OBJECT:
+      {
+        JsonNode *child, *next;
+        for (child = node->children.head; child != NULL; child = next) {
+          next = child->next;
+          json_delete(child);
+        }
+        break;
+      }
+      default:;
+    }
+
+    free(node);
+  }
+}
+
+bool json_validate(const char *json)
+{
+  const char *s = json;
+
+  skip_space(&s);
+  if (!parse_value(&s, NULL))
+    return false;
+
+  skip_space(&s);
+  if (*s != 0)
+    return false;
+
+  return true;
+}
+
+JsonNode *json_find_element(JsonNode *array, int index)
+{
+  JsonNode *element;
+  int i = 0;
+
+  if (array == NULL || array->tag != JSON_ARRAY)
+    return NULL;
+
+  json_foreach(element, array) {
+    if (i == index)
+      return element;
+    i++;
+  }
+
+  return NULL;
+}
+
+JsonNode *json_find_member(JsonNode *object, const char *name)
+{
+  JsonNode *member;
+
+  if (object == NULL || object->tag != JSON_OBJECT)
+    return NULL;
+
+  json_foreach(member, object)
+    if (strcmp(member->key, name) == 0)
+      return member;
+
+  return NULL;
+}
+
+JsonNode *json_first_child(const JsonNode *node)
+{
+  if (node != NULL && (node->tag == JSON_ARRAY || node->tag == JSON_OBJECT))
+    return node->children.head;
+  return NULL;
+}
+
+static JsonNode *mknode(JsonTag tag)
+{
+  JsonNode *ret = (JsonNode*) calloc(1, sizeof(JsonNode));
+  if (ret == NULL)
+    out_of_memory();
+  ret->tag = tag;
+  return ret;
+}
+
+JsonNode *json_mknull(void)
+{
+  return mknode(JSON_NULL);
+}
+
+JsonNode *json_mkbool(bool b)
+{
+  JsonNode *ret = mknode(JSON_BOOL);
+  ret->bool_ = b;
+  return ret;
+}
+
+static JsonNode *mkstring(char *s)
+{
+  JsonNode *ret = mknode(JSON_STRING);
+  ret->string_ = s;
+  return ret;
+}
+
+JsonNode *json_mkstring(const char *s)
+{
+  return mkstring(json_strdup(s));
+}
+
+JsonNode *json_mknumber(double n)
+{
+  JsonNode *node = mknode(JSON_NUMBER);
+  node->number_ = n;
+  return node;
+}
+
+JsonNode *json_mkarray(void)
+{
+  return mknode(JSON_ARRAY);
+}
+
+JsonNode *json_mkobject(void)
+{
+  return mknode(JSON_OBJECT);
+}
+
+static void append_node(JsonNode *parent, JsonNode *child)
+{
+  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;
+}
+
+static void prepend_node(JsonNode *parent, JsonNode *child)
+{
+  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;
+}
+
+static void append_member(JsonNode *object, char *key, JsonNode *value)
+{
+  value->key = key;
+  append_node(object, value);
+}
+
+void json_append_element(JsonNode *array, JsonNode *element)
+{
+  assert(array->tag == JSON_ARRAY);
+  assert(element->parent == NULL);
+
+  append_node(array, element);
+}
+
+void json_prepend_element(JsonNode *array, JsonNode *element)
+{
+  assert(array->tag == JSON_ARRAY);
+  assert(element->parent == NULL);
+
+  prepend_node(array, element);
+}
+
+void json_append_member(JsonNode *object, const char *key, JsonNode *value)
+{
+  assert(object->tag == JSON_OBJECT);
+  assert(value->parent == NULL);
+
+  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);
+
+  value->key = json_strdup(key);
+  prepend_node(object, value);
+}
+
+void json_remove_from_parent(JsonNode *node)
+{
+  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;
+
+    free(node->key);
+
+    node->parent = NULL;
+    node->prev = node->next = NULL;
+    node->key = NULL;
+  }
+}
+
+static bool parse_value(const char **sp, JsonNode **out)
+{
+  const char *s = *sp;
+
+  switch (*s) {
+    case 'n':
+      if (expect_literal(&s, "null")) {
+        if (out)
+          *out = json_mknull();
+        *sp = s;
+        return true;
+      }
+      return false;
+
+    case 'f':
+      if (expect_literal(&s, "false")) {
+        if (out)
+          *out = json_mkbool(false);
+        *sp = s;
+        return true;
+      }
+      return false;
+
+    case 't':
+      if (expect_literal(&s, "true")) {
+        if (out)
+          *out = json_mkbool(true);
+        *sp = s;
+        return true;
+      }
+      return false;
+
+    case '"': {
+      char *str = NULL;
+      if (parse_string(&s, out ? &str : NULL)) {
+        if (out)
+          *out = mkstring(str);
+        *sp = s;
+        return true;
+      }
+      return false;
+    }
+
+    case '[':
+      if (parse_array(&s, out)) {
+        *sp = s;
+        return true;
+      }
+      return false;
+
+    case '{':
+      if (parse_object(&s, out)) {
+        *sp = s;
+        return true;
+      }
+      return false;
+
+    default: {
+      double num;
+      if (parse_number(&s, out ? &num : NULL)) {
+        if (out)
+          *out = json_mknumber(num);
+        *sp = s;
+        return true;
+      }
+      return false;
+    }
+  }
+}
+
+static bool parse_array(const char **sp, JsonNode **out)
+{
+  const char *s = *sp;
+  JsonNode *ret = out ? json_mkarray() : NULL;
+  JsonNode *element = NULL;
+
+  if (*s++ != '[')
+    goto failure;
+  skip_space(&s);
+
+  if (*s == ']') {
+    s++;
+    goto success;
+  }
+
+  for (;;) {
+    if (!parse_value(&s, out ? &element : NULL))
+      goto failure;
+    skip_space(&s);
+
+    if (out)
+      json_append_element(ret, element);
+
+    if (*s == ']') {
+      s++;
+      goto success;
+    }
+
+    if (*s++ != ',')
+      goto failure;
+    skip_space(&s);
+  }
+
+success:
+  *sp = s;
+  if (out)
+    *out = ret;
+  return true;
+
+failure:
+  json_delete(ret);
+  return false;
+}
+
+static bool parse_object(const char **sp, JsonNode **out)
+{
+  const char *s = *sp;
+  JsonNode *ret = out ? json_mkobject() : NULL;
+  char *key = NULL;
+  JsonNode *value = NULL;
+
+  if (*s++ != '{')
+    goto failure;
+  skip_space(&s);
+
+  if (*s == '}') {
+    s++;
+    goto success;
+  }
+
+  for (;;) {
+    if (!parse_string(&s, out ? &key : NULL))
+      goto failure;
+    skip_space(&s);
+
+    if (*s++ != ':')
+      goto failure_free_key;
+    skip_space(&s);
+
+    if (!parse_value(&s, out ? &value : NULL))
+      goto failure_free_key;
+    skip_space(&s);
+
+    if (out)
+      append_member(ret, key, value);
+
+    if (*s == '}') {
+      s++;
+      goto success;
+    }
+
+    if (*s++ != ',')
+      goto failure;
+    skip_space(&s);
+  }
+
+success:
+  *sp = s;
+  if (out)
+    *out = ret;
+  return true;
+
+failure_free_key:
+  if (out)
+    free(key);
+failure:
+  json_delete(ret);
+  return false;
+}
+
+bool parse_string(const char **sp, char **out)
+{
+  const char *s = *sp;
+  SB sb = { 0, 0, 0 };
+  char throwaway_buffer[4];
+    /* enough space for a UTF-8 character */
+  char *b;
+
+  if (*s++ != '"')
+    return false;
+
+  if (out) {
+    sb_init(&sb);
+    sb_need(&sb, 4);
+    b = sb.cur;
+  } else {
+    b = throwaway_buffer;
+  }
+
+  while (*s != '"') {
+    unsigned char c = *s++;
+
+    /* Parse next character, and write it to b. */
+    if (c == '\\') {
+      c = *s++;
+      switch (c) {
+        case '"':
+        case '\\':
+        case '/':
+          *b++ = c;
+          break;
+        case 'b':
+          *b++ = '\b';
+          break;
+        case 'f':
+          *b++ = '\f';
+          break;
+        case 'n':
+          *b++ = '\n';
+          break;
+        case 'r':
+          *b++ = '\r';
+          break;
+        case 't':
+          *b++ = '\t';
+          break;
+        case 'u':
+        {
+          uint16_t uc, lc;
+          uint32_t unicode;
+
+          if (!parse_hex16(&s, &uc))
+            goto failed;
+
+          if (uc >= 0xD800 && uc <= 0xDFFF) {
+            /* Handle UTF-16 surrogate pair. */
+            if (*s++ != '\\' || *s++ != 'u' || !parse_hex16(&s, &lc))
+              goto failed; /* Incomplete surrogate pair. */
+            if (!from_surrogate_pair(uc, lc, &unicode))
+              goto failed; /* Invalid surrogate pair. */
+          } else if (uc == 0) {
+            /* Disallow "\u0000". */
+            goto failed;
+          } else {
+            unicode = uc;
+          }
+
+          b += utf8_write_char(unicode, b);
+          break;
+        }
+        default:
+          /* Invalid escape */
+          goto failed;
+      }
+    } else if (c <= 0x1F) {
+      /* Control characters are not allowed in string literals. */
+      goto failed;
+    } else {
+      /* Validate and echo a UTF-8 character. */
+      int len;
+
+      s--;
+      len = utf8_validate_cz(s);
+      if (len == 0)
+        goto failed; /* Invalid UTF-8 character. */
+
+      while (len--)
+        *b++ = *s++;
+    }
+
+    /*
+     * Update sb to know about the new bytes,
+     * and set up b to write another character.
+     */
+    if (out) {
+      sb.cur = b;
+      sb_need(&sb, 4);
+      b = sb.cur;
+    } else {
+      b = throwaway_buffer;
+    }
+  }
+  s++;
+
+  if (out)
+    *out = sb_finish(&sb);
+  *sp = s;
+  return true;
+
+failed:
+  if (out)
+    sb_free(&sb);
+  return false;
+}
+
+bool is_space(const char *c) {
+  return ((*c) == '\t' || (*c) == '\n' || (*c) == '\r' || (*c) == ' ');
+}
+
+bool is_digit(const char *c){
+  return ((*c) >= '0' && (*c) <= '9');
+}
+
+/*
+ * The JSON spec says that a number shall follow this precise pattern
+ * (spaces and quotes added for readability):
+ *   '-'? (0 | [1-9][0-9]*) ('.' [0-9]+)? ([Ee] [+-]? [0-9]+)?
+ *
+ * However, some JSON parsers are more liberal.  For instance, PHP accepts
+ * '.5' and '1.'.  JSON.parse accepts '+3'.
+ *
+ * This function takes the strict approach.
+ */
+bool parse_number(const char **sp, double *out)
+{
+  const char *s = *sp;
+
+  /* '-'? */
+  if (*s == '-')
+    s++;
+
+  /* (0 | [1-9][0-9]*) */
+  if (*s == '0') {
+    s++;
+  } else {
+    if (!is_digit(s))
+      return false;
+    do {
+      s++;
+    } while (is_digit(s));
+  }
+
+  /* ('.' [0-9]+)? */
+  if (*s == '.') {
+    s++;
+    if (!is_digit(s))
+      return false;
+    do {
+      s++;
+    } while (is_digit(s));
+  }
+
+  /* ([Ee] [+-]? [0-9]+)? */
+  if (*s == 'E' || *s == 'e') {
+    s++;
+    if (*s == '+' || *s == '-')
+      s++;
+    if (!is_digit(s))
+      return false;
+    do {
+      s++;
+    } while (is_digit(s));
+  }
+
+  if (out)
+    *out = strtod(*sp, NULL);
+
+  *sp = s;
+  return true;
+}
+
+static void skip_space(const char **sp)
+{
+  const char *s = *sp;
+  while (is_space(s))
+    s++;
+  *sp = s;
+}
+
+static void emit_value(SB *out, const JsonNode *node)
+{
+  assert(tag_is_valid(node->tag));
+  switch (node->tag) {
+    case JSON_NULL:
+      sb_puts(out, "null");
+      break;
+    case JSON_BOOL:
+      sb_puts(out, node->bool_ ? "true" : "false");
+      break;
+    case JSON_STRING:
+      emit_string(out, node->string_);
+      break;
+    case JSON_NUMBER:
+      emit_number(out, node->number_);
+      break;
+    case JSON_ARRAY:
+      emit_array(out, node);
+      break;
+    case JSON_OBJECT:
+      emit_object(out, node);
+      break;
+    default:
+      assert(false);
+  }
+}
+
+void emit_value_indented(SB *out, const JsonNode *node, const char *space, int indent_level)
+{
+  assert(tag_is_valid(node->tag));
+  switch (node->tag) {
+    case JSON_NULL:
+      sb_puts(out, "null");
+      break;
+    case JSON_BOOL:
+      sb_puts(out, node->bool_ ? "true" : "false");
+      break;
+    case JSON_STRING:
+      emit_string(out, node->string_);
+      break;
+    case JSON_NUMBER:
+      emit_number(out, node->number_);
+      break;
+    case JSON_ARRAY:
+      emit_array_indented(out, node, space, indent_level);
+      break;
+    case JSON_OBJECT:
+      emit_object_indented(out, node, space, indent_level);
+      break;
+    default:
+      assert(false);
+  }
+}
+
+static void emit_array(SB *out, const JsonNode *array)
+{
+  const JsonNode *element;
+
+  sb_putc(out, '[');
+  json_foreach(element, array) {
+    emit_value(out, element);
+    if (element->next != NULL)
+      sb_putc(out, ',');
+  }
+  sb_putc(out, ']');
+}
+
+static void emit_array_indented(SB *out, const JsonNode *array, const char *space, int indent_level)
+{
+  const JsonNode *element = array->children.head;
+  int i;
+
+  if (element == NULL) {
+    sb_puts(out, "[]");
+    return;
+  }
+
+  sb_puts(out, "[\n");
+  while (element != NULL) {
+    for (i = 0; i < indent_level + 1; i++)
+      sb_puts(out, space);
+    emit_value_indented(out, element, space, indent_level + 1);
+
+    element = element->next;
+    sb_puts(out, element != NULL ? ",\n" : "\n");
+  }
+  for (i = 0; i < indent_level; i++)
+    sb_puts(out, space);
+  sb_putc(out, ']');
+}
+
+static void emit_object(SB *out, const JsonNode *object)
+{
+  const JsonNode *member;
+
+  sb_putc(out, '{');
+  json_foreach(member, object) {
+    emit_string(out, member->key);
+    sb_putc(out, ':');
+    emit_value(out, member);
+    if (member->next != NULL)
+      sb_putc(out, ',');
+  }
+  sb_putc(out, '}');
+}
+
+static void emit_object_indented(SB *out, const JsonNode *object, const char *space, int indent_level)
+{
+  const JsonNode *member = object->children.head;
+  int i;
+
+  if (member == NULL) {
+    sb_puts(out, "{}");
+    return;
+  }
+
+  sb_puts(out, "{\n");
+  while (member != NULL) {
+    for (i = 0; i < indent_level + 1; i++)
+      sb_puts(out, space);
+    emit_string(out, member->key);
+    sb_puts(out, ": ");
+    emit_value_indented(out, member, space, indent_level + 1);
+
+    member = member->next;
+    sb_puts(out, member != NULL ? ",\n" : "\n");
+  }
+  for (i = 0; i < indent_level; i++)
+    sb_puts(out, space);
+  sb_putc(out, '}');
+}
+
+void emit_string(SB *out, const char *str)
+{
+  bool escape_unicode = false;
+  const char *s = str;
+  char *b;
+
+  assert(utf8_validate(str));
+
+  /*
+   * 14 bytes is enough space to write up to two
+   * \uXXXX escapes and two quotation marks.
+   */
+  sb_need(out, 14);
+  b = out->cur;
+
+  *b++ = '"';
+  while (*s != 0) {
+    unsigned char c = *s++;
+
+    /* Encode the next character, and write it to b. */
+    switch (c) {
+      case '"':
+        *b++ = '\\';
+        *b++ = '"';
+        break;
+      case '\\':
+        *b++ = '\\';
+        *b++ = '\\';
+        break;
+      case '\b':
+        *b++ = '\\';
+        *b++ = 'b';
+        break;
+      case '\f':
+        *b++ = '\\';
+        *b++ = 'f';
+        break;
+      case '\n':
+        *b++ = '\\';
+        *b++ = 'n';
+        break;
+      case '\r':
+        *b++ = '\\';
+        *b++ = 'r';
+        break;
+      case '\t':
+        *b++ = '\\';
+        *b++ = 't';
+        break;
+      default: {
+        int len;
+
+        s--;
+        len = utf8_validate_cz(s);
+
+        if (len == 0) {
+          /*
+           * Handle invalid UTF-8 character gracefully in production
+           * by writing a replacement character (U+FFFD)
+           * and skipping a single byte.
+           *
+           * This should never happen when assertions are enabled
+           * due to the assertion at the beginning of this function.
+           */
+          assert(false);
+          if (escape_unicode) {
+            strcpy(b, "\\uFFFD");
+            b += 6;
+          } else {
+            *b++ = 0xEFu;
+            *b++ = 0xBFu;
+            *b++ = 0xBDu;
+          }
+          s++;
+        } else if (c < 0x1F || (c >= 0x80 && escape_unicode)) {
+          /* Encode using \u.... */
+          uint32_t unicode;
+
+          s += utf8_read_char(s, &unicode);
+
+          if (unicode <= 0xFFFF) {
+            *b++ = '\\';
+            *b++ = 'u';
+            b += write_hex16(b, unicode);
+          } else {
+            /* Produce a surrogate pair. */
+            uint16_t uc, lc;
+            assert(unicode <= 0x10FFFF);
+            to_surrogate_pair(unicode, &uc, &lc);
+            *b++ = '\\';
+            *b++ = 'u';
+            b += write_hex16(b, uc);
+            *b++ = '\\';
+            *b++ = 'u';
+            b += write_hex16(b, lc);
+          }
+        } else {
+          /* Write the character directly. */
+          while (len--)
+            *b++ = *s++;
+        }
+
+        break;
+      }
+    }
+
+    /*
+     * Update *out to know about the new bytes,
+     * and set up b to write another encoded character.
+     */
+    out->cur = b;
+    sb_need(out, 14);
+    b = out->cur;
+  }
+  *b++ = '"';
+
+  out->cur = b;
+}
+
+static void emit_number(SB *out, double num)
+{
+  /*
+   * This isn't exactly how JavaScript renders numbers,
+   * but it should produce valid JSON for reasonable numbers
+   * preserve precision well enough, and avoid some oddities
+   * like 0.3 -> 0.299999999999999988898 .
+   */
+  char buf[64];
+  sprintf(buf, "%.16g", num);
+
+  if (number_is_valid(buf))
+    sb_puts(out, buf);
+  else
+    sb_puts(out, "null");
+}
+
+static bool tag_is_valid(unsigned int tag)
+{
+  return (/* tag >= JSON_NULL && */ tag <= JSON_OBJECT);
+}
+
+static bool number_is_valid(const char *num)
+{
+  return (parse_number(&num, NULL) && *num == '\0');
+}
+
+static bool expect_literal(const char **sp, const char *str)
+{
+  const char *s = *sp;
+
+  while (*str != '\0')
+    if (*s++ != *str++)
+      return false;
+
+  *sp = s;
+  return true;
+}
+
+/*
+ * Parses exactly 4 hex characters (capital or lowercase).
+ * Fails if any input chars are not [0-9A-Fa-f].
+ */
+static bool parse_hex16(const char **sp, uint16_t *out)
+{
+  const char *s = *sp;
+  uint16_t ret = 0;
+  uint16_t i;
+  uint16_t tmp;
+  char c;
+
+  for (i = 0; i < 4; i++) {
+    c = *s++;
+    if (c >= '0' && c <= '9')
+      tmp = c - '0';
+    else if (c >= 'A' && c <= 'F')
+      tmp = c - 'A' + 10;
+    else if (c >= 'a' && c <= 'f')
+      tmp = c - 'a' + 10;
+    else
+      return false;
+
+    ret <<= 4;
+    ret += tmp;
+  }
+
+  if (out)
+    *out = ret;
+  *sp = s;
+  return true;
+}
+
+/*
+ * Encodes a 16-bit number into hexadecimal,
+ * writing exactly 4 hex chars.
+ */
+static int write_hex16(char *out, uint16_t val)
+{
+  const char *hex = "0123456789ABCDEF";
+
+  *out++ = hex[(val >> 12) & 0xF];
+  *out++ = hex[(val >> 8)  & 0xF];
+  *out++ = hex[(val >> 4)  & 0xF];
+  *out++ = hex[ val        & 0xF];
+
+  return 4;
+}
+
+bool json_check(const JsonNode *node, char errmsg[256])
+{
+  #define problem(...) do { \
+      if (errmsg != NULL) \
+        snprintf(errmsg, 256, __VA_ARGS__); \
+      return false; \
+    } while (0)
+
+  if (node->key != NULL && !utf8_validate(node->key))
+    problem("key contains invalid UTF-8");
+
+  if (!tag_is_valid(node->tag))
+    problem("tag is invalid (%u)", node->tag);
+
+  if (node->tag == JSON_BOOL) {
+    if (node->bool_ != false && node->bool_ != true)
+      problem("bool_ is neither false (%d) nor true (%d)", (int)false, (int)true);
+  } else if (node->tag == JSON_STRING) {
+    if (node->string_ == NULL)
+      problem("string_ is NULL");
+    if (!utf8_validate(node->string_))
+      problem("string_ contains invalid UTF-8");
+  } else if (node->tag == JSON_ARRAY || node->tag == JSON_OBJECT) {
+    JsonNode *head = node->children.head;
+    JsonNode *tail = node->children.tail;
+
+    if (head == NULL || tail == NULL) {
+      if (head != NULL)
+        problem("tail is NULL, but head is not");
+      if (tail != NULL)
+        problem("head is NULL, but tail is not");
+    } else {
+      JsonNode *child;
+      JsonNode *last = NULL;
+
+      if (head->prev != NULL)
+        problem("First child's prev pointer is not NULL");
+
+      for (child = head; child != NULL; last = child, child = child->next) {
+        if (child == node)
+          problem("node is its own child");
+        if (child->next == child)
+          problem("child->next == child (cycle)");
+        if (child->next == head)
+          problem("child->next == head (cycle)");
+
+        if (child->parent != node)
+          problem("child does not point back to parent");
+        if (child->next != NULL && child->next->prev != child)
+          problem("child->next does not point back to child");
+
+        if (node->tag == JSON_ARRAY && child->key != NULL)
+          problem("Array element's key is not NULL");
+        if (node->tag == JSON_OBJECT && child->key == NULL)
+          problem("Object member's key is NULL");
+
+        if (!json_check(child, errmsg))
+          return false;
+      }
+
+      if (last != tail)
+        problem("tail does not match pointer found by starting at head and following next links");
+    }
+  }
+
+  return true;
+
+  #undef problem
+}
diff --git a/libsass/src/json.hpp b/libsass/src/json.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/json.hpp
@@ -0,0 +1,117 @@
+/*
+  Copyright (C) 2011 Joseph A. Adams (joeyadams3.14159@gmail.com)
+  All rights reserved.
+
+  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 the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+  THE SOFTWARE.
+*/
+
+#ifndef CCAN_JSON_H
+#define CCAN_JSON_H
+
+#include <stdbool.h>
+#include <stddef.h>
+
+typedef enum {
+  JSON_NULL,
+  JSON_BOOL,
+  JSON_STRING,
+  JSON_NUMBER,
+  JSON_ARRAY,
+  JSON_OBJECT,
+} JsonTag;
+
+typedef struct JsonNode JsonNode;
+
+struct JsonNode
+{
+  /* 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 {
+      JsonNode *head, *tail;
+    } children;
+  };
+};
+
+/*** Encoding, decoding, and validation ***/
+
+JsonNode   *json_decode         (const char *json);
+char       *json_encode         (const JsonNode *node);
+char       *json_encode_string  (const char *str);
+char       *json_stringify      (const JsonNode *node, const char *space);
+void        json_delete         (JsonNode *node);
+
+bool        json_validate       (const char *json);
+
+/*** Lookup and traversal ***/
+
+JsonNode   *json_find_element   (JsonNode *array, int index);
+JsonNode   *json_find_member    (JsonNode *object, const char *key);
+
+JsonNode   *json_first_child    (const JsonNode *node);
+
+#define json_foreach(i, object_or_array)            \
+  for ((i) = json_first_child(object_or_array);   \
+     (i) != NULL;                               \
+     (i) = (i)->next)
+
+/*** Construction and manipulation ***/
+
+JsonNode *json_mknull(void);
+JsonNode *json_mkbool(bool b);
+JsonNode *json_mkstring(const char *s);
+JsonNode *json_mknumber(double n);
+JsonNode *json_mkarray(void);
+JsonNode *json_mkobject(void);
+
+void json_append_element(JsonNode *array, JsonNode *element);
+void json_prepend_element(JsonNode *array, JsonNode *element);
+void json_append_member(JsonNode *object, const char *key, JsonNode *value);
+void json_prepend_member(JsonNode *object, const char *key, JsonNode *value);
+
+void json_remove_from_parent(JsonNode *node);
+
+/*** Debugging ***/
+
+/*
+ * Look for structure and encoding problems in a JsonNode or its descendents.
+ *
+ * If a problem is detected, return false, writing a description of the problem
+ * to errmsg (unless errmsg is NULL).
+ */
+bool json_check(const JsonNode *node, char errmsg[256]);
+
+#endif
diff --git a/libsass/src/kwd_arg_macros.hpp b/libsass/src/kwd_arg_macros.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/kwd_arg_macros.hpp
@@ -0,0 +1,28 @@
+#ifndef SASS_KWD_ARG_MACROS_H
+#define SASS_KWD_ARG_MACROS_H
+
+// Example usage:
+// KWD_ARG_SET(Args) {
+//   KWD_ARG(Args, string, foo);
+//   KWD_ARG(Args, int, bar);
+//   ...
+// };
+//
+// ... and later ...
+//
+// something(Args().foo("hey").bar(3));
+
+#define KWD_ARG_SET(set_name) class set_name
+
+#define KWD_ARG(set_name, type, name) \
+private: \
+  type name##_; \
+public: \
+  set_name& name(type name##__) { \
+    name##_ = name##__; \
+    return *this; \
+  } \
+  type name() { return name##_; } \
+private:
+
+#endif
diff --git a/libsass/src/lexer.cpp b/libsass/src/lexer.cpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/lexer.cpp
@@ -0,0 +1,169 @@
+#include <cctype>
+#include <cstddef>
+#include <iostream>
+#include <iomanip>
+#include "lexer.hpp"
+#include "constants.hpp"
+
+
+namespace Sass {
+  using namespace Constants;
+
+  namespace Prelexer {
+
+    //####################################
+    // BASIC CHARACTER MATCHERS
+    //####################################
+
+    // Match standard control chars
+    const char* kwd_at(const char* src) { return exactly<'@'>(src); }
+    const char* kwd_dot(const char* src) { return exactly<'.'>(src); }
+    const char* kwd_comma(const char* src) { return exactly<','>(src); };
+    const char* kwd_colon(const char* src) { return exactly<':'>(src); };
+    const char* kwd_star(const char* src) { return exactly<'*'>(src); };
+    const char* kwd_plus(const char* src) { return exactly<'+'>(src); };
+    const char* kwd_minus(const char* src) { return exactly<'-'>(src); };
+    const char* kwd_slash(const char* src) { return exactly<'/'>(src); };
+
+    //####################################
+    // implement some function that do exist in the standard
+    // but those are locale aware which brought some trouble
+    // this even seems to improve performance by quite a bit
+    //####################################
+
+    bool is_alpha(const char& chr)
+    {
+      return unsigned(chr - 'A') <= 'Z' - 'A' ||
+             unsigned(chr - 'a') <= 'z' - 'a';
+    }
+
+    bool is_space(const char& chr)
+    {
+      // adapted the technique from is_alpha
+      return chr == ' ' || unsigned(chr - '\t') <= '\r' - '\t';
+    }
+
+    bool is_digit(const char& chr)
+    {
+      // adapted the technique from is_alpha
+      return unsigned(chr - '0') <= '9' - '0';
+    }
+
+    bool is_xdigit(const char& chr)
+    {
+      // adapted the technique from is_alpha
+      return unsigned(chr - '0') <= '9' - '0' ||
+             unsigned(chr - 'a') <= 'f' - 'a' ||
+             unsigned(chr - 'A') <= 'F' - 'A';
+    }
+
+    bool is_punct(const char& chr)
+    {
+      // locale independent
+      return chr == '.';
+    }
+
+    bool is_alnum(const char& chr)
+    {
+      return is_alpha(chr) || is_digit(chr);
+    }
+
+    // check if char is outside ascii range
+    bool is_unicode(const char& chr)
+    {
+      // check for unicode range
+      return unsigned(chr) > 127;
+    }
+
+    // check if char is outside ascii range
+    // but with specific ranges (copied from Ruby Sass)
+    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)
+      );
+    }
+
+    // check if char is within a reduced ascii range
+    // valid in a uri (copied from Ruby Sass)
+    bool is_uri_character(const char& chr)
+    {
+      return unsigned(chr) > 41 && unsigned(chr) < 127;
+    }
+
+    // check if char is within a reduced ascii range
+    // valid for escaping (copied from Ruby Sass)
+    bool is_escapable_character(const char& chr)
+    {
+      return unsigned(chr) > 31 && unsigned(chr) < 127;
+    }
+
+    // Match word character (look ahead)
+    bool is_character(const char& chr)
+    {
+      // valid alpha, numeric or unicode char (plus hyphen)
+      return is_alnum(chr) || is_unicode(chr) || chr == '-';
+    }
+
+    //####################################
+    // BASIC CLASS MATCHERS
+    //####################################
+
+    // create matchers that advance the position
+    const char* space(const char* src) { return is_space(*src) ? src + 1 : 0; }
+    const char* alpha(const char* src) { return is_alpha(*src) ? src + 1 : 0; }
+    const char* unicode(const char* src) { return is_unicode(*src) ? src + 1 : 0; }
+    const char* nonascii(const char* src) { return is_nonascii(*src) ? src + 1 : 0; }
+    const char* digit(const char* src) { return is_digit(*src) ? src + 1 : 0; }
+    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* 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; }
+
+    // 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); }
+
+    // Whitespace handling.
+    const char* no_spaces(const char* src) { return negate< space >(src); }
+    const char* optional_spaces(const char* src) { return zero_plus< space >(src); }
+
+    // Match any single character.
+    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; }
+
+    // Match linefeed /(?:\n|\r\n?)/
+    const char* re_linebreak(const char* src)
+    {
+      // end of file or unix linefeed return here
+      if (*src == 0 || *src == '\n') return src + 1;
+      // a carriage return may optionally be followed by a linefeed
+      if (*src == '\r') return *(src + 1) == '\n' ? src + 2 : src + 1;
+      // no linefeed
+      return 0;
+    }
+
+    // Assert string boundaries (/\Z|\z|\A/)
+    // This is a zero-width positive lookahead
+    const char* end_of_line(const char* src)
+    {
+      // end of file or unix linefeed return here
+      return *src == 0 || *src == '\n' || *src == '\r' ? src : 0;
+    }
+
+    // Assert end_of_file boundary (/\z/)
+    // This is a zero-width positive lookahead
+    const char* end_of_file(const char* src)
+    {
+      // end of file or unix linefeed return here
+      return *src == 0 ? src : 0;
+    }
+
+  }
+}
diff --git a/libsass/src/lexer.hpp b/libsass/src/lexer.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/lexer.hpp
@@ -0,0 +1,285 @@
+#ifndef SASS_LEXER_H
+#define SASS_LEXER_H
+
+#include <cstring>
+
+namespace Sass {
+  namespace Prelexer {
+
+    //####################################
+    // BASIC CHARACTER MATCHERS
+    //####################################
+
+    // Match standard control chars
+    const char* kwd_at(const char* src);
+    const char* kwd_dot(const char* src);
+    const char* kwd_comma(const char* src);
+    const char* kwd_colon(const char* src);
+    const char* kwd_star(const char* src);
+    const char* kwd_plus(const char* src);
+    const char* kwd_minus(const char* src);
+    const char* kwd_slash(const char* src);
+
+    //####################################
+    // BASIC CLASS MATCHERS
+    //####################################
+
+    // These are locale independant
+    bool is_space(const char& src);
+    bool is_alpha(const char& src);
+    bool is_punct(const char& src);
+    bool is_digit(const char& src);
+    bool is_alnum(const char& src);
+    bool is_xdigit(const char& src);
+    bool is_unicode(const char& src);
+    bool is_nonascii(const char& src);
+    bool is_character(const char& src);
+    bool is_uri_character(const char& src);
+    bool escapable_character(const char& src);
+
+    // Match a single ctype predicate.
+    const char* space(const char* src);
+    const char* alpha(const char* src);
+    const char* digit(const char* src);
+    const char* xdigit(const char* src);
+    const char* alnum(const char* src);
+    const char* punct(const char* src);
+    const char* unicode(const char* src);
+    const char* nonascii(const char* src);
+    const char* character(const char* src);
+    const char* uri_character(const char* src);
+    const char* escapable_character(const char* src);
+
+    // Match multiple ctype characters.
+    const char* spaces(const char* src);
+    const char* digits(const char* src);
+
+    // Whitespace handling.
+    const char* no_spaces(const char* src);
+    const char* optional_spaces(const char* src);
+
+    // Match any single character (/./).
+    const char* any_char(const char* src);
+
+    // Assert word boundary (/\b/)
+    // Is a zero-width positive lookaheads
+    const char* word_boundary(const char* src);
+
+    // Match a single linebreak (/(?:\n|\r\n?)/).
+    const char* re_linebreak(const char* src);
+
+    // Assert string boundaries (/\Z|\z|\A/)
+    // There are zero-width positive lookaheads
+    const char* end_of_line(const char* src);
+
+    // Assert end_of_file boundary (/\z/)
+    const char* end_of_file(const char* src);
+    // const char* start_of_string(const char* src);
+
+    // Type definition for prelexer functions
+    typedef const char* (*prelexer)(const char*);
+
+    //####################################
+    // BASIC "REGEX" CONSTRUCTORS
+    //####################################
+
+    // Match a single character literal.
+    // Regex equivalent: /(?:x)/
+    template <char chr>
+    const char* exactly(const char* src) {
+      return *src == chr ? src + 1 : 0;
+    }
+
+    // Match the full string literal.
+    // Regex equivalent: /(?:literal)/
+    template <const char* str>
+    const char* exactly(const char* src) {
+      if (str == 0) return 0;
+      const char* pre = str;
+      if (src == 0) return 0;
+      // there is a small chance that the search string
+      // is longer than the rest of the string to look at
+      while (*pre && *src == *pre) {
+        ++src, ++pre;
+      }
+      // did the matcher finish?
+      return *pre == 0 ? src : 0;
+    }
+
+
+    // Match the full string literal.
+    // Regex equivalent: /(?:literal)/i
+    // only define lower case alpha chars
+    template <const char* str>
+    const char* insensitive(const char* src) {
+      if (str == 0) return 0;
+      const char* pre = str;
+      if (src == 0) return 0;
+      // there is a small chance that the search string
+      // is longer than the rest of the string to look at
+      while (*pre && (*src == *pre || *src+32 == *pre)) {
+        ++src, ++pre;
+      }
+      // did the matcher finish?
+      return *pre == 0 ? src : 0;
+    }
+
+    // Match for members of char class.
+    // Regex equivalent: /[axy]/
+    template <const char* char_class>
+    const char* class_char(const char* src) {
+      const char* cc = char_class;
+      while (*cc && *src != *cc) ++cc;
+      return *cc ? src + 1 : 0;
+    }
+
+    // Match for members of char class.
+    // Regex equivalent: /[axy]+/
+    template <const char* char_class>
+    const char* class_chars(const char* src) {
+      const char* p = src;
+      while (class_char<char_class>(p)) ++p;
+      return p == src ? 0 : p;
+    }
+
+    // Match all except the supplied one.
+    // Regex equivalent: /[^x]/
+    template <const char chr>
+    const char* any_char_but(const char* src) {
+      return (*src && *src != chr) ? src + 1 : 0;
+    }
+
+    // Succeeds if the matcher fails.
+    // Aka. zero-width negative lookahead.
+    // Regex equivalent: /(?!literal)/
+    template <prelexer mx>
+    const char* negate(const char* src) {
+      return mx(src) ? 0 : src;
+    }
+
+    // Succeeds if the matcher succeeds.
+    // Aka. zero-width positive lookahead.
+    // Regex equivalent: /(?=literal)/
+    // just hangs around until we need it
+    template <prelexer mx>
+    const char* lookahead(const char* src) {
+      return mx(src) ? src : 0;
+    }
+
+    // Tries supplied matchers in order.
+    // Succeeds if one of them succeeds.
+    // Regex equivalent: /(?:FOO|BAR)/
+    template <const prelexer mx>
+    const char* alternatives(const char* src) {
+      const char* rslt;
+      if ((rslt = mx(src))) return rslt;
+      return 0;
+    }
+    template <const prelexer mx1, const prelexer mx2, const prelexer... mxs>
+    const char* alternatives(const char* src) {
+      const char* rslt;
+      if ((rslt = mx1(src))) return rslt;
+      return alternatives<mx2, mxs...>(src);
+    }
+
+    // Tries supplied matchers in order.
+    // Succeeds if all of them succeeds.
+    // Regex equivalent: /(?:FOO)(?:BAR)/
+    template <const prelexer mx1>
+    const char* sequence(const char* src) {
+      const char* rslt = src;
+      if (!(rslt = mx1(rslt))) return 0;
+      return rslt;
+    }
+    template <const prelexer mx1, const prelexer mx2, const prelexer... mxs>
+    const char* sequence(const char* src) {
+      const char* rslt = src;
+      if (!(rslt = mx1(rslt))) return 0;
+      return sequence<mx2, mxs...>(rslt);
+    }
+
+
+    // Match a pattern or not. Always succeeds.
+    // Regex equivalent: /(?:literal)?/
+    template <prelexer mx>
+    const char* optional(const char* src) {
+      const char* p = mx(src);
+      return p ? p : src;
+    }
+
+    // Match zero or more of the patterns.
+    // Regex equivalent: /(?:literal)*/
+    template <prelexer mx>
+    const char* zero_plus(const char* src) {
+      const char* p = mx(src);
+      while (p) src = p, p = mx(src);
+      return src;
+    }
+
+    // Match one or more of the patterns.
+    // Regex equivalent: /(?:literal)+/
+    template <prelexer mx>
+    const char* one_plus(const char* src) {
+      const char* p = mx(src);
+      if (!p) return 0;
+      while (p) src = p, p = mx(src);
+      return src;
+    }
+
+    // Match mx non-greedy until delimiter.
+    // Other prelexers are greedy by default.
+    // Regex equivalent: /(?:$mx)*?(?=$delim)\b/
+    template <prelexer mx, prelexer delim>
+    const char* non_greedy(const char* src) {
+      while (!delim(src)) {
+        const char* p = mx(src);
+        if (p == src) return 0;
+        if (p == 0) return 0;
+        src = p;
+      }
+      return src;
+    }
+
+    //####################################
+    // ADVANCED "REGEX" CONSTRUCTORS
+    //####################################
+
+    // Match with word boundary rule.
+    // Regex equivalent: /(?:$mx)\b/i
+    template <const char* str>
+    const char* keyword(const char* src) {
+      return sequence <
+               insensitive < str >,
+               word_boundary
+             >(src);
+    }
+
+    // Match with word boundary rule.
+    // Regex equivalent: /(?:$mx)\b/
+    template <const char* str>
+    const char* word(const char* src) {
+      return sequence <
+               exactly < str >,
+               word_boundary
+             >(src);
+    }
+
+    template <char chr>
+    const char* loosely(const char* src) {
+      return sequence <
+               optional_spaces,
+               exactly < chr >
+             >(src);
+    }
+    template <const char* str>
+    const char* loosely(const char* src) {
+      return sequence <
+               optional_spaces,
+               exactly < str >
+             >(src);
+    }
+
+  }
+}
+
+#endif
diff --git a/libsass/src/listize.cpp b/libsass/src/listize.cpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/listize.cpp
@@ -0,0 +1,87 @@
+#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)
+  {  }
+
+  Expression* Listize::operator()(Selector_List* sel)
+  {
+    List* l = SASS_MEMORY_NEW(ctx.mem, List, sel->pstate(), sel->length(), SASS_COMMA);
+    for (size_t i = 0, L = sel->length(); i < L; ++i) {
+      if (!(*sel)[i]) continue;
+      *l << (*sel)[i]->perform(this);
+    }
+    return l;
+  }
+
+  Expression* Listize::operator()(Compound_Selector* 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);
+    }
+    return SASS_MEMORY_NEW(ctx.mem, String_Quoted, sel->pstate(), str);
+  }
+
+  Expression* Listize::operator()(Complex_Selector* sel)
+  {
+    List* l = SASS_MEMORY_NEW(ctx.mem, List, sel->pstate(), 2);
+
+    Compound_Selector* head = sel->head();
+    if (head && !head->is_empty_reference())
+    {
+      Expression* hh = head->perform(this);
+      if (hh) *l << hh;
+    }
+
+    To_String to_string;
+    std::string reference = ! sel->reference() ? ""
+      : sel->reference()->perform(&to_string);
+    switch(sel->combinator())
+    {
+      case Complex_Selector::PARENT_OF:
+        *l << SASS_MEMORY_NEW(ctx.mem, String_Quoted, sel->pstate(), ">");
+      break;
+      case Complex_Selector::ADJACENT_TO:
+        *l << SASS_MEMORY_NEW(ctx.mem, String_Quoted, sel->pstate(), "+");
+      break;
+      case Complex_Selector::REFERENCE:
+        *l << SASS_MEMORY_NEW(ctx.mem, String_Quoted, sel->pstate(), "/" + reference + "/");
+      break;
+      case Complex_Selector::PRECEDES:
+        *l << SASS_MEMORY_NEW(ctx.mem, String_Quoted, sel->pstate(), "~");
+      break;
+      case Complex_Selector::ANCESTOR_OF:
+      break;
+    }
+
+    Complex_Selector* 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);
+    }
+    if (l->length() == 0) return 0;
+    return l;
+  }
+
+  Expression* Listize::fallback_impl(AST_Node* n)
+  {
+    return dynamic_cast<Expression*>(n);
+  }
+
+}
diff --git a/libsass/src/listize.hpp b/libsass/src/listize.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/listize.hpp
@@ -0,0 +1,39 @@
+#ifndef SASS_LISTIZE_H
+#define SASS_LISTIZE_H
+
+#include <vector>
+#include <iostream>
+
+#include "ast.hpp"
+#include "context.hpp"
+#include "operation.hpp"
+#include "environment.hpp"
+
+namespace Sass {
+
+  typedef Environment<AST_Node*> Env;
+  struct Backtrace;
+
+  class Listize : public Operation_CRTP<Expression*, Listize> {
+
+    Context&            ctx;
+
+    Expression* fallback_impl(AST_Node* n);
+
+  public:
+    Listize(Context&);
+    virtual ~Listize() { }
+
+    using Operation<Expression*>::operator();
+
+    Expression* operator()(Selector_List*);
+    Expression* operator()(Complex_Selector*);
+    Expression* operator()(Compound_Selector*);
+
+    template <typename U>
+    Expression* fallback(U x) { return fallback_impl(x); }
+  };
+
+}
+
+#endif
diff --git a/libsass/src/mapping.hpp b/libsass/src/mapping.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/mapping.hpp
@@ -0,0 +1,18 @@
+#ifndef SASS_MAPPING_H
+#define SASS_MAPPING_H
+
+#include "position.hpp"
+
+namespace Sass {
+
+  struct Mapping {
+    Position original_position;
+    Position generated_position;
+
+    Mapping(const Position& original_position, const Position& generated_position)
+    : original_position(original_position), generated_position(generated_position) { }
+  };
+
+}
+
+#endif
diff --git a/libsass/src/memory_manager.cpp b/libsass/src/memory_manager.cpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/memory_manager.cpp
@@ -0,0 +1,76 @@
+#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
new file mode 100644
--- /dev/null
+++ b/libsass/src/memory_manager.hpp
@@ -0,0 +1,48 @@
+#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
new file mode 100644
--- /dev/null
+++ b/libsass/src/node.cpp
@@ -0,0 +1,322 @@
+#include <vector>
+
+#include "node.hpp"
+#include "to_string.hpp"
+#include "context.hpp"
+#include "parser.hpp"
+
+namespace Sass {
+
+
+  Node Node::createCombinator(const Complex_Selector::Combinator& combinator) {
+    NodeDequePtr null;
+    return Node(COMBINATOR, combinator, NULL /*pSelector*/, null /*pCollection*/);
+  }
+
+
+  Node Node::createSelector(Complex_Selector* pSelector, Context& ctx) {
+    NodeDequePtr null;
+
+    Complex_Selector* pStripped = pSelector->clone(ctx);
+    pStripped->tail(NULL);
+    pStripped->combinator(Complex_Selector::ANCESTOR_OF);
+
+    Node n(SELECTOR, Complex_Selector::ANCESTOR_OF, pStripped, null /*pCollection*/);
+    if (pSelector) n.got_line_feed = pSelector->has_line_feed();
+    return n;
+  }
+
+
+  Node Node::createCollection() {
+    NodeDequePtr pEmptyCollection = std::make_shared<NodeDeque>();
+    return Node(COLLECTION, Complex_Selector::ANCESTOR_OF, NULL /*pSelector*/, pEmptyCollection);
+  }
+
+
+  Node Node::createCollection(const NodeDeque& values) {
+    NodeDequePtr pShallowCopiedCollection = std::make_shared<NodeDeque>(values);
+    return Node(COLLECTION, Complex_Selector::ANCESTOR_OF, NULL /*pSelector*/, pShallowCopiedCollection);
+  }
+
+
+  Node Node::createNil() {
+    NodeDequePtr null;
+    return Node(NIL, Complex_Selector::ANCESTOR_OF, NULL /*pSelector*/, null /*pCollection*/);
+  }
+
+
+  Node::Node(const TYPE& type, Complex_Selector::Combinator combinator, Complex_Selector* pSelector, NodeDequePtr& pCollection)
+  : got_line_feed(false), mType(type), mCombinator(combinator), mpSelector(pSelector), mpCollection(pCollection)
+  { if (pSelector) got_line_feed = pSelector->has_line_feed(); }
+
+
+  Node Node::clone(Context& ctx) const {
+    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));
+      }
+    }
+
+    Node n(mType, mCombinator, mpSelector ? mpSelector->clone(ctx) : NULL, pNewCollection);
+    n.got_line_feed = got_line_feed;
+    return n;
+  }
+
+
+  bool Node::contains(const Node& potentialChild, bool simpleSelectorOrderDependent) const {
+  	bool found = false;
+
+    for (NodeDeque::iterator iter = mpCollection->begin(), iterEnd = mpCollection->end(); iter != iterEnd; iter++) {
+      Node& toTest = *iter;
+
+      if (nodesEqual(toTest, potentialChild, simpleSelectorOrderDependent)) {
+        found = true;
+        break;
+      }
+    }
+
+    return found;
+  }
+
+
+  bool Node::operator==(const Node& rhs) const {
+  	return nodesEqual(*this, rhs, true /*simpleSelectorOrderDependent*/);
+  }
+
+
+  bool nodesEqual(const Node& lhs, const Node& rhs, bool simpleSelectorOrderDependent) {
+    if (lhs.type() != rhs.type()) {
+      return false;
+    }
+
+    if (lhs.isCombinator()) {
+
+    	return lhs.combinator() == rhs.combinator();
+
+    } else if (lhs.isNil()) {
+
+      return true; // no state to check
+
+    } else if (lhs.isSelector()){
+
+      return selectors_equal(*lhs.selector(), *rhs.selector(), simpleSelectorOrderDependent);
+
+    } else if (lhs.isCollection()) {
+
+      if (lhs.collection()->size() != rhs.collection()->size()) {
+        return false;
+      }
+
+      for (NodeDeque::iterator lhsIter = lhs.collection()->begin(), lhsIterEnd = lhs.collection()->end(),
+           rhsIter = rhs.collection()->begin(); lhsIter != lhsIterEnd; lhsIter++, rhsIter++) {
+
+        if (!nodesEqual(*lhsIter, *rhsIter, simpleSelectorOrderDependent)) {
+          return false;
+        }
+
+      }
+
+      return true;
+
+    }
+
+    // We shouldn't get here.
+    throw "Comparing unknown node types. A new type was probably added and this method wasn't implemented for it.";
+  }
+
+
+  void Node::plus(Node& rhs) {
+  	if (!this->isCollection() || !rhs.isCollection()) {
+    	throw "Both the current node and rhs must be collections.";
+    }
+  	this->collection()->insert(this->collection()->end(), rhs.collection()->begin(), rhs.collection()->end());
+  }
+
+#ifdef DEBUG
+  std::ostream& operator<<(std::ostream& os, const Node& node) {
+
+    if (node.isCombinator()) {
+
+      switch (node.combinator()) {
+        case Complex_Selector::ANCESTOR_OF: os << "\" \""; break;
+        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;
+      }
+
+    } else if (node.isNil()) {
+
+      os << "nil";
+
+    } else if (node.isSelector()){
+
+      To_String to_string;
+      os << node.selector()->head()->perform(&to_string);
+
+    } else if (node.isCollection()) {
+
+      os << "[";
+
+      for (NodeDeque::iterator iter = node.collection()->begin(), iterBegin = node.collection()->begin(), iterEnd = node.collection()->end(); iter != iterEnd; iter++) {
+        if (iter != iterBegin) {
+          os << ", ";
+        }
+
+        os << (*iter);
+      }
+
+      os << "]";
+
+    }
+
+    return os;
+
+  }
+#endif
+
+
+  Node complexSelectorToNode(Complex_Selector* pToConvert, Context& ctx) {
+    if (pToConvert == NULL) {
+      return Node::createNil();
+    }
+    Node node = Node::createCollection();
+    node.got_line_feed = pToConvert->has_line_feed();
+    bool has_lf = pToConvert->has_line_feed();
+
+    // unwrap the selector from parent ref
+    if (pToConvert->head() && pToConvert->head()->has_parent_ref()) {
+      Complex_Selector* tail = pToConvert->tail();
+      if (tail) tail->has_line_feed(pToConvert->has_line_feed());
+      pToConvert = tail;
+    }
+
+    while (pToConvert) {
+
+      bool empty_parent_ref = pToConvert->head() && pToConvert->head()->is_empty_reference();
+
+      if (pToConvert->head() == NULL || empty_parent_ref) {
+      }
+
+      // the first Complex_Selector may contain a dummy head pointer, skip it.
+      if (pToConvert->head() != NULL && !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;
+      }
+
+      if (pToConvert->combinator() != Complex_Selector::ANCESTOR_OF) {
+        node.collection()->push_back(Node::createCombinator(pToConvert->combinator()));
+        if (has_lf) node.collection()->back().got_line_feed = has_lf;
+        has_lf = false;
+      }
+
+      if (pToConvert && empty_parent_ref && pToConvert->tail()) {
+        // pToConvert->tail()->has_line_feed(pToConvert->has_line_feed());
+      }
+
+      pToConvert = pToConvert->tail();
+    }
+
+    return node;
+  }
+
+
+  Complex_Selector* 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.";
+    }
+
+
+    NodeDeque& childNodes = *toConvert.collection();
+
+    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* pCurrent = pFirst;
+
+    if (toConvert.isSelector()) pFirst->has_line_feed(toConvert.got_line_feed);
+    if (toConvert.isCombinator()) pFirst->has_line_feed(toConvert.got_line_feed);
+
+    for (NodeDeque::iterator childIter = childNodes.begin(), childIterEnd = childNodes.end(); childIter != childIterEnd; childIter++) {
+
+      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()
+        // if (child.got_line_feed) pCurrent->has_line_feed(child.got_line_feed);
+        pCurrent = pCurrent->tail();
+      } else if (child.isCombinator()) {
+        pCurrent->combinator(child.combinator());
+        if (child.got_line_feed) pCurrent->has_line_feed(child.got_line_feed);
+
+        // if the next node is also a combinator, create another Complex_Selector to hold it so it doesn't replace the current combinator
+        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));
+            if (nextNode.got_line_feed) pCurrent->tail()->has_line_feed(nextNode.got_line_feed);
+            pCurrent = pCurrent->tail();
+          }
+        }
+      } else {
+        throw "The node to convert's children must be only combinators or selectors.";
+      }
+    }
+
+    // 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]"));
+    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;
+  }
+
+  // A very naive trim function, which removes duplicates in a node
+  // This is only used in Complex_Selector::unify_with for now, may need modifications to fit other needs
+  Node Node::naiveTrim(Node& seqses, Context& ctx) {
+
+    std::vector<Node*> res;
+    std::vector<Complex_Selector*> known;
+
+    NodeDeque::reverse_iterator seqsesIter = seqses.collection()->rbegin(),
+                                seqsesIterEnd = seqses.collection()->rend();
+
+    for (; seqsesIter != seqsesIterEnd; ++seqsesIter)
+    {
+      Node& seqs1 = *seqsesIter;
+      if( seqs1.isSelector() ) {
+        Complex_Selector* sel = seqs1.selector();
+        std::vector<Complex_Selector*>::iterator it;
+        bool found = false;
+        for (it = known.begin(); it != known.end(); ++it) {
+          if (**it == *sel) { found = true; break; }
+        }
+        if( !found ) {
+          known.push_back(seqs1.selector());
+          res.push_back(&seqs1);
+        }
+      } else {
+        res.push_back(&seqs1);
+      }
+    }
+
+    Node result = Node::createCollection();
+
+    for (size_t i = res.size() - 1; i != std::string::npos; --i) {
+      result.collection()->push_back(*res[i]);
+    }
+
+    return result;
+  }
+}
diff --git a/libsass/src/node.hpp b/libsass/src/node.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/node.hpp
@@ -0,0 +1,120 @@
+#ifndef SASS_NODE_H
+#define SASS_NODE_H
+
+#include <deque>
+#include <memory>
+
+#include "ast.hpp"
+
+
+namespace Sass {
+
+
+
+
+  class Context;
+
+  /*
+   There are a lot of stumbling blocks when trying to port the ruby extend code to C++. The biggest is the choice of
+   data type. The ruby code will pretty seamlessly switch types between an Array<SimpleSequence or Op> (libsass'
+   equivalent is the Complex_Selector) to a Sequence, which contains more metadata about the sequence than just the
+   selector info. They also have the ability to have arbitrary nestings of arrays like [1, [2]], which is hard to
+   implement using Array equivalents in C++ (like the deque or vector). They also have the ability to include nil
+   in the arrays, like [1, nil, 3], which has potential semantic differences than an empty array [1, [], 3]. To be
+   able to represent all of these as unique cases, we need to create a tree of variant objects. The tree nature allows
+   the inconsistent nesting levels. The variant nature (while making some of the C++ code uglier) allows the code to
+   more closely match the ruby code, which is a huge benefit when attempting to implement an complex algorithm like
+   the Extend operator.
+
+   Note that the current libsass data model also pairs the combinator with the Complex_Selector that follows it, but
+   ruby sass has no such restriction, so we attempt to create a data structure that can handle them split apart.
+   */
+
+  class Node;
+  typedef std::deque<Node> NodeDeque;
+  typedef std::shared_ptr<NodeDeque> NodeDequePtr;
+
+  class Node {
+  public:
+    enum TYPE {
+      SELECTOR,
+      COMBINATOR,
+      COLLECTION,
+      NIL
+    };
+
+    TYPE type() const { return mType; }
+    bool isCombinator() const { return mType == COMBINATOR; }
+    bool isSelector() const { return mType == SELECTOR; }
+    bool isCollection() const { return mType == COLLECTION; }
+    bool isNil() const { return mType == NIL; }
+    bool got_line_feed;
+
+    Complex_Selector::Combinator combinator() const { return mCombinator; }
+
+    Complex_Selector* selector() { return mpSelector; }
+    const Complex_Selector* 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);
+
+    static Node createCollection();
+    static Node createCollection(const NodeDeque& values);
+
+    static Node createNil();
+    static Node naiveTrim(Node& seqses, Context& ctx);
+
+    Node clone(Context& ctx) const;
+
+    bool operator==(const Node& rhs) const;
+    inline bool operator!=(const Node& rhs) const { return !(*this == rhs); }
+
+
+    /*
+    COLLECTION FUNCTIONS
+
+    Most types don't need any helper methods (nil and combinator due to their simplicity and
+    selector due to the fact that we leverage the non-node selector code on the Complex_Selector
+    whereever possible). The following methods are intended to be called on Node objects whose
+    type is COLLECTION only.
+    */
+
+    // rhs and this must be node collections. Shallow copy the nodes from rhs to the end of this.
+    // This function DOES NOT remove the nodes from rhs.
+    void plus(Node& rhs);
+
+    // potentialChild must be a node collection of selectors/combinators. this must be a collection
+    // of collections of nodes/combinators. This method checks if potentialChild is a child of this
+    // Node.
+    bool contains(const Node& potentialChild, bool simpleSelectorOrderDependent) const;
+
+  private:
+    // 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);
+
+    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
+    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);
+
+  bool nodesEqual(const Node& one, const Node& two, bool simpleSelectorOrderDependent);
+
+}
+
+#endif
diff --git a/libsass/src/operation.hpp b/libsass/src/operation.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/operation.hpp
@@ -0,0 +1,172 @@
+#ifndef SASS_OPERATION_H
+#define SASS_OPERATION_H
+
+#include "ast_fwd_decl.hpp"
+
+namespace Sass {
+
+  template<typename T>
+  class Operation {
+  public:
+    virtual T operator()(AST_Node* 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;
+    // 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;
+    // 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;
+    // 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;
+
+    template <typename U>
+    T fallback(U x) { return T(); }
+  };
+
+  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;
+    // 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); }
+    // 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); }
+    // 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); }
+    // 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); }
+
+    template <typename U>
+    T fallback(U x)                                 { return T(); }
+  };
+  template<typename T, typename D>
+  inline Operation_CRTP<T, D>::~Operation_CRTP()    { }
+
+}
+
+#endif
diff --git a/libsass/src/output.cpp b/libsass/src/output.cpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/output.cpp
@@ -0,0 +1,393 @@
+#include "ast.hpp"
+#include "output.hpp"
+#include "to_string.hpp"
+
+namespace Sass {
+
+  Output::Output(Context* ctx)
+  : Inspect(Emitter(ctx)),
+    charset(""),
+    top_nodes(0)
+  {}
+
+  Output::~Output() { }
+
+  void Output::fallback_impl(AST_Node* n)
+  {
+    return n->perform(this);
+  }
+
+  void Output::operator()(Number* n)
+  {
+    // use values to_string facility
+    To_String to_string(ctx);
+    std::string res = n->perform(&to_string);
+    // 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());
+    }
+    // output the final token
+    append_token(res, n);
+  }
+
+  void Output::operator()(Import* imp)
+  {
+    top_nodes.push_back(imp);
+  }
+
+  void Output::operator()(Map* m)
+  {
+    To_String to_string(ctx);
+    std::string dbg(m->perform(&to_string));
+    error(dbg + " isn't a valid CSS value.", m->pstate());
+  }
+
+  OutputBuffer Output::get_buffer(void)
+  {
+
+    Emitter emitter(ctx);
+    Inspect inspect(emitter);
+
+    size_t size_nodes = top_nodes.size();
+    for (size_t i = 0; i < size_nodes; i++) {
+      top_nodes[i]->perform(&inspect);
+      inspect.append_mandatory_linefeed();
+    }
+
+    // flush scheduled outputs
+    inspect.finalize();
+    // prepend buffer on top
+    prepend_output(inspect.output());
+    // make sure we end with a linefeed
+    if (!ends_with(wbuf.buffer, ctx->linefeed)) {
+      // if the output is not completely empty
+      if (!wbuf.buffer.empty()) append_string(ctx->linefeed);
+    }
+
+    // search for unicode char
+    for(const char& chr : wbuf.buffer) {
+      // skip all ascii chars
+      if (chr >= 0) continue;
+      // declare the charset
+      if (output_style() != SASS_STYLE_COMPRESSED)
+        charset = "@charset \"UTF-8\";"
+                  + ctx->linefeed;
+      else charset = "\xEF\xBB\xBF";
+      // abort search
+      break;
+    }
+
+    // add charset as first line, before comments and imports
+    if (!charset.empty()) prepend_string(charset);
+
+    return wbuf;
+
+  }
+
+  void Output::operator()(Comment* c)
+  {
+    To_String to_string(ctx);
+    std::string txt = c->text()->perform(&to_string);
+    // if (indentation && txt == "/**/") return;
+    bool important = c->is_important();
+    if (output_style() != SASS_STYLE_COMPRESSED || important) {
+      if (buffer().size() == 0) {
+        top_nodes.push_back(c);
+      } else {
+        in_comment = true;
+        append_indentation();
+        c->text()->perform(this);
+        in_comment = false;
+        if (indentation == 0) {
+          append_mandatory_linefeed();
+        } else {
+          append_optional_linefeed();
+        }
+      }
+    }
+  }
+
+  void Output::operator()(Ruleset* r)
+  {
+    Selector* s     = r->selector();
+    Block*    b     = r->block();
+    bool      decls = false;
+
+    // Filter out rulesets that aren't printable (process its children though)
+    if (!Util::isPrintable(r, output_style())) {
+      for (size_t i = 0, L = b->length(); i < L; ++i) {
+        Statement* stm = (*b)[i];
+        if (dynamic_cast<Has_Block*>(stm)) {
+          stm->perform(this);
+        }
+      }
+      return;
+    }
+
+    if (b->has_non_hoistable()) {
+      decls = true;
+      if (output_style() == 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;
+              }
+            }
+          }
+          else if (dec->value()->concrete_type() == Expression::LIST) {
+            List* list = static_cast<List*>(dec->value());
+            bool all_invisible = true;
+            for (size_t list_i = 0, list_L = list->length(); list_i < list_L; ++list_i) {
+              Expression* item = (*list)[list_i];
+              if (!item->is_invisible()) all_invisible = false;
+            }
+            if (all_invisible) bPrintExpression = false;
+          }
+        }
+        // Print if OK
+        if (!stm->is_hoistable() && bPrintExpression) {
+          stm->perform(this);
+        }
+      }
+      if (output_style() == 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);
+        }
+      }
+      if (decls) --indentation;
+    }
+  }
+
+  void Output::operator()(Keyframe_Rule* r)
+  {
+    Block* b = r->block();
+    Selector* v = r->selector();
+
+    if (v) {
+      v->perform(this);
+    }
+
+    if (!b) {
+      append_colon_separator();
+      return;
+    }
+
+    append_scope_opener();
+    for (size_t i = 0, L = b->length(); i < L; ++i) {
+      Statement* stm = (*b)[i];
+      if (!stm->is_hoistable()) {
+        stm->perform(this);
+        if (i < L - 1) append_special_linefeed();
+      }
+    }
+
+    for (size_t i = 0, L = b->length(); i < L; ++i) {
+      Statement* stm = (*b)[i];
+      if (stm->is_hoistable()) {
+        stm->perform(this);
+      }
+    }
+
+    append_scope_closer();
+  }
+
+  void Output::operator()(Supports_Block* f)
+  {
+    if (f->is_invisible()) return;
+
+    Supports_Condition* c = f->condition();
+    Block* b              = f->block();
+
+    // Filter out feature blocks that aren't printable (process its children though)
+    if (!Util::isPrintable(f, output_style())) {
+      for (size_t i = 0, L = b->length(); i < L; ++i) {
+        Statement* stm = (*b)[i];
+        if (dynamic_cast<Has_Block*>(stm)) {
+          stm->perform(this);
+        }
+      }
+      return;
+    }
+
+    if (output_style() == SASS_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();
+      }
+    }
+
+    if (output_style() == SASS_STYLE_NESTED) indentation -= f->tabs();
+
+    append_scope_closer();
+
+  }
+
+  void Output::operator()(Media_Block* m)
+  {
+    if (m->is_invisible()) return;
+
+    List*  q     = m->media_queries();
+    Block* b     = m->block();
+
+    // Filter out media blocks that aren't printable (process its children though)
+    if (!Util::isPrintable(m, output_style())) {
+      for (size_t i = 0, L = b->length(); i < L; ++i) {
+        Statement* stm = (*b)[i];
+        if (dynamic_cast<Has_Block*>(stm)) {
+          stm->perform(this);
+        }
+      }
+      return;
+    }
+    if (output_style() == SASS_STYLE_NESTED) indentation += m->tabs();
+    append_indentation();
+    append_token("@media", m);
+    append_mandatory_space();
+    in_media_block = true;
+    q->perform(this);
+    in_media_block = false;
+    append_scope_opener();
+
+    for (size_t i = 0, L = b->length(); i < L; ++i) {
+      if ((*b)[i]) (*b)[i]->perform(this);
+      if (i < L - 1) append_special_linefeed();
+    }
+
+    if (output_style() == SASS_STYLE_NESTED) indentation -= m->tabs();
+    append_scope_closer();
+  }
+
+  void Output::operator()(At_Rule* a)
+  {
+    std::string      kwd   = a->keyword();
+    Selector*   s     = a->selector();
+    Expression* v     = a->value();
+    Block*      b     = a->block();
+
+    append_indentation();
+    append_token(kwd, a);
+    if (s) {
+      append_mandatory_space();
+      in_wrapped = true;
+      s->perform(this);
+      in_wrapped = false;
+    }
+    if (v) {
+      append_mandatory_space();
+      v->perform(this);
+    }
+    if (!b) {
+      append_delimiter();
+      return;
+    }
+
+    if (b->is_invisible() || b->length() == 0) {
+      return append_string(" {}");
+    }
+
+    append_scope_opener();
+
+    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();
+      }
+    }
+
+    append_scope_closer();
+  }
+
+  void Output::operator()(String_Quoted* s)
+  {
+    if (s->quote_mark()) {
+      append_token(quote(s->value(), s->quote_mark()), s);
+    } else if (!in_comment) {
+      append_token(string_to_output(s->value()), s);
+    } else {
+      append_token(s->value(), s);
+    }
+  }
+
+  void Output::operator()(String_Constant* s)
+  {
+    std::string value(s->value());
+    if (s->can_compress_whitespace() && output_style() == SASS_STYLE_COMPRESSED) {
+      value.erase(std::remove_if(value.begin(), value.end(), ::isspace), value.end());
+    }
+    if (!in_comment) {
+      append_token(string_to_output(value), s);
+    } else {
+      append_token(value, s);
+    }
+  }
+
+}
diff --git a/libsass/src/output.hpp b/libsass/src/output.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/output.hpp
@@ -0,0 +1,56 @@
+#ifndef SASS_OUTPUT_H
+#define SASS_OUTPUT_H
+
+#include <string>
+#include <vector>
+
+#include "util.hpp"
+#include "inspect.hpp"
+#include "operation.hpp"
+
+namespace Sass {
+  class Context;
+
+  // Refactor to make it generic to find linefeed (look behind)
+  inline bool ends_with(std::string const & value, std::string const & ending)
+  {
+    if (ending.size() > value.size()) return false;
+    return std::equal(ending.rbegin(), ending.rend(), value.rbegin());
+  }
+
+  class Output : public Inspect {
+  protected:
+    using Inspect::operator();
+
+  public:
+    // change to Emitter
+    Output(Context* ctx);
+    virtual ~Output();
+
+  protected:
+    std::string charset;
+    std::vector<AST_Node*> 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*);
+
+    void fallback_impl(AST_Node* n);
+
+  };
+
+}
+
+#endif
diff --git a/libsass/src/parser.cpp b/libsass/src/parser.cpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/parser.cpp
@@ -0,0 +1,2436 @@
+#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;
+    // 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
new file mode 100644
--- /dev/null
+++ b/libsass/src/parser.hpp
@@ -0,0 +1,311 @@
+#ifndef SASS_PARSER_H
+#define SASS_PARSER_H
+
+#include <string>
+#include <vector>
+
+#include "ast.hpp"
+#include "position.hpp"
+#include "context.hpp"
+#include "position.hpp"
+#include "prelexer.hpp"
+
+struct Lookahead {
+  const char* found;
+  const char* error;
+  const char* position;
+  bool parsable;
+  bool has_interpolants;
+};
+
+namespace Sass {
+
+  class Parser : public ParserState {
+  public:
+
+    enum Syntactic_Context { nothing, mixin_def, function_def };
+
+    Context& ctx;
+    std::vector<Block*> block_stack;
+    std::vector<Syntactic_Context> stack;
+    Media_Block* last_media_block;
+    const char* source;
+    const char* position;
+    const char* end;
+    Position before_token;
+    Position after_token;
+    ParserState pstate;
+    int indentation;
+
+
+    Token lexed;
+    bool in_at_root;
+
+    Parser(Context& ctx, const ParserState& pstate)
+    : ParserState(pstate), ctx(ctx), block_stack(0), stack(0), last_media_block(0),
+      source(0), position(0), end(0), before_token(pstate), after_token(pstate), pstate(pstate), indentation(0)
+    { in_at_root = false; stack.push_back(nothing); }
+
+    // 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]"));
+    // special static parsers to convert strings into certain selectors
+    static Selector_List* parse_selector(const char* src, Context& ctx, ParserState pstate = ParserState("[SELECTOR]"));
+
+#ifdef __clang__
+
+    // lex and peak uses the template parameter to branch on the action, which
+    // triggers clangs tautological comparison on the single-comparison
+    // branches. This is not a bug, just a merging of behaviour into
+    // one function
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wtautological-compare"
+
+#endif
+
+
+    bool peek_newline(const char* start = 0);
+
+    // skip over spaces, tabs and line comments
+    template <Prelexer::prelexer mx>
+    const char* sneak(const char* start = 0)
+    {
+      using namespace Prelexer;
+
+      // maybe use optional start position from arguments?
+      const char* it_position = start ? start : position;
+
+      // skip white-space?
+      if (mx == spaces ||
+          mx == no_spaces ||
+          mx == css_comments ||
+          mx == css_whitespace ||
+          mx == optional_spaces ||
+          mx == optional_css_comments ||
+          mx == optional_css_whitespace
+      ) {
+        return it_position;
+      }
+
+      // skip over spaces, tabs and sass line comments
+      const char* pos = optional_css_whitespace(it_position);
+      // always return a valid position
+      return pos ? pos : it_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)
+    {
+
+      // sneak up to the actual token we want to lex
+      // this should skip over white-space if desired
+      const char* it_before_token = sneak < mx >(start);
+
+      // match the given prelexer
+      return mx(it_before_token);
+
+    }
+
+    // white-space handling is built into the lexer
+    // this way you do not need to parse it yourself
+    // some matchers don't accept certain white-space
+    // we do not support start arg, since we manipulate
+    // sourcemap offset and we modify the position pointer!
+    // lex will only skip over space, tabs and line comment
+    template <Prelexer::prelexer mx>
+    const char* lex(bool lazy = true, bool force = false)
+    {
+
+      // position considered before lexed token
+      // we can skip whitespace or comments for
+      // lazy developers (but we need control)
+      const char* it_before_token = position;
+
+      // sneak up to the actual token we want to lex
+      // this should skip over white-space if desired
+      if (lazy) it_before_token = sneak < mx >(position);
+
+      // now call matcher to get position after token
+      const char* it_after_token = mx(it_before_token);
+
+      // maybe we want to update the parser state anyway?
+      if (force == false) {
+        // assertion that we got a valid match
+        if (it_after_token == 0) return 0;
+        // assertion that we actually lexed something
+        if (it_after_token == it_before_token) return 0;
+      }
+
+      // create new lexed token object (holds the parse results)
+      lexed = Token(position, it_before_token, it_after_token);
+
+      // advance position (add whitespace before current token)
+      before_token = after_token.add(position, it_before_token);
+
+      // update after_token position for current token
+      after_token.add(it_before_token, it_after_token);
+
+      // ToDo: could probably do this incremetal on original object (API wants offset?)
+      pstate = ParserState(path, source, lexed, before_token, after_token - before_token);
+
+      // advance internal char iterator
+      return position = it_after_token;
+
+    }
+
+    // lex_css skips over space, tabs, line and block comment
+    // all block comments will be consumed and thrown away
+    // source-map position will point to token after the comment
+    template <Prelexer::prelexer mx>
+    const char* lex_css()
+    {
+      // copy old token
+      Token prev = lexed;
+      // store previous pointer
+      const char* oldpos = position;
+      Position bt = before_token;
+      Position at = after_token;
+      ParserState op = pstate;
+      // throw away comments
+      // update srcmap position
+      lex < Prelexer::css_comments >();
+      // now lex a new token
+      const char* pos = lex< mx >();
+      // maybe restore prev state
+      if (pos == 0) {
+        pstate = op;
+        lexed = prev;
+        position = oldpos;
+        after_token = at;
+        before_token = bt;
+      }
+      // return match
+      return pos;
+    }
+
+    // all block comments will be skipped and thrown away
+    template <Prelexer::prelexer mx>
+    const char* peek_css(const char* start = 0)
+    {
+      // now peek a token (skip comments first)
+      return peek< mx >(peek < Prelexer::css_comments >(start));
+    }
+
+#ifdef __clang__
+
+#pragma clang diagnostic pop
+
+#endif
+
+    void error(std::string msg, Position pos);
+    // generate message with given and expected sample
+    // text before and in the middle are configurable
+    void css_error(const std::string& msg,
+                   const std::string& prefix = " after ",
+                   const std::string& middle = ", was: ");
+    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);
+    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();
+    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();
+
+    // these will throw errors
+    Token lex_variable();
+    Token lex_identifier();
+
+    void parse_block_comments();
+
+    Lookahead lookahead_for_value(const char* start = 0);
+    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);
+
+    void throw_syntax_error(std::string message, size_t ln = 0);
+    void throw_read_error(std::string message, size_t ln = 0);
+  };
+
+  size_t check_bom_chars(const char* src, const char *end, const unsigned char* bom, size_t len);
+}
+
+#endif
diff --git a/libsass/src/paths.hpp b/libsass/src/paths.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/paths.hpp
@@ -0,0 +1,71 @@
+#ifndef SASS_PATHS_H
+#define SASS_PATHS_H
+
+#include <string>
+#include <vector>
+#include <sstream>
+
+
+template<typename T>
+std::string vector_to_string(std::vector<T> v)
+{
+  std::stringstream buffer;
+  buffer << "[";
+
+  if (!v.empty())
+  {  buffer << v[0]; }
+  else
+  { buffer << "]"; }
+
+  if (v.size() == 1)
+  { buffer << "]"; }
+  else
+  {
+    for (size_t i = 1, S = v.size(); i < S; ++i) buffer << ", " << v[i];
+    buffer << "]";
+  }
+
+  return buffer.str();
+}
+
+namespace Sass {
+
+
+  template<typename T>
+  std::vector<std::vector<T> > paths(std::vector<std::vector<T> > strata, size_t from_end = 0)
+  {
+    if (strata.empty()) {
+      return std::vector<std::vector<T> >();
+    }
+
+    size_t end = strata.size() - from_end;
+    if (end <= 1) {
+      std::vector<std::vector<T> > starting_points;
+      starting_points.reserve(strata[0].size());
+      for (size_t i = 0, S = strata[0].size(); i < S; ++i) {
+        std::vector<T> starting_point;
+        starting_point.push_back(strata[0][i]);
+        starting_points.push_back(starting_point);
+      }
+      return starting_points;
+    }
+
+    std::vector<std::vector<T> > up_to_here = paths(strata, from_end + 1);
+    std::vector<T>          here       = strata[end-1];
+
+    std::vector<std::vector<T> > branches;
+    branches.reserve(up_to_here.size() * here.size());
+    for (size_t i = 0, S1 = up_to_here.size(); i < S1; ++i) {
+      for (size_t j = 0, S2 = here.size(); j < S2; ++j) {
+        std::vector<T> branch = up_to_here[i];
+        branch.push_back(here[j]);
+        branches.push_back(branch);
+      }
+    }
+
+    return branches;
+  }
+
+}
+
+#endif
diff --git a/libsass/src/plugins.cpp b/libsass/src/plugins.cpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/plugins.cpp
@@ -0,0 +1,165 @@
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <sys/types.h>
+#include <dirent.h>
+#include <errno.h>
+#include <dlfcn.h>
+#endif
+
+#include <iostream>
+#include "output.hpp"
+#include "plugins.hpp"
+
+namespace Sass {
+
+  Plugins::Plugins(void) { }
+  Plugins::~Plugins(void) { }
+
+  // check if plugin is compatible with this version
+  // plugins may be linked static against libsass
+  // we try to be compatible between major versions
+  inline bool compatibility(const char* their_version)
+  {
+// const char* their_version = "3.1.2";
+    // first check if anyone has an unknown version
+    const char* our_version = libsass_version();
+    if (!strcmp(their_version, "[na]")) return false;
+    if (!strcmp(our_version, "[na]")) return false;
+
+    // find the position of the second dot
+    size_t pos = std::string(our_version).find('.', 0);
+    if (pos != std::string::npos) pos = std::string(our_version).find('.', pos + 1);
+
+    // if we do not have two dots we fallback to compare complete string
+    if (pos == std::string::npos) { return strcmp(their_version, our_version) ? 0 : 1; }
+    // otherwise only compare up to the second dot (major versions)
+    else { return strncmp(their_version, our_version, pos) ? 0 : 1; }
+
+  }
+
+  // load one specific plugin
+  bool Plugins::load_plugin (const std::string& path)
+  {
+
+    typedef const char* (*__plugin_version__)(void);
+    typedef Sass_Function_List (*__plugin_load_fns__)(void);
+    typedef Sass_Importer_List (*__plugin_load_imps__)(void);
+
+    if (LOAD_LIB(plugin, path))
+    {
+      // try to load initial function to query libsass version suppor
+      if (LOAD_LIB_FN(__plugin_version__, plugin_version, "libsass_get_version"))
+      {
+        // get the libsass version of the plugin
+        if (!compatibility(plugin_version())) return false;
+        // try to get import address for "libsass_load_functions"
+        if (LOAD_LIB_FN(__plugin_load_fns__, plugin_load_functions, "libsass_load_functions"))
+        {
+          Sass_Function_List fns = plugin_load_functions();
+          while (fns && *fns) { functions.push_back(*fns); ++ fns; }
+        }
+        // try to get import address for "libsass_load_importers"
+        if (LOAD_LIB_FN(__plugin_load_imps__, plugin_load_importers, "libsass_load_importers"))
+        {
+          Sass_Importer_List imps = plugin_load_importers();
+          while (imps && *imps) { importers.push_back(*imps); ++ imps; }
+        }
+        // try to get import address for "libsass_load_headers"
+        if (LOAD_LIB_FN(__plugin_load_imps__, plugin_load_headers, "libsass_load_headers"))
+        {
+          Sass_Importer_List imps = plugin_load_headers();
+          while (imps && *imps) { headers.push_back(*imps); ++ imps; }
+        }
+        // success
+        return true;
+      }
+      else
+      {
+        // print debug message to stderr (should not happen)
+        std::cerr << "failed loading 'libsass_support' in <" << path << ">" << std::endl;
+        if (const char* dlsym_error = dlerror()) std::cerr << dlsym_error << std::endl;
+        CLOSE_LIB(plugin);
+      }
+    }
+    else
+    {
+      // print debug message to stderr (should not happen)
+      std::cerr << "failed loading plugin <" << path << ">" << std::endl;
+      if (const char* dlopen_error = dlerror()) std::cerr << dlopen_error << std::endl;
+    }
+
+    return false;
+
+  }
+
+  size_t Plugins::load_plugins(const std::string& path)
+  {
+
+    // count plugins
+    size_t loaded = 0;
+
+    #ifdef _WIN32
+
+      try
+      {
+
+        // use wchar (utf16)
+        WIN32_FIND_DATAW data;
+        // trailing slash is guaranteed
+        std::string globsrch(path + "*.dll");
+        // convert to wide chars (utf16) for system call
+        std::wstring wglobsrch(UTF_8::convert_to_utf16(globsrch));
+        HANDLE hFile = FindFirstFileW(wglobsrch.c_str(), &data);
+        // check if system called returned a result
+        // ToDo: maybe we should print a debug message
+        if (hFile == INVALID_HANDLE_VALUE) return -1;
+
+        // read directory
+        while (true)
+        {
+          try
+          {
+            // the system will report the filenames with wide chars (utf16)
+            std::string entry = UTF_8::convert_from_utf16(data.cFileName);
+            // check if file ending matches exactly
+            if (!ends_with(entry, ".dll")) continue;
+            // load the plugin and increase counter
+            if (load_plugin(path + entry)) ++ loaded;
+            // check if there should be more entries
+            if (GetLastError() == ERROR_NO_MORE_FILES) break;
+            // load next entry (check for return type)
+            if (!FindNextFileW(hFile, &data)) break;
+          }
+          catch (...)
+          {
+            // report the error to the console (should not happen)
+            // seems like we got strange data from the system call?
+            std::cerr << "filename in plugin path has invalid utf8?" << std::endl;
+          }
+        }
+      }
+      catch (utf8::invalid_utf8)
+      {
+        // report the error to the console (should not happen)
+        // implementors should make sure to provide valid utf8
+        std::cerr << "plugin path contains invalid utf8" << std::endl;
+      }
+
+    #else
+
+      DIR *dp;
+      struct dirent *dirp;
+      if((dp  = opendir(path.c_str())) == NULL) return -1;
+      while ((dirp = readdir(dp)) != NULL) {
+        if (!ends_with(dirp->d_name, ".so")) continue;
+        if (load_plugin(path + dirp->d_name)) ++ loaded;
+      }
+      closedir(dp);
+
+    #endif
+    return loaded;
+
+  }
+
+}
diff --git a/libsass/src/plugins.hpp b/libsass/src/plugins.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/plugins.hpp
@@ -0,0 +1,57 @@
+#ifndef SASS_PLUGINS_H
+#define SASS_PLUGINS_H
+
+#include <string>
+#include <vector>
+#include "utf8_string.hpp"
+#include "sass/functions.h"
+
+#ifdef _WIN32
+
+  #define LOAD_LIB(var, path) HMODULE var = LoadLibraryW(UTF_8::convert_to_utf16(path).c_str())
+  #define LOAD_LIB_WCHR(var, path_wide_str) HMODULE var = LoadLibraryW(path_wide_str.c_str())
+  #define LOAD_LIB_FN(type, var, name) type var = (type) GetProcAddress(plugin, name)
+  #define CLOSE_LIB(var) FreeLibrary(var)
+
+  #ifndef dlerror
+  #define dlerror() 0
+  #endif
+
+#else
+
+  #define LOAD_LIB(var, path) void* var = dlopen(path.c_str(), RTLD_LAZY)
+  #define LOAD_LIB_FN(type, var, name) type var = (type) dlsym(plugin, name)
+  #define CLOSE_LIB(var) dlclose(var)
+
+#endif
+
+namespace Sass {
+
+
+  class Plugins {
+
+    public: // c-tor
+      Plugins(void);
+      ~Plugins(void);
+
+    public: // methods
+      // load one specific plugin
+      bool load_plugin(const std::string& path);
+      // load all plugins from a directory
+      size_t load_plugins(const std::string& path);
+
+    public: // public accessors
+      const std::vector<Sass_Importer_Entry> get_headers(void) { return headers; }
+      const std::vector<Sass_Importer_Entry> get_importers(void) { return importers; }
+      const std::vector<Sass_Function_Entry> get_functions(void) { return functions; }
+
+    private: // private vars
+      std::vector<Sass_Importer_Entry> headers;
+      std::vector<Sass_Importer_Entry> importers;
+      std::vector<Sass_Function_Entry> functions;
+
+  };
+
+}
+
+#endif
diff --git a/libsass/src/position.cpp b/libsass/src/position.cpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/position.cpp
@@ -0,0 +1,162 @@
+#include "position.hpp"
+
+namespace Sass {
+
+
+  Offset::Offset(const char* string)
+  : line(0), column(0)
+  {
+    *this = inc(string, string + strlen(string));
+  }
+
+  Offset::Offset(const std::string& text)
+  : line(0), column(0)
+  {
+    *this = inc(text.c_str(), text.c_str() + text.size());
+  }
+
+  Offset::Offset(const size_t line, const size_t column)
+  : line(line), column(column) { }
+
+  // init/create instance from const char substring
+  Offset Offset::init(const char* beg, const char* end)
+  {
+    Offset offset(0, 0);
+    if (end == 0) {
+      end += strlen(beg);
+    }
+    offset.add(beg, end);
+    return offset;
+  }
+
+  // increase offset by given string (mostly called by lexer)
+  // increase line counter and count columns on the last line
+  // ToDo: make the col count utf8 aware
+  Offset Offset::add(const char* begin, const char* end)
+  {
+    if (end == 0) return *this;
+    while (begin < end && *begin) {
+      if (*begin == '\n') {
+        ++ line;
+        // start new line
+        column = 0;
+      } else {
+        ++ column;
+      }
+      ++begin;
+    }
+    return *this;
+  }
+
+  // increase offset by given string (mostly called by lexer)
+  // increase line counter and count columns on the last line
+  Offset Offset::inc(const char* begin, const char* end) const
+  {
+    Offset offset(line, column);
+    offset.add(begin, end);
+    return offset;
+  }
+
+  bool Offset::operator== (const Offset &pos) const
+  {
+    return line == pos.line && column == pos.column;
+  }
+
+  bool Offset::operator!= (const Offset &pos) const
+  {
+    return line != pos.line || column != pos.column;
+  }
+
+  void Offset::operator+= (const Offset &off)
+  {
+    *this = Offset(line + off.line, off.line > 0 ? off.column : column + off.column);
+  }
+
+  Offset Offset::operator+ (const Offset &off) const
+  {
+    return Offset(line + off.line, off.line > 0 ? off.column : column + off.column);
+  }
+
+  Offset Offset::operator- (const Offset &off) const
+  {
+    return Offset(line - off.line, off.line == line ? column - off.column : column);
+  }
+
+  Position::Position(const size_t file)
+  : Offset(0, 0), file(file) { }
+
+  Position::Position(const size_t file, const Offset& offset)
+  : Offset(offset), file(file) { }
+
+  Position::Position(const size_t line, const size_t column)
+  : Offset(line, column), file(-1) { }
+
+  Position::Position(const size_t file, const size_t line, const size_t column)
+  : Offset(line, column), file(file) { }
+
+
+  ParserState::ParserState(const char* path, const char* src, const size_t file)
+  : Position(file, 0, 0), path(path), src(src), offset(0, 0), token() { }
+
+  ParserState::ParserState(const char* path, const char* src, const Position& position, Offset offset)
+  : Position(position), path(path), src(src), offset(offset), token() { }
+
+  ParserState::ParserState(const char* path, const char* src, const Token& token, const Position& position, Offset offset)
+  : Position(position), path(path), src(src), offset(offset), token(token) { }
+
+  Position Position::add(const char* begin, const char* end)
+  {
+    Offset::add(begin, end);
+    return *this;
+  }
+
+  Position Position::inc(const char* begin, const char* end) const
+  {
+    Offset offset(line, column);
+    offset = offset.inc(begin, end);
+    return Position(file, offset);
+  }
+
+  bool Position::operator== (const Position &pos) const
+  {
+    return file == pos.file && line == pos.line && column == pos.column;
+  }
+
+  bool Position::operator!= (const Position &pos) const
+  {
+    return file == pos.file || line != pos.line || column != pos.column;
+  }
+
+  void Position::operator+= (const Offset &off)
+  {
+    *this = Position(file, line + off.line, off.line > 0 ? off.column : column + off.column);
+  }
+
+  const Position Position::operator+ (const Offset &off) const
+  {
+    return Position(file, line + off.line, off.line > 0 ? off.column : column + off.column);
+  }
+
+  const Offset Position::operator- (const Offset &off) const
+  {
+    return Offset(line - off.line, off.line == line ? column - off.column : column);
+  }
+
+  /* not used anymore - remove?
+  std::ostream& operator<<(std::ostream& strm, const Offset& off)
+  {
+    if (off.line == string::npos) strm << "-1:"; else strm << off.line << ":";
+    if (off.column == string::npos) strm << "-1"; else strm << off.column;
+    return strm;
+  } */
+
+  /* not used anymore - remove?
+  std::ostream& operator<<(std::ostream& strm, const Position& pos)
+  {
+    if (pos.file != string::npos) strm << pos.file << ":";
+    if (pos.line == string::npos) strm << "-1:"; else strm << pos.line << ":";
+    if (pos.column == string::npos) strm << "-1"; else strm << pos.column;
+    return strm;
+  } */
+
+}
diff --git a/libsass/src/position.hpp b/libsass/src/position.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/position.hpp
@@ -0,0 +1,123 @@
+#ifndef SASS_POSITION_H
+#define SASS_POSITION_H
+
+#include <string>
+#include <cstring>
+// #include <iostream>
+
+namespace Sass {
+
+
+  class Offset {
+
+    public: // c-tor
+      Offset(const char* string);
+      Offset(const std::string& text);
+      Offset(const size_t line, const size_t column);
+
+      // return new position, incremented by the given string
+      Offset add(const char* begin, const char* end);
+      Offset inc(const char* begin, const char* end) const;
+
+      // init/create instance from const char substring
+      static Offset init(const char* beg, const char* end);
+
+    public: // overload operators for position
+      void operator+= (const Offset &pos);
+      bool operator== (const Offset &pos) const;
+      bool operator!= (const Offset &pos) const;
+      Offset operator+ (const Offset &off) const;
+      Offset operator- (const Offset &off) const;
+
+    public: // overload output stream operator
+      // friend std::ostream& operator<<(std::ostream& strm, const Offset& off);
+
+    public:
+      Offset off() { return *this; }
+
+    public:
+      size_t line;
+      size_t column;
+
+  };
+
+  class Position : public Offset {
+
+    public: // c-tor
+      Position(const size_t file); // line(0), column(0)
+      Position(const size_t file, const Offset& offset);
+      Position(const size_t line, const size_t column); // file(-1)
+      Position(const size_t file, const size_t line, const size_t column);
+
+    public: // overload operators for position
+      void operator+= (const Offset &off);
+      bool operator== (const Position &pos) const;
+      bool operator!= (const Position &pos) const;
+      const Position operator+ (const Offset &off) const;
+      const Offset operator- (const Offset &off) const;
+      // return new position, incremented by the given string
+      Position add(const char* begin, const char* end);
+      Position inc(const char* begin, const char* end) const;
+
+    public: // overload output stream operator
+      // friend std::ostream& operator<<(std::ostream& strm, const Position& pos);
+
+    public:
+      size_t file;
+
+  };
+
+  // Token type for representing lexed chunks of text
+  class Token {
+  public:
+    const char* prefix;
+    const char* begin;
+    const char* end;
+
+    Token()
+    : prefix(0), begin(0), end(0) { }
+    Token(const char* b, const char* e)
+    : prefix(b), begin(b), end(e) { }
+    Token(const char* str)
+    : prefix(str), begin(str), end(str + strlen(str)) { }
+    Token(const char* p, const char* b, const char* e)
+    : prefix(p), begin(b), end(e) { }
+
+    size_t length()    const { return end - begin; }
+    std::string ws_before() const { return std::string(prefix, begin); }
+    std::string to_string() const { return std::string(begin, end); }
+    std::string time_wspace() const {
+      std::string str(to_string());
+      std::string whitespaces(" \t\f\v\n\r");
+      return str.erase(str.find_last_not_of(whitespaces)+1);
+    }
+
+    operator bool()        { return begin && end && begin >= end; }
+    operator std::string() { return to_string(); }
+
+    bool operator==(Token t)  { return to_string() == t.to_string(); }
+  };
+
+  class ParserState : public Position {
+
+    public: // c-tor
+      ParserState(const char* path, const char* src = 0, const size_t file = std::string::npos);
+      ParserState(const char* path, const char* src, const Position& position, Offset offset = Offset(0, 0));
+      ParserState(const char* path, const char* src, const Token& token, const Position& position, Offset offset = Offset(0, 0));
+
+    public: // down casts
+      Offset off() { return *this; }
+      Position pos() { return *this; }
+      ParserState pstate() { return *this; }
+
+    public:
+      const char* path;
+      const char* src;
+      Offset offset;
+      Token token;
+
+  };
+
+}
+
+#endif
diff --git a/libsass/src/prelexer.cpp b/libsass/src/prelexer.cpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/prelexer.cpp
@@ -0,0 +1,1141 @@
+#include <cctype>
+#include <cstddef>
+#include <iostream>
+#include <iomanip>
+#include "util.hpp"
+#include "position.hpp"
+#include "prelexer.hpp"
+#include "constants.hpp"
+
+
+namespace Sass {
+  // using namespace Lexer;
+  using namespace Constants;
+
+  namespace Prelexer {
+
+
+    // Match a line comment (/.*?(?=\n|\r\n?|\Z)/.
+    const char* line_comment(const char* src)
+    {
+      return sequence<
+               exactly <
+                 slash_slash
+               >,
+               non_greedy<
+                 any_char,
+                 end_of_line
+               >
+             >(src);
+    }
+
+    // Match a block comment.
+    const char* block_comment(const char* src)
+    {
+      return sequence<
+               delimited_by<
+                 slash_star,
+                 star_slash,
+                 false
+               >
+             >(src);
+    }
+    /* not use anymore - remove?
+    const char* block_comment_prefix(const char* src) {
+      return exactly<slash_star>(src);
+    }
+    // Match either comment.
+    const char* comment(const char* src) {
+      return line_comment(src);
+    }
+    */
+
+    // Match zero plus white-space or line_comments
+    const char* optional_css_whitespace(const char* src) {
+      return zero_plus< alternatives<spaces, line_comment> >(src);
+    }
+    const char* css_whitespace(const char* src) {
+      return one_plus< alternatives<spaces, line_comment> >(src);
+    }
+    // Match optional_css_whitepace plus block_comments
+    const char* optional_css_comments(const char* src) {
+      return zero_plus< alternatives<spaces, line_comment, block_comment> >(src);
+    }
+    const char* css_comments(const char* src) {
+      return one_plus< alternatives<spaces, line_comment, block_comment> >(src);
+    }
+
+    // Match one backslash escaped char /\\./
+    const char* escape_seq(const char* src)
+    {
+      return sequence<
+        exactly<'\\'>,
+        alternatives <
+          minmax_range<
+            1, 3, xdigit
+          >,
+          any_char
+        >,
+        optional <
+          exactly <' '>
+        >
+      >(src);
+    }
+
+    // Match identifier start
+    const char* identifier_alpha(const char* src)
+    {
+      return alternatives<
+               unicode_seq,
+               alpha,
+               unicode,
+               exactly<'-'>,
+               exactly<'_'>,
+               NONASCII,
+               ESCAPE,
+               escape_seq
+             >(src);
+    }
+
+    // Match identifier after start
+    const char* identifier_alnum(const char* src)
+    {
+      return alternatives<
+               unicode_seq,
+               alnum,
+               unicode,
+               exactly<'-'>,
+               exactly<'_'>,
+               NONASCII,
+               ESCAPE,
+               escape_seq
+             >(src);
+    }
+
+    // Match CSS identifiers.
+    const char* strict_identifier(const char* src)
+    {
+      return sequence<
+               one_plus < strict_identifier_alpha >,
+               zero_plus < strict_identifier_alnum >
+               // word_boundary not needed
+             >(src);
+    }
+
+    // Match CSS identifiers.
+    const char* identifier(const char* src)
+    {
+      return sequence<
+               zero_plus< exactly<'-'> >,
+               one_plus < identifier_alpha >,
+               zero_plus < identifier_alnum >
+               // word_boundary not needed
+             >(src);
+    }
+
+    const char* strict_identifier_alpha(const char* src)
+    {
+      return alternatives <
+               alpha,
+               unicode,
+               escape_seq,
+               exactly<'_'>
+             >(src);
+    }
+
+    const char* strict_identifier_alnum(const char* src)
+    {
+      return alternatives <
+               alnum,
+               unicode,
+               escape_seq,
+               exactly<'_'>
+             >(src);
+    }
+
+    // Match CSS unit identifier.
+    const char* unit_identifier(const char* src)
+    {
+      return sequence <
+               optional < exactly <'-'> >,
+               strict_identifier_alpha,
+               zero_plus < alternatives<
+                 strict_identifier_alnum,
+                 sequence <
+                   one_plus < exactly<'-'> >,
+                   strict_identifier_alpha
+                 >
+               > >
+             >(src);
+    }
+
+    const char* identifier_alnums(const char* src)
+    {
+      return one_plus< identifier_alnum >(src);
+    }
+
+    // Match number prefix ([\+\-]+)
+    const char* number_prefix(const char* src) {
+      return alternatives <
+        exactly < '+' >,
+        sequence <
+          exactly < '-' >,
+          optional_css_whitespace,
+          exactly< '-' >
+        >
+      >(src);
+    }
+
+    // Match interpolant schemas
+    const char* identifier_schema(const char* src) {
+
+      return sequence <
+               one_plus <
+                 sequence <
+                   zero_plus <
+                     alternatives <
+                       identifier,
+                       exactly <'-'>
+                     >
+                   >,
+                   interpolant,
+                   zero_plus <
+                     alternatives <
+                       digits,
+                       identifier,
+                       quoted_string,
+                       exactly<'+'>,
+                       exactly<'-'>
+                     >
+                   >
+                 >
+               >,
+               negate <
+                 exactly<'%'>
+               >
+             > (src);
+    }
+
+    // interpolants can be recursive/nested
+    const char* interpolant(const char* src) {
+      return recursive_scopes< exactly<hash_lbrace>, exactly<rbrace> >(src);
+    }
+
+    // $re_squote = /'(?:$re_itplnt|\\.|[^'])*'/
+    const char* single_quoted_string(const char* src) {
+      // match a single quoted string, while skipping interpolants
+      return sequence <
+        exactly <'\''>,
+        zero_plus <
+          alternatives <
+            // skip escapes
+            sequence <
+              exactly < '\\' >,
+              re_linebreak
+            >,
+            escape_seq,
+            unicode_seq,
+            // skip interpolants
+            interpolant,
+            // skip non delimiters
+            any_char_but < '\'' >
+          >
+        >,
+        exactly <'\''>
+      >(src);
+    }
+
+    // $re_dquote = /"(?:$re_itp|\\.|[^"])*"/
+    const char* double_quoted_string(const char* src) {
+      // match a single quoted string, while skipping interpolants
+      return sequence <
+        exactly <'"'>,
+        zero_plus <
+          alternatives <
+            // skip escapes
+            sequence <
+              exactly < '\\' >,
+              re_linebreak
+            >,
+            escape_seq,
+            unicode_seq,
+            // skip interpolants
+            interpolant,
+            // skip non delimiters
+            any_char_but < '"' >
+          >
+        >,
+        exactly <'"'>
+      >(src);
+    }
+
+    // $re_quoted = /(?:$re_squote|$re_dquote)/
+    const char* quoted_string(const char* src) {
+      // match a quoted string, while skipping interpolants
+      return alternatives<
+        single_quoted_string,
+        double_quoted_string
+      >(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);
+    }
+
+    /* not used anymore - remove?
+    const char* filename(const char* src) {
+      return one_plus< alternatives< identifier, number, exactly<'.'> > >(src);
+    }
+    */
+
+    // Match CSS '@' keywords.
+    const char* at_keyword(const char* src) {
+      return sequence<exactly<'@'>, identifier>(src);
+    }
+
+    const char* re_reference_combinator(const char* src) {
+      return sequence <
+        optional <
+          sequence <
+            zero_plus <
+              exactly <'-'>
+            >,
+            identifier,
+            exactly <'|'>
+          >
+        >,
+        zero_plus <
+          exactly <'-'>
+        >,
+        identifier
+      >(src);
+    }
+
+    const char* static_reference_combinator(const char* src) {
+      return sequence <
+        exactly <'/'>,
+        re_reference_combinator,
+        exactly <'/'>
+      >(src);
+    }
+
+    const char* schema_reference_combinator(const char* src) {
+      return sequence <
+        exactly <'/'>,
+        optional <
+          sequence <
+            css_ip_identifier,
+            exactly <'|'>
+          >
+        >,
+        css_ip_identifier,
+        exactly <'/'>
+      > (src);
+    }
+
+    const char* kwd_import(const char* src) {
+      return word<import_kwd>(src);
+    }
+
+    const char* kwd_at_root(const char* src) {
+      return word<at_root_kwd>(src);
+    }
+
+    const char* kwd_with_directive(const char* src) {
+      return word<with_kwd>(src);
+    }
+
+    const char* kwd_without_directive(const char* src) {
+      return word<without_kwd>(src);
+    }
+
+    const char* kwd_media(const char* src) {
+      return word<media_kwd>(src);
+    }
+
+    const char* kwd_supports_directive(const char* src) {
+      return word<supports_kwd>(src);
+    }
+
+    const char* kwd_mixin(const char* src) {
+      return word<mixin_kwd>(src);
+    }
+
+    const char* kwd_function(const char* src) {
+      return word<function_kwd>(src);
+    }
+
+    const char* kwd_return_directive(const char* src) {
+      return word<return_kwd>(src);
+    }
+
+    const char* kwd_include_directive(const char* src) {
+      return word<include_kwd>(src);
+    }
+
+    const char* kwd_content_directive(const char* src) {
+      return word<content_kwd>(src);
+    }
+
+    const char* kwd_charset_directive(const char* src) {
+      return word<charset_kwd>(src);
+    }
+
+    const char* kwd_extend(const char* src) {
+      return word<extend_kwd>(src);
+    }
+
+
+    const char* kwd_if_directive(const char* src) {
+      return word<if_kwd>(src);
+    }
+
+    const char* kwd_else_directive(const char* src) {
+      return word<else_kwd>(src);
+    }
+    const char* elseif_directive(const char* src) {
+      return sequence< exactly< else_kwd >,
+                                optional_css_comments,
+                                word< if_after_else_kwd > >(src);
+    }
+
+    const char* kwd_for_directive(const char* src) {
+      return word<for_kwd>(src);
+    }
+
+    const char* kwd_from(const char* src) {
+      return word<from_kwd>(src);
+    }
+
+    const char* kwd_to(const char* src) {
+      return word<to_kwd>(src);
+    }
+
+    const char* kwd_through(const char* src) {
+      return word<through_kwd>(src);
+    }
+
+    const char* kwd_each_directive(const char* src) {
+      return word<each_kwd>(src);
+    }
+
+    const char* kwd_in(const char* src) {
+      return word<in_kwd>(src);
+    }
+
+    const char* kwd_while_directive(const char* src) {
+      return word<while_kwd>(src);
+    }
+
+    const char* name(const char* src) {
+      return one_plus< alternatives< alnum,
+                                     exactly<'-'>,
+                                     exactly<'_'>,
+                                     exactly<'\\'> > >(src);
+    }
+
+    const char* kwd_warn(const char* src) {
+      return word<warn_kwd>(src);
+    }
+
+    const char* kwd_err(const char* src) {
+      return word<error_kwd>(src);
+    }
+
+    const char* kwd_dbg(const char* src) {
+      return word<debug_kwd>(src);
+    }
+
+    /* not used anymore - remove?
+    const char* directive(const char* src) {
+      return sequence< exactly<'@'>, identifier >(src);
+    } */
+
+    const char* kwd_null(const char* src) {
+      return word<null_kwd>(src);
+    }
+
+    const char* css_identifier(const char* src) {
+      return sequence <
+               zero_plus <
+                 exactly <'-'>
+               >,
+               identifier
+             >(src);
+    }
+
+    const char* css_ip_identifier(const char* src) {
+      return sequence <
+               zero_plus <
+                 exactly <'-'>
+               >,
+               alternatives <
+                 identifier,
+                 interpolant
+               >
+             >(src);
+    }
+
+    // Match CSS type selectors
+    const char* namespace_prefix(const char* src) {
+      return sequence <
+               optional <
+                 alternatives <
+                   exactly <'*'>,
+                   css_identifier
+                 >
+               >,
+               exactly <'|'>,
+               negate <
+                 exactly <'='>
+               >
+             >(src);
+    }
+
+    // Match CSS type selectors
+    const char* namespace_schema(const char* src) {
+      return sequence <
+               optional <
+                 alternatives <
+                   exactly <'*'>,
+                   css_ip_identifier
+                 >
+               >,
+               exactly<'|'>,
+               negate <
+                 exactly <'='>
+               >
+             >(src);
+    }
+
+    const char* hyphens_and_identifier(const char* src) {
+      return sequence< zero_plus< exactly< '-' > >, identifier >(src);
+    }
+    const char* hyphens_and_name(const char* src) {
+      return sequence< zero_plus< exactly< '-' > >, name >(src);
+    }
+    const char* universal(const char* src) {
+      return sequence< optional<namespace_schema>, exactly<'*'> >(src);
+    }
+    // Match CSS id names.
+    const char* id_name(const char* src) {
+      return sequence<exactly<'#'>, name>(src);
+    }
+    // Match CSS class names.
+    const char* class_name(const char* src) {
+      return sequence<exactly<'.'>, identifier>(src);
+    }
+    // Attribute name in an attribute selector.
+    const char* attribute_name(const char* src) {
+      return alternatives< sequence< optional<namespace_schema>, identifier>,
+                           identifier >(src);
+    }
+    // match placeholder selectors
+    const char* placeholder(const char* src) {
+      return sequence<exactly<'%'>, identifier>(src);
+    }
+    // Match CSS numeric constants.
+
+    const char* sign(const char* src) {
+      return class_char<sign_chars>(src);
+    }
+    const char* unsigned_number(const char* src) {
+      return alternatives<sequence< zero_plus<digits>,
+                                    exactly<'.'>,
+                                    one_plus<digits> >,
+                          digits>(src);
+    }
+    const char* number(const char* src) {
+      return sequence< optional<sign>, unsigned_number>(src);
+    }
+    const char* coefficient(const char* src) {
+      return alternatives< sequence< optional<sign>, digits >,
+                           sign >(src);
+    }
+    const char* binomial(const char* src) {
+      return sequence <
+               optional < sign >,
+               optional < digits >,
+               exactly <'n'>,
+               zero_plus < sequence <
+                 optional_css_whitespace, sign,
+                 optional_css_whitespace, digits
+               > >
+             >(src);
+    }
+    const char* percentage(const char* src) {
+      return sequence< number, exactly<'%'> >(src);
+    }
+    const char* ampersand(const char* src) {
+      return exactly<'&'>(src);
+    }
+
+    /* not used anymore - remove?
+    const char* em(const char* src) {
+      return sequence< number, exactly<em_kwd> >(src);
+    } */
+    const char* dimension(const char* src) {
+      return sequence<number, unit_identifier >(src);
+    }
+    const char* hex(const char* src) {
+      const char* p = sequence< exactly<'#'>, one_plus<xdigit> >(src);
+      ptrdiff_t len = p - src;
+      return (len != 4 && len != 7) ? 0 : p;
+    }
+    const char* hexa(const char* src) {
+      const char* p = sequence< exactly<'#'>, one_plus<xdigit> >(src);
+      ptrdiff_t len = p - src;
+      return (len != 4 && len != 7 && len != 9) ? 0 : p;
+    }
+    const char* hex0(const char* src) {
+      const char* p = sequence< exactly<'0'>, exactly<'x'>, one_plus<xdigit> >(src);
+      ptrdiff_t len = p - src;
+      return (len != 5 && len != 8) ? 0 : p;
+    }
+
+    /* no longer used - remove?
+    const char* rgb_prefix(const char* src) {
+      return word<rgb_kwd>(src);
+    }*/
+    // 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 < '$' >
+        >,
+        zero_plus <
+          alternatives <
+            alnum,
+            interpolant,
+            exactly <'/'>,
+            class_char < uri_chars >
+          >
+        >
+      >(src);
+    }
+
+    // TODO: rename the following two functions
+    /* no longer used - remove?
+    const char* uri(const char* src) {
+      return sequence< exactly<url_kwd>,
+                       optional<spaces>,
+                       quoted_string,
+                       optional<spaces>,
+                       exactly<')'> >(src);
+    }*/
+    /* no longer used - remove?
+    const char* url_value(const char* src) {
+      return sequence< optional< sequence< identifier, exactly<':'> > >, // optional protocol
+                       one_plus< sequence< zero_plus< exactly<'/'> >, filename > >, // one or more folders and/or trailing filename
+                       optional< exactly<'/'> > >(src);
+    }*/
+    /* no longer used - remove?
+    const char* url_schema(const char* src) {
+      return sequence< optional< sequence< identifier, exactly<':'> > >, // optional protocol
+                       filename_schema >(src); // optional trailing slash
+    }*/
+    // Match CSS "!important" keyword.
+    const char* kwd_important(const char* src) {
+      return sequence< exactly<'!'>,
+                       optional_css_whitespace,
+                       word<important_kwd> >(src);
+    }
+    // Match CSS "!optional" keyword.
+    const char* kwd_optional(const char* src) {
+      return sequence< exactly<'!'>,
+      optional_css_whitespace,
+      word<optional_kwd> >(src);
+    }
+    // Match Sass "!default" keyword.
+    const char* default_flag(const char* src) {
+      return sequence< exactly<'!'>,
+                       optional_css_whitespace,
+                       word<default_kwd> >(src);
+    }
+    // Match Sass "!global" keyword.
+    const char* global_flag(const char* src) {
+      return sequence< exactly<'!'>,
+                       optional_css_whitespace,
+                       word<global_kwd> >(src);
+    }
+    // Match CSS pseudo-class/element prefixes.
+    const char* pseudo_prefix(const char* src) {
+      return sequence< exactly<':'>, optional< exactly<':'> > >(src);
+    }
+    // Match CSS function call openers.
+    const char* functional_schema(const char* src) {
+      return sequence <
+               one_plus <
+                 sequence <
+                   zero_plus <
+                     alternatives <
+                       identifier,
+                       exactly <'-'>
+                     >
+                   >,
+                   one_plus <
+                     sequence <
+                       interpolant,
+                       alternatives <
+                         digits,
+                         identifier,
+                         exactly<'+'>,
+                         exactly<'-'>
+                       >
+                     >
+                   >
+                 >
+               >,
+               negate <
+                 exactly <'%'>
+               >,
+               lookahead <
+                 exactly <'('>
+               >
+             > (src);
+    }
+
+    const char* re_nothing(const char* src) {
+      return src;
+    }
+
+    const char* re_functional(const char* src) {
+      return sequence< identifier, optional < block_comment >, exactly<'('> >(src);
+    }
+    const char* re_pseudo_selector(const char* src) {
+      return sequence< identifier, optional < block_comment >, exactly<'('> >(src);
+    }
+    // Match the CSS negation pseudo-class.
+    const char* pseudo_not(const char* src) {
+      return word< pseudo_not_kwd >(src);
+    }
+    // Match CSS 'odd' and 'even' keywords for functional pseudo-classes.
+    const char* even(const char* src) {
+      return word<even_kwd>(src);
+    }
+    const char* odd(const char* src) {
+      return word<odd_kwd>(src);
+    }
+    // Match CSS attribute-matching operators.
+    const char* exact_match(const char* src) { return exactly<'='>(src); }
+    const char* class_match(const char* src) { return exactly<tilde_equal>(src); }
+    const char* dash_match(const char* src) { return exactly<pipe_equal>(src); }
+    const char* prefix_match(const char* src) { return exactly<caret_equal>(src); }
+    const char* suffix_match(const char* src) { return exactly<dollar_equal>(src); }
+    const char* substring_match(const char* src) { return exactly<star_equal>(src); }
+    // Match CSS combinators.
+    /* not used anymore - remove?
+    const char* adjacent_to(const char* src) {
+      return sequence< optional_spaces, exactly<'+'> >(src);
+    }
+    const char* precedes(const char* src) {
+      return sequence< optional_spaces, exactly<'~'> >(src);
+    }
+    const char* parent_of(const char* src) {
+      return sequence< optional_spaces, exactly<'>'> >(src);
+    }
+    const char* ancestor_of(const char* src) {
+      return sequence< spaces, negate< exactly<'{'> > >(src);
+    }*/
+
+    // Match SCSS variable names.
+    const char* variable(const char* src) {
+      return sequence<exactly<'$'>, identifier>(src);
+    }
+
+    // Match Sass boolean keywords.
+    const char* kwd_true(const char* src) {
+      return word<true_kwd>(src);
+    }
+    const char* kwd_false(const char* src) {
+      return word<false_kwd>(src);
+    }
+    const char* kwd_only(const char* src) {
+      return keyword < only_kwd >(src);
+    }
+    const char* kwd_and(const char* src) {
+      return keyword < and_kwd >(src);
+    }
+    const char* kwd_or(const char* src) {
+      return keyword < or_kwd >(src);
+    }
+    const char* kwd_not(const char* src) {
+      return keyword < not_kwd >(src);
+    }
+    const char* kwd_eq(const char* src) {
+      return exactly<eq>(src);
+    }
+    const char* kwd_neq(const char* src) {
+      return exactly<neq>(src);
+    }
+    const char* kwd_gt(const char* src) {
+      return exactly<gt>(src);
+    }
+    const char* kwd_gte(const char* src) {
+      return exactly<gte>(src);
+    }
+    const char* kwd_lt(const char* src) {
+      return exactly<lt>(src);
+    }
+    const char* kwd_lte(const char* src) {
+      return exactly<lte>(src);
+    }
+
+    // match specific IE syntax
+    const char* ie_progid(const char* src) {
+      return sequence <
+        word<progid_kwd>,
+        exactly<':'>,
+        alternatives< identifier_schema, identifier >,
+        zero_plus< sequence<
+          exactly<'.'>,
+          alternatives< identifier_schema, identifier >
+        > >,
+        zero_plus < sequence<
+          exactly<'('>,
+          optional_css_whitespace,
+          optional < sequence<
+            alternatives< variable, identifier_schema, identifier >,
+            optional_css_whitespace,
+            exactly<'='>,
+            optional_css_whitespace,
+            alternatives< variable, identifier_schema, identifier, quoted_string, number, hexa >,
+            zero_plus< sequence<
+              optional_css_whitespace,
+              exactly<','>,
+              optional_css_whitespace,
+              sequence<
+                alternatives< variable, identifier_schema, identifier >,
+                optional_css_whitespace,
+                exactly<'='>,
+                optional_css_whitespace,
+                alternatives< variable, identifier_schema, identifier, quoted_string, number, hexa >
+              >
+            > >
+          > >,
+          optional_css_whitespace,
+          exactly<')'>
+        > >
+      >(src);
+    }
+    const char* ie_expression(const char* src) {
+      return sequence < word<expression_kwd>, exactly<'('>, skip_over_scopes< exactly<'('>, exactly<')'> > >(src);
+    }
+    const char* ie_property(const char* src) {
+      return alternatives < ie_expression, ie_progid >(src);
+    }
+
+    // const char* ie_args(const char* src) {
+    //   return sequence< alternatives< ie_keyword_arg, value_schema, quoted_string, interpolant, number, identifier, delimited_by< '(', ')', true> >,
+    //                    zero_plus< sequence< optional_css_whitespace, exactly<','>, optional_css_whitespace, alternatives< ie_keyword_arg, value_schema, quoted_string, interpolant, number, identifier, delimited_by<'(', ')', true> > > > >(src);
+    // }
+
+    const char* ie_keyword_arg_property(const char* src) {
+      return alternatives <
+          variable,
+          identifier_schema,
+          identifier
+        >(src);
+    }
+    const char* ie_keyword_arg_value(const char* src) {
+      return alternatives <
+          variable,
+          identifier_schema,
+          identifier,
+          quoted_string,
+          number,
+          hexa,
+          sequence <
+            exactly < '(' >,
+            skip_over_scopes <
+              exactly < '(' >,
+              exactly < ')' >
+            >
+          >
+        >(src);
+    }
+
+    const char* ie_keyword_arg(const char* src) {
+      return sequence <
+        ie_keyword_arg_property,
+        optional_css_whitespace,
+        exactly<'='>,
+        optional_css_whitespace,
+        ie_keyword_arg_value
+      >(src);
+    }
+
+    // Path matching functions.
+    /* not used anymore - remove?
+    const char* folder(const char* src) {
+      return sequence< zero_plus< any_char_except<'/'> >,
+                       exactly<'/'> >(src);
+    }
+    const char* folders(const char* src) {
+      return zero_plus< folder >(src);
+    }*/
+    /* not used anymore - remove?
+    const char* chunk(const char* src) {
+      char inside_str = 0;
+      const char* p = src;
+      size_t depth = 0;
+      while (true) {
+        if (!*p) {
+          return 0;
+        }
+        else if (!inside_str && (*p == '"' || *p == '\'')) {
+          inside_str = *p;
+        }
+        else if (*p == inside_str && *(p-1) != '\\') {
+          inside_str = 0;
+        }
+        else if (*p == '(' && !inside_str) {
+          ++depth;
+        }
+        else if (*p == ')' && !inside_str) {
+          if (depth == 0) return p;
+          else            --depth;
+        }
+        ++p;
+      }
+      // unreachable
+      return 0;
+    }
+    */
+
+    // follow the CSS spec more closely and see if this helps us scan URLs correctly
+    /* not used anymore - remove?
+    const char* NL(const char* src) {
+      return alternatives< exactly<'\n'>,
+                           sequence< exactly<'\r'>, exactly<'\n'> >,
+                           exactly<'\r'>,
+                           exactly<'\f'> >(src);
+    }*/
+
+    const char* H(const char* src) {
+      return std::isxdigit(*src) ? src+1 : 0;
+    }
+
+    const char* W(const char* src) {
+      return zero_plus< alternatives<
+        space,
+        exactly< '\t' >,
+        exactly< '\r' >,
+        exactly< '\n' >,
+        exactly< '\f' >
+      > >(src);
+    }
+
+    const char* UUNICODE(const char* src) {
+      return sequence< exactly<'\\'>,
+                       between<H, 1, 6>,
+                       optional< W >
+                       >(src);
+    }
+
+    const char* NONASCII(const char* src) {
+      return nonascii(src);
+    }
+
+    const char* ESCAPE(const char* src) {
+      return alternatives<
+        UUNICODE,
+        sequence<
+          exactly<'\\'>,
+          alternatives<
+            NONASCII,
+            escapable_character
+          >
+        >
+      >(src);
+    }
+
+
+    // const char* real_uri_prefix(const char* src) {
+    //   return alternatives<
+    //     exactly< url_kwd >,
+    //     exactly< url_prefix_kwd >
+    //   >(src);
+    // }
+
+    const char* real_uri_suffix(const char* src) {
+      return sequence< W, exactly< ')' > >(src);
+    }
+
+    const char* real_uri_value(const char* src) {
+      return
+      sequence<
+        non_greedy<
+          alternatives<
+            class_char< real_uri_chars >,
+            uri_character,
+            NONASCII,
+            ESCAPE
+          >,
+          alternatives<
+            real_uri_suffix,
+            exactly< hash_lbrace >
+          >
+        >
+      >
+      (src);
+    }
+
+    const char* static_string(const char* src) {
+      const char* pos = src;
+      const char * s = quoted_string(pos);
+      Token t(pos, s);
+      const unsigned int p = count_interval< interpolant >(t.begin, t.end);
+      return (p == 0) ? t.end : 0;
+    }
+
+    const char* unicode_seq(const char* src) {
+      return sequence <
+        alternatives <
+          exactly< 'U' >,
+          exactly< 'u' >
+        >,
+        exactly< '+' >,
+        padded_token <
+          6, xdigit,
+          exactly < '?' >
+        >
+      >(src);
+    }
+
+    const char* static_component(const char* src) {
+      return alternatives< identifier,
+                           static_string,
+                           percentage,
+                           hex,
+                           exactly<'|'>,
+                           // exactly<'+'>,
+                           sequence < number, unit_identifier >,
+                           number,
+                           sequence< exactly<'!'>, word<important_kwd> >
+                          >(src);
+    }
+
+    const char* static_property(const char* src) {
+      return
+        sequence <
+          zero_plus<
+            sequence <
+              optional_css_comments,
+              alternatives <
+                exactly<','>,
+                exactly<'('>,
+                exactly<')'>,
+                kwd_optional,
+                quoted_string,
+                interpolant,
+                identifier,
+                percentage,
+                dimension,
+                variable,
+                alnum,
+                sequence <
+                  exactly <'\\'>,
+                  any_char
+                >
+              >
+            >
+          >,
+          lookahead <
+            sequence <
+              optional_css_comments,
+              alternatives <
+                exactly <';'>,
+                exactly <'}'>,
+                end_of_file
+              >
+            >
+          >
+        >(src);
+    }
+
+    const char* static_value(const char* src) {
+      return sequence< sequence<
+                         static_component,
+                         zero_plus< identifier >
+                       >,
+                       zero_plus < sequence<
+                                     alternatives<
+                                       sequence< optional_spaces, alternatives<
+                                         exactly < '/' >,
+                                         exactly < ',' >,
+                                         exactly < ' ' >
+                                       >, optional_spaces >,
+                                       spaces
+                                     >,
+                                     static_component
+                       > >,
+                       zero_plus < spaces >,
+                       alternatives< exactly<';'>, exactly<'}'> >
+                      >(src);
+    }
+
+    const char* parenthese_scope(const char* src) {
+      return sequence <
+        exactly < '(' >,
+        skip_over_scopes <
+          exactly < '(' >,
+          exactly < ')' >
+        >
+      >(src);
+    }
+
+    const char* type_selector(const char* src) {
+      return sequence< optional<namespace_schema>, identifier>(src);
+    }
+    const char* re_type_selector(const char* src) {
+      return alternatives< type_selector, universal, quoted_string, dimension, percentage, number, identifier_alnums >(src);
+    }
+    const char* re_type_selector2(const char* src) {
+      return alternatives< type_selector, universal, quoted_string, dimension, percentage, number, identifier_alnums >(src);
+    }
+    const char* re_static_expression(const char* src) {
+      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;
+    }
+
+    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;
+      }
+      if (got < min) return 0;
+      if (got > max) return 0;
+      return pos;
+    }
+
+  }
+}
diff --git a/libsass/src/prelexer.hpp b/libsass/src/prelexer.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/prelexer.hpp
@@ -0,0 +1,416 @@
+#ifndef SASS_PRELEXER_H
+#define SASS_PRELEXER_H
+
+#include <cstring>
+#include "lexer.hpp"
+
+namespace Sass {
+  // using namespace Lexer;
+  namespace Prelexer {
+
+    //####################################
+    // KEYWORD "REGEX" MATCHERS
+    //####################################
+
+    // Match Sass boolean keywords.
+    const char* kwd_true(const char* src);
+    const char* kwd_false(const char* src);
+    const char* kwd_only(const char* src);
+    const char* kwd_and(const char* src);
+    const char* kwd_or(const char* src);
+    const char* kwd_not(const char* src);
+    const char* kwd_eq(const char* src);
+    const char* kwd_neq(const char* src);
+    const char* kwd_gt(const char* src);
+    const char* kwd_gte(const char* src);
+    const char* kwd_lt(const char* src);
+    const char* kwd_lte(const char* src);
+
+    // Match standard control chars
+    const char* kwd_at(const char* src);
+    const char* kwd_dot(const char* src);
+    const char* kwd_comma(const char* src);
+    const char* kwd_colon(const char* src);
+    const char* kwd_slash(const char* src);
+    const char* kwd_star(const char* src);
+    const char* kwd_plus(const char* src);
+    const char* kwd_minus(const char* src);
+
+    //####################################
+    // SPECIAL "REGEX" CONSTRUCTS
+    //####################################
+
+    // Match a sequence of characters delimited by the supplied chars.
+    template <char beg, char end, bool esc>
+    const char* delimited_by(const char* src) {
+      src = exactly<beg>(src);
+      if (!src) return 0;
+      const char* stop;
+      while (1) {
+        if (!*src) return 0;
+        stop = exactly<end>(src);
+        if (stop && (!esc || *(src - 1) != '\\')) return stop;
+        src = stop ? stop : src + 1;
+      }
+    }
+
+    // skip to delimiter (mx) inside given range
+    // this will savely skip over all quoted strings
+    // recursive skip stuff delimited by start/stop
+    // first start/opener must be consumed already!
+    template<prelexer start, prelexer stop>
+    const char* skip_over_scopes(const char* src, const char* end) {
+
+      size_t level = 0;
+      bool in_squote = false;
+      bool in_dquote = false;
+      // bool in_braces = false;
+
+      while (*src) {
+
+        // check for abort condition
+        if (end && src >= end) break;
+
+        // has escaped sequence?
+        if (*src == '\\') {
+          ++ src; // skip this (and next)
+        }
+        else if (*src == '"') {
+          in_dquote = ! in_dquote;
+        }
+        else if (*src == '\'') {
+          in_squote = ! in_squote;
+        }
+        else if (in_dquote || in_squote) {
+          // take everything literally
+        }
+
+        // find another opener inside?
+        else if (const char* pos = start(src)) {
+          ++ level; // increase counter
+          src = pos - 1; // advance position
+        }
+
+        // look for the closer (maybe final, maybe not)
+        else if (const char* final = stop(src)) {
+          // only close one level?
+          if (level > 0) -- level;
+          // return position at end of stop
+          // delimiter may be multiple chars
+          else return final;
+          // advance position
+          src = final - 1;
+        }
+
+        // next
+        ++ src;
+      }
+
+      return 0;
+    }
+
+    // skip to a skip delimited by parentheses
+    // uses smart `skip_over_scopes` internally
+    const char* parenthese_scope(const char* src);
+
+    // skip to delimiter (mx) inside given range
+    // this will savely skip over all quoted strings
+    // recursive skip stuff delimited by start/stop
+    // first start/opener must be consumed already!
+    template<prelexer start, prelexer stop>
+    const char* skip_over_scopes(const char* src) {
+      return skip_over_scopes<start, stop>(src, 0);
+    }
+
+    // Match a sequence of characters delimited by the supplied chars.
+    template <prelexer start, prelexer stop>
+    const char* recursive_scopes(const char* src) {
+      // parse opener
+      src = start(src);
+      // abort if not found
+      if (!src) return 0;
+      // parse the rest until final closer
+      return skip_over_scopes<start, stop>(src);
+    }
+
+    // Match a sequence of characters delimited by the supplied strings.
+    template <const char* beg, const char* end, bool esc>
+    const char* delimited_by(const char* src) {
+      src = exactly<beg>(src);
+      if (!src) return 0;
+      const char* stop;
+      while (1) {
+        if (!*src) return 0;
+        stop = exactly<end>(src);
+        if (stop && (!esc || *(src - 1) != '\\')) return stop;
+        src = stop ? stop : src + 1;
+      }
+    }
+
+    // Tries to match a certain number of times (between the supplied interval).
+    template<prelexer mx, size_t lo, size_t hi>
+    const char* between(const char* src) {
+      for (size_t i = 0; i < lo; ++i) {
+        src = mx(src);
+        if (!src) return 0;
+      }
+      for (size_t i = lo; i <= hi; ++i) {
+        const char* new_src = mx(src);
+        if (!new_src) return src;
+        src = new_src;
+      }
+      return 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.
+    const char* double_quoted_string(const char* src);
+    const char* single_quoted_string(const char* src);
+    const char* quoted_string(const char* src);
+    // Match interpolants.
+    const char* interpolant(const char* src);
+    // Match number prefix ([\+\-]+)
+    const char* number_prefix(const char* src);
+
+    // Match zero plus white-space or line_comments
+    const char* optional_css_whitespace(const char* src);
+    const char* css_whitespace(const char* src);
+    // Match optional_css_whitepace plus block_comments
+    const char* optional_css_comments(const char* src);
+    const char* css_comments(const char* src);
+
+    // Match one backslash escaped char
+    const char* escape_seq(const char* src);
+
+    // Match CSS css variables.
+    const char* custom_property_name(const char* src);
+    // Match a CSS identifier.
+    const char* identifier(const char* src);
+    const char* identifier_alpha(const char* src);
+    const char* identifier_alnum(const char* src);
+    const char* strict_identifier(const char* src);
+    const char* strict_identifier_alpha(const char* src);
+    const char* strict_identifier_alnum(const char* src);
+    // Match a CSS unit identifier.
+    const char* unit_identifier(const char* src);
+    // const char* strict_identifier_alnums(const char* src);
+    // Match reference selector.
+    const char* re_reference_combinator(const char* src);
+    const char* static_reference_combinator(const char* src);
+    const char* schema_reference_combinator(const char* src);
+
+    // Match interpolant schemas
+    const char* identifier_schema(const char* src);
+    const char* value_schema(const char* src);
+    // const char* filename(const char* src);
+    // const char* filename_schema(const char* src);
+    // const char* url_schema(const char* src);
+    // const char* url_value(const char* src);
+    const char* vendor_prefix(const char* src);
+    // Match CSS '@' keywords.
+    const char* at_keyword(const char* src);
+    const char* kwd_import(const char* src);
+    const char* kwd_at_root(const char* src);
+    const char* kwd_with_directive(const char* src);
+    const char* kwd_without_directive(const char* src);
+    const char* kwd_media(const char* src);
+    const char* kwd_supports_directive(const char* src);
+    // const char* keyframes(const char* src);
+    // const char* keyf(const char* src);
+    const char* kwd_mixin(const char* src);
+    const char* kwd_function(const char* src);
+    const char* kwd_return_directive(const char* src);
+    const char* kwd_include_directive(const char* src);
+    const char* kwd_content_directive(const char* src);
+    const char* kwd_charset_directive(const char* src);
+    const char* kwd_extend(const char* src);
+
+    const char* unicode_seq(const char* src);
+
+    const char* kwd_if_directive(const char* src);
+    const char* kwd_else_directive(const char* src);
+    const char* elseif_directive(const char* src);
+
+    const char* kwd_for_directive(const char* src);
+    const char* kwd_from(const char* src);
+    const char* kwd_to(const char* src);
+    const char* kwd_through(const char* src);
+
+    const char* kwd_each_directive(const char* src);
+    const char* kwd_in(const char* src);
+
+    const char* kwd_while_directive(const char* src);
+
+    const char* re_nothing(const char* src);
+    const char* re_type_selector2(const char* src);
+
+
+    const char* kwd_warn(const char* src);
+    const char* kwd_err(const char* src);
+    const char* kwd_dbg(const char* src);
+
+    const char* kwd_null(const char* src);
+
+    const char* re_type_selector(const char* src);
+    const char* re_static_expression(const char* src);
+
+    // identifier that can start with hyphens
+    const char* css_identifier(const char* src);
+    const char* css_ip_identifier(const char* src);
+
+    // Match CSS type selectors
+    const char* namespace_schema(const char* src);
+    const char* namespace_prefix(const char* src);
+    const char* type_selector(const char* src);
+    const char* hyphens_and_identifier(const char* src);
+    const char* hyphens_and_name(const char* src);
+    const char* universal(const char* src);
+    // Match CSS id names.
+    const char* id_name(const char* src);
+    // Match CSS class names.
+    const char* class_name(const char* src);
+    // Attribute name in an attribute selector
+    const char* attribute_name(const char* src);
+    // Match placeholder selectors.
+    const char* placeholder(const char* src);
+    // Match CSS numeric constants.
+    const char* sign(const char* src);
+    const char* unsigned_number(const char* src);
+    const char* number(const char* src);
+    const char* coefficient(const char* src);
+    const char* binomial(const char* src);
+    const char* percentage(const char* src);
+    const char* ampersand(const char* src);
+    const char* dimension(const char* src);
+    const char* hex(const char* src);
+    const char* hexa(const char* src);
+    const char* hex0(const char* src);
+    // const char* rgb_prefix(const char* src);
+    // 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.
+    const char* kwd_optional(const char* src);
+    // Match Sass "!default" keyword.
+    const char* default_flag(const char* src);
+    const char* global_flag(const char* src);
+    // Match CSS pseudo-class/element prefixes
+    const char* pseudo_prefix(const char* src);
+    // Match CSS function call openers.
+    const char* re_functional(const char* src);
+    const char* re_pseudo_selector(const char* src);
+    const char* functional_schema(const char* src);
+    const char* pseudo_not(const char* src);
+    // Match CSS 'odd' and 'even' keywords for functional pseudo-classes.
+    const char* even(const char* src);
+    const char* odd(const char* src);
+    // Match CSS attribute-matching operators.
+    const char* exact_match(const char* src);
+    const char* class_match(const char* src);
+    const char* dash_match(const char* src);
+    const char* prefix_match(const char* src);
+    const char* suffix_match(const char* src);
+    const char* substring_match(const char* src);
+    // Match CSS combinators.
+    // const char* adjacent_to(const char* src);
+    // const char* precedes(const char* src);
+    // const char* parent_of(const char* src);
+    // const char* ancestor_of(const char* src);
+
+    // Match SCSS variable names.
+    const char* variable(const char* src);
+
+    // IE stuff
+    const char* ie_progid(const char* src);
+    const char* ie_expression(const char* src);
+    const char* ie_property(const char* src);
+    const char* ie_keyword_arg(const char* src);
+    const char* ie_keyword_arg_value(const char* src);
+    const char* ie_keyword_arg_property(const char* src);
+
+    // match url()
+    const char* H(const char* src);
+    const char* W(const char* src);
+    // `UNICODE` makes VS sad
+    const char* UUNICODE(const char* src);
+    const char* NONASCII(const char* src);
+    const char* ESCAPE(const char* src);
+    const char* real_uri_suffix(const char* src);
+    // const char* real_uri_prefix(const char* src);
+    const char* real_uri_value(const char* src);
+
+    // Path matching functions.
+    // const char* folder(const char* src);
+    // const char* folders(const char* src);
+
+
+    const char* static_string(const char* src);
+    const char* static_component(const char* src);
+    const char* static_property(const char* src);
+    const char* static_value(const char* src);
+
+    // Utility functions for finding and counting characters in a string.
+    template<char c>
+    const char* find_first(const char* src) {
+      while (*src && *src != c) ++src;
+      return *src ? src : 0;
+    }
+    template<prelexer mx>
+    const char* find_first(const char* src) {
+      while (*src && !mx(src)) ++src;
+      return *src ? src : 0;
+    }
+    template<prelexer mx>
+    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 (mx(beg)) return beg;
+        ++beg;
+      }
+      return 0;
+    }
+    template <prelexer mx>
+    unsigned int count_interval(const char* beg, const char* end) {
+      unsigned int counter = 0;
+      bool esc = false;
+      while (beg < end && *beg) {
+        const char* p;
+        if (esc) {
+          esc = false;
+          ++beg;
+        } else if (*beg == '\\') {
+          esc = true;
+          ++beg;
+        } else if ((p = mx(beg))) {
+          ++counter;
+          beg = p;
+        }
+        else {
+          ++beg;
+        }
+      }
+      return counter;
+    }
+
+    template <size_t size, prelexer mx, prelexer pad>
+    const char* padded_token(const char* src);
+
+    template <size_t min, size_t max, prelexer mx>
+    const char* minmax_range(const char* src);
+
+  }
+}
+
+#endif
diff --git a/libsass/src/remove_placeholders.cpp b/libsass/src/remove_placeholders.cpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/remove_placeholders.cpp
@@ -0,0 +1,55 @@
+#include "remove_placeholders.hpp"
+#include "context.hpp"
+#include "inspect.hpp"
+#include "to_string.hpp"
+#include <iostream>
+
+namespace Sass {
+
+    Remove_Placeholders::Remove_Placeholders(Context& ctx)
+    : ctx(ctx)
+    { }
+
+    void Remove_Placeholders::operator()(Block* b) {
+        for (size_t i = 0, L = b->length(); i < L; ++i) {
+            (*b)[i]->perform(this);
+        }
+    }
+
+    void Remove_Placeholders::operator()(Ruleset* r) {
+        // Create a new selector group without placeholders
+        Selector_List* sl = static_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(new_sl);
+        }
+
+        // Iterate into child blocks
+        Block* b = r->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* 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()(At_Rule* a) {
+        if (a->block()) a->block()->perform(this);
+    }
+
+}
diff --git a/libsass/src/remove_placeholders.hpp b/libsass/src/remove_placeholders.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/remove_placeholders.hpp
@@ -0,0 +1,37 @@
+#ifndef SASS_REMOVE_PLACEHOLDERS_H
+#define SASS_REMOVE_PLACEHOLDERS_H
+
+#pragma once
+
+#include "ast.hpp"
+#include "operation.hpp"
+
+namespace Sass {
+
+
+    class Context;
+
+    class Remove_Placeholders : public Operation_CRTP<void, Remove_Placeholders> {
+
+        Context&          ctx;
+
+        void fallback_impl(AST_Node* n) {}
+
+    public:
+        Remove_Placeholders(Context&);
+        virtual ~Remove_Placeholders() { }
+
+        using Operation<void>::operator();
+
+        void operator()(Block*);
+        void operator()(Ruleset*);
+        void operator()(Media_Block*);
+        void operator()(At_Rule*);
+
+        template <typename U>
+        void fallback(U x) { return fallback_impl(x); }
+    };
+
+}
+
+#endif
diff --git a/libsass/src/sass.cpp b/libsass/src/sass.cpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/sass.cpp
@@ -0,0 +1,41 @@
+#include <cstdlib>
+#include <cstring>
+#include <vector>
+#include <sstream>
+
+#include "sass.h"
+#include "file.hpp"
+#include "util.hpp"
+
+extern "C" {
+  using namespace Sass;
+
+  // 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());
+  }
+
+  // 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());
+  }
+
+  // Make sure to free the returned value!
+  // Incs array has to be null terminated!
+  char* ADDCALL sass_resolve_file (const char* file, const char* paths[])
+  {
+    std::string resolved(File::find_file(file, paths));
+    return sass_strdup(resolved.c_str());
+  }
+
+  // Get compiled libsass version
+  const char* ADDCALL libsass_version(void)
+  {
+    return LIBSASS_VERSION;
+  }
+
+}
diff --git a/libsass/src/sass2scss.cpp b/libsass/src/sass2scss.cpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/sass2scss.cpp
@@ -0,0 +1,845 @@
+/**
+ * sass2scss
+ * Licensed under the MIT License
+ * Copyright (c) Marcel Greter
+ */
+
+#ifdef _MSC_VER
+#define _CRT_SECURE_NO_WARNINGS
+#define _CRT_NONSTDC_NO_DEPRECATE
+#endif
+
+// include library
+#include <stack>
+#include <string>
+#include <cstring>
+#include <cstdlib>
+#include <sstream>
+#include <iostream>
+#include <stdio.h>
+
+///*
+//
+// src comments: comments in sass syntax (staring with //)
+// css comments: multiline comments in css syntax (starting with /*)
+//
+// KEEP_COMMENT: keep src comments in the resulting css code
+// STRIP_COMMENT: strip out all comments (either src or css)
+// CONVERT_COMMENT: convert all src comments to css comments
+//
+//*/
+
+// our own header
+#include "sass2scss.h"
+
+// add namespace for c++
+namespace Sass
+{
+
+	// return the actual prettify value from options
+	#define PRETTIFY(converter) (converter.options - (converter.options & 248))
+	// query the options integer to check if the option is enables
+	#define KEEP_COMMENT(converter) ((converter.options & SASS2SCSS_KEEP_COMMENT) == SASS2SCSS_KEEP_COMMENT)
+	#define STRIP_COMMENT(converter) ((converter.options & SASS2SCSS_STRIP_COMMENT) == SASS2SCSS_STRIP_COMMENT)
+	#define CONVERT_COMMENT(converter) ((converter.options & SASS2SCSS_CONVERT_COMMENT) == SASS2SCSS_CONVERT_COMMENT)
+
+	// some makros to access the indentation stack
+	#define INDENT(converter) (converter.indents.top())
+
+	// some makros to query comment parser status
+	#define IS_PARSING(converter) (converter.comment == "")
+	#define IS_COMMENT(converter) (converter.comment != "")
+	#define IS_SRC_COMMENT(converter) (converter.comment == "//" && ! CONVERT_COMMENT(converter))
+	#define IS_CSS_COMMENT(converter) (converter.comment == "/*" || (converter.comment == "//" && CONVERT_COMMENT(converter)))
+
+	// pretty printer helper function
+	static std::string closer (const converter& converter)
+	{
+		return PRETTIFY(converter) == 0 ? " }" :
+		     PRETTIFY(converter) <= 1 ? " }" :
+		       "\n" + INDENT(converter) + "}";
+	}
+
+	// pretty printer helper function
+	static std::string opener (const converter& converter)
+	{
+		return PRETTIFY(converter) == 0 ? " { " :
+		     PRETTIFY(converter) <= 2 ? " {" :
+		       "\n" + INDENT(converter) + "{";
+	}
+
+	// check if the given string is a pseudo selector
+	// needed to differentiate from sass property syntax
+	static bool isPseudoSelector (std::string& sel)
+	{
+
+		size_t len = sel.length();
+		if (len < 1) return false;
+		size_t pos = sel.find_first_not_of("abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ", 1);
+		if (pos != std::string::npos) sel.erase(pos, std::string::npos);
+		size_t i = sel.length();
+		while (i -- > 0) { sel.at(i) = tolower(sel.at(i)); }
+
+		// CSS Level 1 - Recommendation
+		if (sel == ":link") return true;
+		if (sel == ":visited") return true;
+		if (sel == ":active") return true;
+
+		// CSS Level 2 (Revision 1) - Recommendation
+		if (sel == ":lang") return true;
+		if (sel == ":first-child") return true;
+		if (sel == ":hover") return true;
+		if (sel == ":focus") return true;
+		// disabled - also valid properties
+		// if (sel == ":left") return true;
+		// if (sel == ":right") return true;
+		if (sel == ":first") return true;
+
+		// Selectors Level 3 - Recommendation
+		if (sel == ":target") return true;
+		if (sel == ":root") return true;
+		if (sel == ":nth-child") return true;
+		if (sel == ":nth-last-of-child") return true;
+		if (sel == ":nth-of-type") return true;
+		if (sel == ":nth-last-of-type") return true;
+		if (sel == ":last-child") return true;
+		if (sel == ":first-of-type") return true;
+		if (sel == ":last-of-type") return true;
+		if (sel == ":only-child") return true;
+		if (sel == ":only-of-type") return true;
+		if (sel == ":empty") return true;
+		if (sel == ":not") return true;
+
+		// CSS Basic User Interface Module Level 3 - Working Draft
+		if (sel == ":default") return true;
+		if (sel == ":valid") return true;
+		if (sel == ":invalid") return true;
+		if (sel == ":in-range") return true;
+		if (sel == ":out-of-range") return true;
+		if (sel == ":required") return true;
+		if (sel == ":optional") return true;
+		if (sel == ":read-only") return true;
+		if (sel == ":read-write") return true;
+		if (sel == ":dir") return true;
+		if (sel == ":enabled") return true;
+		if (sel == ":disabled") return true;
+		if (sel == ":checked") return true;
+		if (sel == ":indeterminate") return true;
+		if (sel == ":nth-last-child") return true;
+
+		// Selectors Level 4 - Working Draft
+		if (sel == ":any-link") return true;
+		if (sel == ":local-link") return true;
+		if (sel == ":scope") return true;
+		if (sel == ":active-drop-target") return true;
+		if (sel == ":valid-drop-target") return true;
+		if (sel == ":invalid-drop-target") return true;
+		if (sel == ":current") return true;
+		if (sel == ":past") return true;
+		if (sel == ":future") return true;
+		if (sel == ":placeholder-shown") return true;
+		if (sel == ":user-error") return true;
+		if (sel == ":blank") return true;
+		if (sel == ":nth-match") return true;
+		if (sel == ":nth-last-match") return true;
+		if (sel == ":nth-column") return true;
+		if (sel == ":nth-last-column") return true;
+		if (sel == ":matches") return true;
+
+		// Fullscreen API - Living Standard
+		if (sel == ":fullscreen") return true;
+
+		// not a pseudo selector
+		return false;
+
+	}
+
+	// check if there is some char data
+	// will ignore everything in comments
+	static bool hasCharData (std::string& sass)
+	{
+
+		size_t col_pos = 0;
+
+		while (true)
+		{
+
+			// try to find some meaningfull char
+			col_pos = sass.find_first_not_of(" \t\n\v\f\r", col_pos);
+
+			// there was no meaningfull char found
+			if (col_pos == std::string::npos) return false;
+
+			// found a multiline comment opener
+			if (sass.substr(col_pos, 2) == "/*")
+			{
+				// find the multiline comment closer
+				col_pos = sass.find("*/", col_pos);
+				// maybe we did not find the closer here
+				if (col_pos == std::string::npos) return false;
+				// skip closer
+				col_pos += 2;
+			}
+			else
+			{
+				return true;
+			}
+
+		}
+
+	}
+	// EO hasCharData
+
+	// find src comment opener
+	// correctly skips quoted strings
+	static size_t findCommentOpener (std::string& sass)
+	{
+
+		size_t col_pos = 0;
+		bool apoed = false;
+		bool quoted = false;
+		bool comment = false;
+		size_t brackets = 0;
+
+		while (col_pos != std::string::npos)
+		{
+
+			// process all interesting chars
+			col_pos = sass.find_first_of("\"\'/\\*()", col_pos);
+
+			// assertion for valid result
+			if (col_pos != std::string::npos)
+			{
+				char character = sass.at(col_pos);
+
+				if (character == '(')
+				{
+					if (!quoted && !apoed) brackets ++;
+				}
+				else if (character == ')')
+				{
+					if (!quoted && !apoed) brackets --;
+				}
+				else if (character == '\"')
+				{
+					// invert quote bool
+					if (!apoed && !comment) quoted = !quoted;
+				}
+				else if (character == '\'')
+				{
+					// invert quote bool
+					if (!quoted && !comment) apoed = !apoed;
+				}
+				else if (col_pos > 0 && character == '/')
+				{
+					if (sass.at(col_pos - 1) == '*')
+					{
+						comment = false;
+					}
+					// next needs to be a slash too
+					else if (sass.at(col_pos - 1) == '/')
+					{
+						// only found if not in single or double quote, bracket or comment
+						if (!quoted && !apoed && !comment && brackets == 0) return col_pos - 1;
+					}
+				}
+				else if (character == '\\')
+				{
+					// skip next char if in quote
+					if (quoted || apoed) col_pos ++;
+				}
+				// this might be a comment opener
+				else if (col_pos > 0 && character == '*')
+				{
+					// opening a multiline comment
+					if (sass.at(col_pos - 1) == '/')
+					{
+						// we are now in a comment
+						if (!quoted && !apoed) comment = true;
+					}
+				}
+
+				// skip char
+				col_pos ++;
+
+			}
+
+		}
+		// EO while
+
+		return col_pos;
+
+	}
+	// EO findCommentOpener
+
+	// remove multiline comments from sass string
+	// correctly skips quoted strings
+	static std::string removeMultilineComment (std::string &sass)
+	{
+
+		std::string clean = "";
+		size_t col_pos = 0;
+		size_t open_pos = 0;
+		size_t close_pos = 0;
+		bool apoed = false;
+		bool quoted = false;
+		bool comment = false;
+
+		// process sass til string end
+		while (col_pos != std::string::npos)
+		{
+
+			// process all interesting chars
+			col_pos = sass.find_first_of("\"\'/\\*", col_pos);
+
+			// assertion for valid result
+			if (col_pos != std::string::npos)
+			{
+				char character = sass.at(col_pos);
+
+				// found quoted string delimiter
+				if (character == '\"')
+				{
+					if (!apoed && !comment) quoted = !quoted;
+				}
+				else if (character == '\'')
+				{
+					if (!quoted && !comment) apoed = !apoed;
+				}
+				// found possible comment closer
+				else if (character == '/')
+				{
+					// look back to see if it is actually a closer
+					if (comment && col_pos > 0 && sass.at(col_pos - 1) == '*')
+					{
+						close_pos = col_pos + 1; comment = false;
+					}
+				}
+				else if (character == '\\')
+				{
+					// skip escaped char
+					if (quoted || apoed) col_pos ++;
+				}
+				// this might be a comment opener
+				else if (character == '*')
+				{
+					// look back to see if it is actually an opener
+					if (!quoted && !apoed && col_pos > 0 && sass.at(col_pos - 1) == '/')
+					{
+						comment = true; open_pos = col_pos - 1;
+						clean += sass.substr(close_pos, open_pos - close_pos);
+					}
+				}
+
+				// skip char
+				col_pos ++;
+
+			}
+
+		}
+		// EO while
+
+		// add final parts (add half open comment text)
+		if (comment) clean += sass.substr(open_pos);
+		else clean += sass.substr(close_pos);
+
+		// return string
+		return clean;
+
+	}
+	// EO removeMultilineComment
+
+	// right trim a given string
+	std::string rtrim(const std::string &sass)
+	{
+		std::string trimmed = sass;
+		size_t pos_ws = trimmed.find_last_not_of(" \t\n\v\f\r");
+		if (pos_ws != std::string::npos)
+		{ trimmed.erase(pos_ws + 1); }
+		else { trimmed.clear(); }
+		return trimmed;
+	}
+	// EO rtrim
+
+	// flush whitespace and print additional text, but
+	// only print additional chars and buffer whitespace
+	std::string flush (std::string& sass, converter& converter)
+	{
+
+		// return flushed
+		std::string scss = "";
+
+		// print whitespace buffer
+		scss += PRETTIFY(converter) > 0 ?
+		        converter.whitespace : "";
+		// reset whitespace buffer
+		converter.whitespace = "";
+
+		// remove possible newlines from string
+		size_t pos_right = sass.find_last_not_of("\n\r");
+		if (pos_right == std::string::npos) return scss;
+
+		// get the linefeeds from the string
+		std::string lfs = sass.substr(pos_right + 1);
+		sass = sass.substr(0, pos_right + 1);
+
+		// find some source comment opener
+		size_t comment_pos = findCommentOpener(sass);
+		// check if there was a source comment
+		if (comment_pos != std::string::npos)
+		{
+			// convert comment (but only outside other coments)
+			if (CONVERT_COMMENT(converter) && !IS_COMMENT(converter))
+			{
+				// convert to multiline comment
+				sass.at(comment_pos + 1) = '*';
+				// add comment node to the whitespace
+				sass += " */";
+			}
+			// not at line start
+			if (comment_pos > 0)
+			{
+				// also include whitespace before the actual comment opener
+				size_t ws_pos = sass.find_last_not_of(SASS2SCSS_FIND_WHITESPACE, comment_pos - 1);
+				comment_pos = ws_pos == std::string::npos ? 0 : ws_pos + 1;
+			}
+			if (!STRIP_COMMENT(converter))
+			{
+				// add comment node to the whitespace
+				converter.whitespace += sass.substr(comment_pos);
+			}
+			else
+			{
+				// sass = removeMultilineComments(sass);
+			}
+			// update the actual sass code
+			sass = sass.substr(0, comment_pos);
+		}
+
+		// add newline as getline discharged it
+		converter.whitespace += lfs + "\n";
+
+		// maybe remove any leading whitespace
+		if (PRETTIFY(converter) == 0)
+		{
+			// remove leading whitespace and update string
+			size_t pos_left = sass.find_first_not_of(SASS2SCSS_FIND_WHITESPACE);
+			if (pos_left != std::string::npos) sass = sass.substr(pos_left);
+		}
+
+		// add flushed data
+		scss += sass;
+
+		// return string
+		return scss;
+
+	}
+	// EO flush
+
+	// process a line of the sass text
+	std::string process (std::string& sass, converter& converter)
+	{
+
+		// resulting string
+		std::string scss = "";
+
+		// strip multi line comments
+		if (STRIP_COMMENT(converter))
+		{
+			sass = removeMultilineComment(sass);
+		}
+
+		// right trim input
+		sass = rtrim(sass);
+
+		// get postion of first meaningfull character in string
+		size_t pos_left = sass.find_first_not_of(SASS2SCSS_FIND_WHITESPACE);
+
+		// special case for final run
+		if (converter.end_of_file) pos_left = 0;
+
+		// maybe has only whitespace
+		if (pos_left == std::string::npos)
+		{
+			// just add complete whitespace
+			converter.whitespace += sass + "\n";
+		}
+		// have meaningfull first char
+		else
+		{
+
+			// extract and store indentation string
+			std::string indent = sass.substr(0, pos_left);
+
+			// check if current line starts a comment
+			std::string open = sass.substr(pos_left, 2);
+
+			// line has less or same indentation
+			// finalize previous open parser context
+			if (indent.length() <= INDENT(converter).length())
+			{
+
+				// close multilinie comment
+				if (IS_CSS_COMMENT(converter))
+				{
+					// check if comments will be stripped anyway
+					if (!STRIP_COMMENT(converter)) scss += " */";
+				}
+				// close src comment comment
+				else if (IS_SRC_COMMENT(converter))
+				{
+					// add a newline to avoid closer on same line
+					// this would put the bracket in the comment node
+					// no longer needed since we parse them correctly
+					// if (KEEP_COMMENT(converter)) scss += "\n";
+				}
+				// close css properties
+				else if (converter.property)
+				{
+					// add closer unless in concat mode
+					if (!converter.comma)
+					{
+						// if there was no colon we have a selector
+						// looks like there were no inner properties
+						if (converter.selector) scss += " {}";
+						// add final semicolon
+						else if (!converter.semicolon) scss += ";";
+					}
+				}
+
+				// reset comment state
+				converter.comment = "";
+
+			}
+
+			// make sure we close every "higher" block
+			while (indent.length() < INDENT(converter).length())
+			{
+				// pop stacked context
+				converter.indents.pop();
+				// print close bracket
+				if (IS_PARSING(converter))
+				{ scss += closer(converter); }
+				else { scss += " */"; }
+				// reset comment state
+				converter.comment = "";
+			}
+
+			// reset converter state
+			converter.selector = false;
+
+			// check if we have sass property syntax
+			if (sass.substr(pos_left, 1) == ":" && sass.substr(pos_left, 2) != "::")
+			{
+
+				// default to a selector
+				// change back if property found
+				converter.selector = true;
+				// get postion of first whitespace char
+				size_t pos_wspace = sass.find_first_of(SASS2SCSS_FIND_WHITESPACE, pos_left);
+				// assertion check for valid result
+				if (pos_wspace != std::string::npos)
+				{
+					// get the possible pseudo selector
+					std::string pseudo = sass.substr(pos_left, pos_wspace - pos_left);
+					// get position of the first real property value char
+					// pseudo selectors get this far, but have no actual value
+					size_t pos_value =  sass.find_first_not_of(SASS2SCSS_FIND_WHITESPACE, pos_wspace);
+					// assertion check for valid result
+					if (pos_value != std::string::npos)
+					{
+						// only process if not (fallowed by a semicolon or is a pseudo selector)
+						if (!(sass.at(pos_value) == ':' || isPseudoSelector(pseudo)))
+						{
+							// create new string by interchanging the colon sign for property and value
+							sass = indent + sass.substr(pos_left + 1, pos_wspace - pos_left - 1) + ":" + sass.substr(pos_wspace);
+							// try to find a colon in the current line, but only ...
+							size_t pos_colon = sass.find_first_not_of(":", pos_left);
+							// assertion for valid result
+							if (pos_colon != std::string::npos)
+							{
+								// ... after the first word (skip begining colons)
+								pos_colon = sass.find_first_of(":", pos_colon);
+								// it is a selector if there was no colon found
+								converter.selector = pos_colon == std::string::npos;
+							}
+						}
+					}
+				}
+
+			}
+
+			// terminate some statements immediately
+			else if (
+				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 = 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)
+			{ 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); }
+
+			// add quotes for import if needed
+			else if (sass.substr(pos_left, 7) == "@import")
+			{
+				// get positions for the actual import url
+				size_t pos_import = sass.find_first_of(SASS2SCSS_FIND_WHITESPACE, pos_left + 7);
+				size_t pos_quote = sass.find_first_not_of(SASS2SCSS_FIND_WHITESPACE, pos_import);
+				// leave proper urls untouched
+				if (sass.substr(pos_quote, 4) != "url(")
+				{
+					// check if the url appears to be already quoted
+					if (sass.substr(pos_quote, 1) != "\"" && sass.substr(pos_quote, 1) != "\'")
+					{
+						// get position of the last char on the line
+						size_t pos_end = sass.find_last_not_of(SASS2SCSS_FIND_WHITESPACE);
+						// assertion check for valid result
+						if (pos_end != std::string::npos)
+						{
+							// add quotes around the full line after the import statement
+							sass = sass.substr(0, pos_quote) + "\"" + sass.substr(pos_quote, pos_end - pos_quote + 1) + "\"";
+						}
+					}
+				}
+
+			}
+			else if (
+				sass.substr(pos_left, 7) != "@return" &&
+				sass.substr(pos_left, 7) != "@extend" &&
+				sass.substr(pos_left, 8) != "@include" &&
+				sass.substr(pos_left, 8) != "@content"
+			) {
+
+				// probably a selector anyway
+				converter.selector = true;
+				// try to find first colon in the current line
+				size_t pos_colon = sass.find_first_of(":", pos_left);
+				// assertion that we have a colon
+				if (pos_colon != std::string::npos)
+				{
+					// it is not a selector if we have a space after a colon
+					if (sass[pos_colon+1] == ' ') converter.selector = false;
+					if (sass[pos_colon+1] == '	') converter.selector = false;
+				}
+
+			}
+
+			// current line has more indentation
+			if (indent.length() >= INDENT(converter).length())
+			{
+				// not in comment mode
+				if (IS_PARSING(converter))
+				{
+					// has meaningfull chars
+					if (hasCharData(sass))
+					{
+						// is probably a property
+						// also true for selectors
+						converter.property = true;
+					}
+				}
+			}
+			// current line has more indentation
+			if (indent.length() > INDENT(converter).length())
+			{
+				// not in comment mode
+				if (IS_PARSING(converter))
+				{
+					// had meaningfull chars
+					if (converter.property)
+					{
+						// print block opener
+						scss += opener(converter);
+						// push new stack context
+						converter.indents.push("");
+						// store block indentation
+						INDENT(converter) = indent;
+					}
+				}
+				// is and will be a src comment
+				else if (!IS_CSS_COMMENT(converter))
+				{
+					// scss does not allow multiline src comments
+					// therefore add forward slashes to all lines
+					sass.at(INDENT(converter).length()+0) = '/';
+					// there is an edge case here if indentation
+					// is minimal (will overwrite the fist char)
+					sass.at(INDENT(converter).length()+1) = '/';
+					// could code around that, but I dont' think
+					// this will ever be the cause for any trouble
+				}
+			}
+
+			// line is opening a new comment
+			if (open == "/*" || open == "//")
+			{
+				// reset the property state
+				converter.property = false;
+				// close previous comment
+				if (IS_CSS_COMMENT(converter) && open != "")
+				{
+					if (!STRIP_COMMENT(converter) && !CONVERT_COMMENT(converter)) scss += " */";
+				}
+				// force single line comments
+				// into a correct css comment
+				if (CONVERT_COMMENT(converter))
+				{
+					if (IS_PARSING(converter))
+					{ sass.at(pos_left + 1) = '*'; }
+				}
+				// set comment flag
+				converter.comment = open;
+
+			}
+
+			// flush data only under certain conditions
+			if (!(
+				// strip css and src comments if option is set
+				(IS_COMMENT(converter) && STRIP_COMMENT(converter)) ||
+				// strip src comment even if strip option is not set
+				// but only if the keep src comment option is not set
+				(IS_SRC_COMMENT(converter) && ! KEEP_COMMENT(converter))
+			))
+			{
+				// flush data and buffer whitespace
+				scss += flush(sass, converter);
+			}
+
+			// get postion of last meaningfull char
+			size_t pos_right = sass.find_last_not_of(SASS2SCSS_FIND_WHITESPACE);
+
+			// check for invalid result
+			if (pos_right != std::string::npos)
+			{
+
+				// get the last meaningfull char
+				std::string close = sass.substr(pos_right, 1);
+
+				// check if next line should be concatenated (list mode)
+				converter.comma = IS_PARSING(converter) && close == ",";
+				converter.semicolon = IS_PARSING(converter) && close == ";";
+
+				// check if we have more than
+				// one meaningfull char
+				if (pos_right > 0)
+				{
+
+					// get the last two chars from string
+					std::string close = sass.substr(pos_right - 1, 2);
+					// update parser status for expicitly closed comment
+					if (close == "*/") converter.comment = "";
+
+				}
+
+			}
+			// EO have meaningfull chars from end
+
+		}
+		// EO have meaningfull chars from start
+
+		// return scss
+		return scss;
+
+	}
+	// EO process
+
+	// read line with either CR, LF or CR LF format
+	// http://stackoverflow.com/a/6089413/1550314
+	static std::istream& safeGetline(std::istream& is, std::string& t)
+	{
+		t.clear();
+
+		// The characters in the stream are read one-by-one using a std::streambuf.
+		// That is faster than reading them one-by-one using the std::istream.
+		// Code that uses streambuf this way must be guarded by a sentry object.
+		// The sentry object performs various tasks,
+		// such as thread synchronization and updating the stream state.
+
+		std::istream::sentry se(is, true);
+		std::streambuf* sb = is.rdbuf();
+
+		for(;;) {
+			int c = sb->sbumpc();
+			switch (c) {
+				case '\n':
+					return is;
+				case '\r':
+					if(sb->sgetc() == '\n')
+						sb->sbumpc();
+					return is;
+				case EOF:
+					// Also handle the case when the last line has no line ending
+					if(t.empty())
+						is.setstate(std::ios::eofbit);
+					return is;
+				default:
+					t += (char)c;
+			}
+		}
+	}
+
+	// the main converter function for c++
+	char* sass2scss (const std::string& sass, const int options)
+	{
+
+		// local variables
+		std::string line;
+		std::string scss = "";
+		std::stringstream stream(sass);
+
+		// create converter variable
+		converter converter;
+		// initialise all options
+		converter.comma = false;
+		converter.property = false;
+		converter.selector = false;
+		converter.semicolon = false;
+		converter.end_of_file = false;
+		converter.comment = "";
+		converter.whitespace = "";
+		converter.indents.push("");
+		converter.options = options;
+
+		// read line by line and process them
+		while(safeGetline(stream, line) && !stream.eof())
+		{ scss += process(line, converter); }
+
+		// create mutable string
+		std::string closer = "";
+		// set the end of file flag
+		converter.end_of_file = true;
+		// process to close all open blocks
+		scss += process(closer, converter);
+
+		// allocate new memory on the heap
+		// caller has to free it after use
+		char * cstr = (char*) malloc (scss.length() + 1);
+		// create a copy of the string
+		strcpy (cstr, scss.c_str());
+		// return pointer
+		return &cstr[0];
+
+	}
+	// EO sass2scss
+
+}
+// EO namespace
+
+// implement for c
+extern "C"
+{
+
+	char* ADDCALL sass2scss (const char* sass, const int options)
+	{
+		return Sass::sass2scss(sass, options);
+	}
+
+	// Get compiled sass2scss version
+	const char* ADDCALL sass2scss_version(void) {
+		return SASS2SCSS_VERSION;
+	}
+
+}
diff --git a/libsass/src/sass_context.cpp b/libsass/src/sass_context.cpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/sass_context.cpp
@@ -0,0 +1,708 @@
+#include <cstring>
+#include <stdexcept>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "sass.h"
+#include "file.hpp"
+#include "json.hpp"
+#include "util.hpp"
+#include "context.hpp"
+#include "sass_context.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; }
+
+  static int handle_errors(Sass_Context* c_ctx) {
+    try {
+     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: ");
+      bool got_newline = false;
+      msg_stream << msg_prefix;
+      const char* msg = e.what();
+      while(msg && *msg) {
+        if (*msg == '\r') {
+          got_newline = true;
+        } else if (*msg == '\n') {
+          got_newline = true;
+        } else if (got_newline) {
+          msg_stream << std::string(msg_prefix.size(), ' ');
+          got_newline = false;
+        }
+        msg_stream << *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";
+
+      // 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;
+        }
+        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 ++;
+        }
+        size_t max_left = 42; size_t max_right = 78;
+        size_t move_in = e.pstate.column > max_left ? e.pstate.column - max_left : 0;
+        size_t shorten = (line_end - line_beg) - move_in > max_right ?
+                         (line_end - line_beg) - move_in - max_right : 0;
+        msg_stream << ">> " << std::string(line_beg + move_in, line_end - shorten) << "\n";
+        msg_stream << "   " << std::string(e.pstate.column - move_in, '-') << "^\n";
+      }
+
+      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, "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());
+      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_src = e.pstate.src;
+      c_ctx->output_string = 0;
+      c_ctx->source_map_string = 0;
+      json_delete(json_err);
+    }
+    catch (std::bad_alloc& ba) {
+      std::stringstream msg_stream;
+      JsonNode* json_err = json_mkobject();
+      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());
+      c_ctx->error_status = 2;
+      c_ctx->output_string = 0;
+      c_ctx->source_map_string = 0;
+      json_delete(json_err);
+    }
+    catch (std::exception& e) {
+      std::stringstream msg_stream;
+      JsonNode* json_err = json_mkobject();
+      msg_stream << "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());
+      c_ctx->error_status = 3;
+      c_ctx->output_string = 0;
+      c_ctx->source_map_string = 0;
+      json_delete(json_err);
+    }
+    catch (std::string& e) {
+      std::stringstream msg_stream;
+      JsonNode* json_err = json_mkobject();
+      msg_stream << "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());
+      c_ctx->error_status = 4;
+      c_ctx->output_string = 0;
+      c_ctx->source_map_string = 0;
+      json_delete(json_err);
+    }
+    catch (const char* e) {
+      std::stringstream msg_stream;
+      JsonNode* json_err = json_mkobject();
+      msg_stream << "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);
+      c_ctx->error_status = 4;
+      c_ctx->output_string = 0;
+      c_ctx->source_map_string = 0;
+      json_delete(json_err);
+    }
+    catch (...) {
+      std::stringstream msg_stream;
+      JsonNode* json_err = json_mkobject();
+      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");
+      c_ctx->error_status = 5;
+      c_ctx->output_string = 0;
+      c_ctx->source_map_string = 0;
+      json_delete(json_err);
+    }
+    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()
+  {
+    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;
+      }
+
+      // 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;
+      }
+
+      // free intermediate data
+      free(include_paths);
+      free(plugin_paths);
+
+      // register our custom functions
+      if (c_ctx->c_functions) {
+        auto this_func_data = c_ctx->c_functions;
+        while (this_func_data && *this_func_data) {
+          cpp_ctx->add_c_function(*this_func_data);
+          ++this_func_data;
+        }
+      }
+
+      // register our custom headers
+      if (c_ctx->c_headers) {
+        auto this_head_data = c_ctx->c_headers;
+        while (this_head_data && *this_head_data) {
+          cpp_ctx->add_c_header(*this_head_data);
+          ++this_head_data;
+        }
+      }
+
+      // register our custom importers
+      if (c_ctx->c_importers) {
+        auto this_imp_data = c_ctx->c_importers;
+        while (this_imp_data && *this_imp_data) {
+          cpp_ctx->add_c_importer(*this_imp_data);
+          ++this_imp_data;
+        }
+      }
+
+      // reset error status
+      c_ctx->error_json = 0;
+      c_ctx->error_text = 0;
+      c_ctx->error_message = 0;
+      c_ctx->error_status = 0;
+      // reset error position
+      c_ctx->error_src = 0;
+      c_ctx->error_file = 0;
+      c_ctx->error_line = std::string::npos;
+      c_ctx->error_column = std::string::npos;
+
+      // allocate a new compiler instance
+      Sass_Compiler* compiler = (struct Sass_Compiler*) calloc(1, sizeof(struct Sass_Compiler));
+      compiler->state = SASS_COMPILER_CREATED;
+
+      // store in sass compiler
+      compiler->c_ctx = c_ctx;
+      compiler->cpp_ctx = cpp_ctx;
+      cpp_ctx->c_compiler = compiler;
+
+      // use to parse block
+      return compiler;
+
+    }
+    // pass errors to generic error handler
+    catch (...) { handle_errors(c_ctx); }
+
+    // error
+    return 0;
+
+  }
+
+  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)
+  {
+
+    // prepare sass compiler with context and options
+    Sass_Compiler* compiler = sass_prepare_context(c_ctx, cpp_ctx);
+
+    try {
+      // call each compiler step
+      sass_compiler_parse(compiler);
+      sass_compiler_execute(compiler);
+    }
+    // pass errors to generic error handler
+    catch (...) { handle_errors(c_ctx); }
+
+    sass_delete_compiler(compiler);
+
+    return c_ctx->error_status;
+  }
+
+  inline void init_options (struct Sass_Options* options)
+  {
+    options->precision = 5;
+    options->indent = "  ";
+    options->linefeed = LFEED;
+  }
+
+  Sass_Options* ADDCALL sass_make_options (void)
+  {
+    struct Sass_Options* options = (struct Sass_Options*) calloc(1, sizeof(struct Sass_Options));
+    if (options == 0) { std::cerr << "Error allocating memory for options" << std::endl; return 0; }
+    init_options(options);
+    return options;
+  }
+
+  Sass_File_Context* ADDCALL sass_make_file_context(const char* input_path)
+  {
+    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;
+    init_options(ctx);
+    try {
+      if (input_path == 0) { throw(std::runtime_error("File context created without an input path")); }
+      if (*input_path == 0) { throw(std::runtime_error("File context created with empty input path")); }
+      sass_option_set_input_path(ctx, input_path);
+    } catch (...) {
+      handle_errors(ctx);
+    }
+    return ctx;
+  }
+
+  Sass_Data_Context* ADDCALL sass_make_data_context(char* source_string)
+  {
+    struct Sass_Data_Context* ctx = (struct Sass_Data_Context*) calloc(1, sizeof(struct Sass_Data_Context));
+    if (ctx == 0) { std::cerr << "Error allocating memory for data context" << std::endl; return 0; }
+    ctx->type = SASS_CONTEXT_DATA;
+    init_options(ctx);
+    try {
+      if (source_string == 0) { throw(std::runtime_error("Data context created without a source string")); }
+      if (*source_string == 0) { throw(std::runtime_error("Data context created with empty source string")); }
+      ctx->source_string = source_string;
+    } catch (...) {
+      handle_errors(ctx);
+    }
+    return ctx;
+  }
+
+  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);
+    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);
+    return sass_prepare_context(file_ctx, cpp_ctx);
+  }
+
+  int ADDCALL sass_compile_data_context(Sass_Data_Context* data_ctx)
+  {
+    if (data_ctx == 0) return 1;
+    if (data_ctx->error_status)
+      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")); }
+    }
+    catch (...) { return handle_errors(data_ctx) | 1; }
+    Context* cpp_ctx = new Data_Context(data_ctx);
+    return sass_compile_context(data_ctx, cpp_ctx);
+  }
+
+  int ADDCALL sass_compile_file_context(Sass_File_Context* file_ctx)
+  {
+    if (file_ctx == 0) return 1;
+    if (file_ctx->error_status)
+      return file_ctx->error_status;
+    try {
+      if (file_ctx->input_path == 0) { throw(std::runtime_error("File context has no input path")); }
+      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);
+    return sass_compile_context(file_ctx, cpp_ctx);
+  }
+
+  int ADDCALL sass_compiler_parse(struct Sass_Compiler* compiler)
+  {
+    if (compiler == 0) return 1;
+    if (compiler->state == SASS_COMPILER_PARSED) return 0;
+    if (compiler->state != SASS_COMPILER_CREATED) return -1;
+    if (compiler->c_ctx == NULL) return 1;
+    if (compiler->cpp_ctx == NULL) return 1;
+    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);
+    // success
+    return 0;
+  }
+
+  int ADDCALL sass_compiler_execute(struct Sass_Compiler* compiler)
+  {
+    if (compiler == 0) return 1;
+    if (compiler->state == SASS_COMPILER_EXECUTED) return 0;
+    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->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;
+    // compile the parsed root block
+    try { compiler->c_ctx->output_string = cpp_ctx->render(root); }
+    // pass catched errors to generic error handler
+    catch (...) { return handle_errors(compiler->c_ctx) | 1; }
+    // generate source map json and store on context
+    compiler->c_ctx->source_map_string = cpp_ctx->render_srcmap();
+    // success
+    return 0;
+  }
+
+  // helper function, not exported, only accessible locally
+  static void sass_clear_options (struct Sass_Options* options)
+  {
+    if (options == 0) return;
+    // Deallocate custom functions
+    if (options->c_functions) {
+      Sass_Function_List this_func_data = options->c_functions;
+      while (this_func_data && *this_func_data) {
+        free(*this_func_data);
+        ++this_func_data;
+      }
+    }
+    // Deallocate custom headers
+    if (options->c_headers) {
+      Sass_Importer_List this_head_data = options->c_headers;
+      while (this_head_data && *this_head_data) {
+        free(*this_head_data);
+        ++this_head_data;
+      }
+    }
+    // Deallocate custom importers
+    if (options->c_importers) {
+      Sass_Importer_List this_imp_data = options->c_importers;
+      while (this_imp_data && *this_imp_data) {
+        free(*this_imp_data);
+        ++this_imp_data;
+      }
+    }
+    // Deallocate inc paths
+    if (options->plugin_paths) {
+      struct string_list* cur;
+      struct string_list* next;
+      cur = options->plugin_paths;
+      while (cur) {
+        next = cur->next;
+        free(cur->string);
+        free(cur);
+        cur = next;
+      }
+    }
+    // Deallocate inc paths
+    if (options->include_paths) {
+      struct string_list* cur;
+      struct string_list* next;
+      cur = options->include_paths;
+      while (cur) {
+        next = cur->next;
+        free(cur->string);
+        free(cur);
+        cur = next;
+      }
+    }
+    // Free custom functions
+    free(options->c_functions);
+    // Free custom importers
+    free(options->c_importers);
+    free(options->c_headers);
+    // Reset our pointers
+    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
+  // sass_free_context is also defined in old sass_interface
+  static void sass_clear_context (struct Sass_Context* ctx)
+  {
+    if (ctx == 0) return;
+    // release the allocated memory (mostly via sass_strdup)
+    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;
+    ctx->source_map_string = 0;
+    ctx->error_message = 0;
+    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;
+    // now clear the options
+    sass_clear_options(ctx);
+  }
+
+  void ADDCALL sass_delete_compiler (struct Sass_Compiler* compiler)
+  {
+    if (compiler == 0) {
+      return;
+    }
+    Context* cpp_ctx = compiler->cpp_ctx;
+    if (cpp_ctx) delete(cpp_ctx);
+    compiler->cpp_ctx = 0;
+    free(compiler);
+  }
+
+  // Deallocate all associated memory with file context
+  void ADDCALL sass_delete_file_context (struct Sass_File_Context* ctx)
+  {
+    // clear the context and free it
+    sass_clear_context(ctx); free(ctx);
+  }
+  // Deallocate all associated memory with data context
+  void ADDCALL sass_delete_data_context (struct Sass_Data_Context* ctx)
+  {
+    // clean the source string if it was not passed
+    // we reset this member once we start parsing
+    if (ctx->source_string) free(ctx->source_string);
+    // clear the context and free it
+    sass_clear_context(ctx); free(ctx);
+  }
+
+  // Getters for sass context from specific implementations
+  struct Sass_Context* ADDCALL sass_file_context_get_context(struct Sass_File_Context* ctx) { return ctx; }
+  struct Sass_Context* ADDCALL sass_data_context_get_context(struct Sass_Data_Context* ctx) { return ctx; }
+
+  // Getters for context options from Sass_Context
+  struct Sass_Options* ADDCALL sass_context_get_options(struct Sass_Context* ctx) { return ctx; }
+  struct Sass_Options* ADDCALL sass_file_context_get_options(struct Sass_File_Context* ctx) { return ctx; }
+  struct Sass_Options* ADDCALL sass_data_context_get_options(struct Sass_Data_Context* ctx) { return ctx; }
+  void ADDCALL sass_file_context_set_options (struct Sass_File_Context* ctx, struct Sass_Options* opt) { copy_options(ctx, opt); }
+  void ADDCALL sass_data_context_set_options (struct Sass_Data_Context* ctx, struct Sass_Options* opt) { copy_options(ctx, opt); }
+
+  // Getters for Sass_Compiler options (get conected sass context)
+  enum Sass_Compiler_State ADDCALL sass_compiler_get_state(struct Sass_Compiler* compiler) { return compiler->state; }
+  struct Sass_Context* ADDCALL sass_compiler_get_context(struct Sass_Compiler* compiler) { return compiler->c_ctx; }
+  struct Sass_Options* ADDCALL sass_compiler_get_options(struct Sass_Compiler* compiler) { return compiler->c_ctx; }
+  // Getters for Sass_Compiler options (query import stack)
+  size_t ADDCALL sass_compiler_get_import_stack_size(struct Sass_Compiler* compiler) { return compiler->cpp_ctx->import_stack.size(); }
+  Sass_Import_Entry ADDCALL sass_compiler_get_last_import(struct Sass_Compiler* compiler) { return compiler->cpp_ctx->import_stack.back(); }
+  Sass_Import_Entry ADDCALL sass_compiler_get_import_entry(struct Sass_Compiler* compiler, size_t idx) { return compiler->cpp_ctx->import_stack[idx]; }
+
+  // Calculate the size of the stored null terminated array
+  size_t ADDCALL sass_context_get_included_files_size (struct Sass_Context* ctx)
+  { size_t l = 0; auto i = ctx->included_files; while (i && *i) { ++i; ++l; } return l; }
+
+  // Create getter and setters for options
+  IMPLEMENT_SASS_OPTION_ACCESSOR(int, precision);
+  IMPLEMENT_SASS_OPTION_ACCESSOR(enum Sass_Output_Style, output_style);
+  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, omit_source_map_url);
+  IMPLEMENT_SASS_OPTION_ACCESSOR(bool, is_indented_syntax_src);
+  IMPLEMENT_SASS_OPTION_ACCESSOR(Sass_Function_List, c_functions);
+  IMPLEMENT_SASS_OPTION_ACCESSOR(Sass_Importer_List, c_importers);
+  IMPLEMENT_SASS_OPTION_ACCESSOR(Sass_Importer_List, c_headers);
+  IMPLEMENT_SASS_OPTION_ACCESSOR(const char*, indent);
+  IMPLEMENT_SASS_OPTION_ACCESSOR(const char*, linefeed);
+  IMPLEMENT_SASS_OPTION_STRING_ACCESSOR(const char*, input_path, 0);
+  IMPLEMENT_SASS_OPTION_STRING_ACCESSOR(const char*, output_path, 0);
+  IMPLEMENT_SASS_OPTION_STRING_ACCESSOR(const char*, plugin_path, 0);
+  IMPLEMENT_SASS_OPTION_STRING_ACCESSOR(const char*, include_path, 0);
+  IMPLEMENT_SASS_OPTION_STRING_ACCESSOR(const char*, source_map_file, 0);
+  IMPLEMENT_SASS_OPTION_STRING_ACCESSOR(const char*, source_map_root, 0);
+
+  // Create getter and setters for context
+  IMPLEMENT_SASS_CONTEXT_GETTER(int, error_status);
+  IMPLEMENT_SASS_CONTEXT_GETTER(const char*, error_json);
+  IMPLEMENT_SASS_CONTEXT_GETTER(const char*, error_message);
+  IMPLEMENT_SASS_CONTEXT_GETTER(const char*, error_text);
+  IMPLEMENT_SASS_CONTEXT_GETTER(const char*, error_file);
+  IMPLEMENT_SASS_CONTEXT_GETTER(size_t, error_line);
+  IMPLEMENT_SASS_CONTEXT_GETTER(size_t, error_column);
+  IMPLEMENT_SASS_CONTEXT_GETTER(const char*, error_src);
+  IMPLEMENT_SASS_CONTEXT_GETTER(const char*, output_string);
+  IMPLEMENT_SASS_CONTEXT_GETTER(const char*, source_map_string);
+  IMPLEMENT_SASS_CONTEXT_GETTER(char**, included_files);
+
+  // Take ownership of memory (value on context is set to 0)
+  IMPLEMENT_SASS_CONTEXT_TAKER(char*, error_json);
+  IMPLEMENT_SASS_CONTEXT_TAKER(char*, error_message);
+  IMPLEMENT_SASS_CONTEXT_TAKER(char*, error_text);
+  IMPLEMENT_SASS_CONTEXT_TAKER(char*, error_file);
+  IMPLEMENT_SASS_CONTEXT_TAKER(char*, output_string);
+  IMPLEMENT_SASS_CONTEXT_TAKER(char*, source_map_string);
+  IMPLEMENT_SASS_CONTEXT_TAKER(char**, included_files);
+
+  // Push function for include paths (no manipulation support for now)
+  void ADDCALL sass_option_push_include_path(struct Sass_Options* options, const char* path)
+  {
+
+    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;
+    struct string_list* last = options->include_paths;
+    if (!options->include_paths) {
+      options->include_paths = include_path;
+    } else {
+      while (last->next)
+        last = last->next;
+      last->next = include_path;
+    }
+
+  }
+
+  // Push function for plugin paths (no manipulation support for now)
+  void ADDCALL sass_option_push_plugin_path(struct Sass_Options* options, const char* path)
+  {
+
+    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;
+    struct string_list* last = options->plugin_paths;
+    if (!options->plugin_paths) {
+      options->plugin_paths = plugin_path;
+    } else {
+      while (last->next)
+        last = last->next;
+      last->next = plugin_path;
+    }
+
+  }
+
+}
diff --git a/libsass/src/sass_context.hpp b/libsass/src/sass_context.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/sass_context.hpp
@@ -0,0 +1,156 @@
+#ifndef SASS_SASS_CONTEXT_H
+#define SASS_SASS_CONTEXT_H
+
+#include "sass.h"
+#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;
+
+  // embed sourceMappingUrl as data uri
+  bool source_map_embed;
+
+  // embed include contents in maps
+  bool source_map_contents;
+
+  // Disable sourceMappingUrl in css output
+  bool omit_source_map_url;
+
+  // Treat source_string as sass (as opposed to scss)
+  bool is_indented_syntax_src;
+
+  // The input path is used for source map
+  // generation. It can be used to define
+  // something with string compilation or to
+  // overload the input file path. It is
+  // set to "stdin" for data contexts and
+  // to the input file on file contexts.
+  char* input_path;
+
+  // The output path is used for source map
+  // generation. Libsass will not write to
+  // this file, it is just used to create
+  // 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?
+  char* include_path;
+  char* plugin_path;
+
+  // Include paths (linked string list)
+  struct string_list* include_paths;
+  // Plugin paths (linked string list)
+  struct string_list* plugin_paths;
+
+  // Path to source map file
+  // Enables source map generation
+  // Used to create sourceMappingUrl
+  char* source_map_file;
+
+  // Directly inserted in source maps
+  char* source_map_root;
+
+  // Custom functions that can be called from sccs code
+  Sass_Function_List c_functions;
+
+  // List of custom importers
+  Sass_Importer_List c_importers;
+
+  // List of custom headers
+  Sass_Importer_List c_headers;
+
+};
+
+
+// base for all contexts
+struct Sass_Context : Sass_Options
+{
+
+  // store context type info
+  enum Sass_Input_Style type;
+
+  // generated output data
+  char* output_string;
+
+  // generated source map json
+  char* source_map_string;
+
+  // error status
+  int error_status;
+  char* error_json;
+  char* error_text;
+  char* error_message;
+  // error position
+  char* error_file;
+  size_t error_line;
+  size_t error_column;
+  const char* error_src;
+
+  // report imported files
+  char** included_files;
+
+};
+
+// struct for file compilation
+struct Sass_File_Context : Sass_Context {
+
+  // no additional fields required
+  // input_path is already on options
+
+};
+
+// struct for data compilation
+struct Sass_Data_Context : Sass_Context {
+
+  // provided source string
+  char* source_string;
+  char* srcmap_string;
+
+};
+
+// link c and cpp context
+struct Sass_Compiler {
+  // progress status
+  Sass_Compiler_State state;
+  // original c context
+  Sass_Context* c_ctx;
+  // Sass::Context
+  Sass::Context* cpp_ctx;
+  // Sass::Block
+  Sass::Block* root;
+};
+
+#endif
diff --git a/libsass/src/sass_functions.cpp b/libsass/src/sass_functions.cpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/sass_functions.cpp
@@ -0,0 +1,144 @@
+#include <cstring>
+#include "util.hpp"
+#include "context.hpp"
+#include "sass/functions.h"
+#include "sass_functions.hpp"
+
+extern "C" {
+  using namespace Sass;
+
+  Sass_Function_List ADDCALL sass_make_function_list(size_t length)
+  {
+    return (Sass_Function_List) calloc(length + 1, sizeof(Sass_Function_Entry));
+  }
+
+  Sass_Function_Entry ADDCALL sass_make_function(const char* signature, Sass_Function_Fn function, void* cookie)
+  {
+    Sass_Function_Entry cb = (Sass_Function_Entry) calloc(1, sizeof(Sass_Function));
+    if (cb == 0) return 0;
+    cb->signature = signature;
+    cb->function = function;
+    cb->cookie = cookie;
+    return cb;
+  }
+
+  // Setters and getters for callbacks on function lists
+  Sass_Function_Entry ADDCALL sass_function_get_list_entry(Sass_Function_List list, size_t pos) { return list[pos]; }
+  void sass_function_set_list_entry(Sass_Function_List list, size_t pos, Sass_Function_Entry cb) { list[pos] = cb; }
+
+  const char* ADDCALL sass_function_get_signature(Sass_Function_Entry cb) { return cb->signature; }
+  Sass_Function_Fn ADDCALL sass_function_get_function(Sass_Function_Entry cb) { return cb->function; }
+  void* ADDCALL sass_function_get_cookie(Sass_Function_Entry cb) { return cb->cookie; }
+
+  Sass_Importer_Entry ADDCALL sass_make_importer(Sass_Importer_Fn importer, double priority, void* cookie)
+  {
+    Sass_Importer_Entry cb = (Sass_Importer_Entry) calloc(1, sizeof(Sass_Importer));
+    if (cb == 0) return 0;
+    cb->importer = importer;
+    cb->priority = priority;
+    cb->cookie = cookie;
+    return cb;
+  }
+
+  Sass_Importer_Fn ADDCALL sass_importer_get_function(Sass_Importer_Entry cb) { return cb->importer; }
+  double ADDCALL sass_importer_get_priority (Sass_Importer_Entry cb) { return cb->priority; }
+  void* ADDCALL sass_importer_get_cookie(Sass_Importer_Entry cb) { return cb->cookie; }
+
+  // Just in case we have some stray import structs
+  void ADDCALL sass_delete_importer (Sass_Importer_Entry cb)
+  {
+    free(cb);
+  }
+
+  // Creator for sass custom importer function list
+  Sass_Importer_List ADDCALL sass_make_importer_list(size_t length)
+  {
+    return (Sass_Importer_List) calloc(length + 1, sizeof(Sass_Importer_Entry));
+  }
+
+  Sass_Importer_Entry ADDCALL sass_importer_get_list_entry(Sass_Importer_List list, size_t idx) { return list[idx]; }
+  void ADDCALL sass_importer_set_list_entry(Sass_Importer_List list, size_t idx, Sass_Importer_Entry cb) { list[idx] = cb; }
+
+  // Creator for sass custom importer return argument list
+  Sass_Import_List ADDCALL sass_make_import_list(size_t length)
+  {
+    return (Sass_Import**) calloc(length + 1, sizeof(Sass_Import*));
+  }
+
+  // Creator for a single import entry returned by the custom importer inside the list
+  // We take ownership of the memory for source and srcmap (freed when context is destroyd)
+  Sass_Import_Entry ADDCALL sass_make_import(const char* imp_path, const char* abs_path, char* source, char* srcmap)
+  {
+    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->source = source;
+    v->srcmap = srcmap;
+    v->error = 0;
+    v->line = -1;
+    v->column = -1;
+    return v;
+  }
+
+  // Older style, but somehow still valid - keep around or deprecate?
+  Sass_Import_Entry ADDCALL sass_make_import_entry(const char* path, char* source, char* srcmap)
+  {
+    return sass_make_import(path, path, source, srcmap);
+  }
+
+  // Upgrade a normal import entry to throw an error (original path can be re-used by error reporting)
+  Sass_Import_Entry ADDCALL sass_import_set_error(Sass_Import_Entry import, const char* error, size_t line, size_t col)
+  {
+    if (import == 0) return 0;
+    if (import->error) free(import->error);
+    import->error = error ? sass_strdup(error) : 0;
+    import->line = line ? line : -1;
+    import->column = col ? col : -1;
+    return import;
+  }
+
+  // Setters and getters for entries on the import list
+  void ADDCALL sass_import_set_list_entry(Sass_Import_List list, size_t idx, Sass_Import_Entry entry) { list[idx] = entry; }
+  Sass_Import_Entry ADDCALL sass_import_get_list_entry(Sass_Import_List list, size_t idx) { return list[idx]; }
+
+  // Deallocator for the allocated memory
+  void ADDCALL sass_delete_import_list(Sass_Import_List list)
+  {
+    Sass_Import_List it = list;
+    if (list == 0) return;
+    while(*list) {
+      sass_delete_import(*list);
+      ++list;
+    }
+    free(it);
+  }
+
+  // Just in case we have some stray import structs
+  void ADDCALL sass_delete_import(Sass_Import_Entry import)
+  {
+    free(import->imp_path);
+    free(import->abs_path);
+    free(import->source);
+    free(import->srcmap);
+    free(import->error);
+    free(import);
+  }
+
+  // Getter for import entry
+  const char* ADDCALL sass_import_get_imp_path(Sass_Import_Entry entry) { return entry->imp_path; }
+  const char* ADDCALL sass_import_get_abs_path(Sass_Import_Entry entry) { return entry->abs_path; }
+  const char* ADDCALL sass_import_get_source(Sass_Import_Entry entry) { return entry->source; }
+  const char* ADDCALL sass_import_get_srcmap(Sass_Import_Entry entry) { return entry->srcmap; }
+
+  // Getter for import error entry
+  size_t ADDCALL sass_import_get_error_line(Sass_Import_Entry entry) { return entry->line; }
+  size_t ADDCALL sass_import_get_error_column(Sass_Import_Entry entry) { return entry->column; }
+  const char* ADDCALL sass_import_get_error_message(Sass_Import_Entry entry) { return entry->error; }
+
+  // Explicit functions to take ownership of the memory
+  // Resets our own property since we do not know if it is still alive
+  char* ADDCALL sass_import_take_source(Sass_Import_Entry entry) { char* ptr = entry->source; entry->source = 0; return ptr; }
+  char* ADDCALL sass_import_take_srcmap(Sass_Import_Entry entry) { char* ptr = entry->srcmap; entry->srcmap = 0; return ptr; }
+
+}
diff --git a/libsass/src/sass_functions.hpp b/libsass/src/sass_functions.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/sass_functions.hpp
@@ -0,0 +1,32 @@
+#ifndef SASS_SASS_FUNCTIONS_H
+#define SASS_SASS_FUNCTIONS_H
+
+#include "sass.h"
+
+// Struct to hold custom function callback
+struct Sass_Function {
+  const char*      signature;
+  Sass_Function_Fn function;
+  void*            cookie;
+};
+
+// External import entry
+struct Sass_Import {
+  char* imp_path; // path as found in the import statement
+  char *abs_path; // path after importer has resolved it
+  char* source;
+  char* srcmap;
+  // error handling
+  char* error;
+  size_t line;
+  size_t column;
+};
+
+// Struct to hold importer callback
+struct Sass_Importer {
+  Sass_Importer_Fn importer;
+  double           priority;
+  void*            cookie;
+};
+
+#endif
diff --git a/libsass/src/sass_interface.cpp b/libsass/src/sass_interface.cpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/sass_interface.cpp
@@ -0,0 +1,216 @@
+#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
new file mode 100644
--- /dev/null
+++ b/libsass/src/sass_util.cpp
@@ -0,0 +1,150 @@
+#include "node.hpp"
+#include "to_string.hpp"
+
+namespace Sass {
+
+
+  /*
+    # This is the equivalent of ruby's Sass::Util.paths.
+    #
+    # Return an array of all possible paths through the given arrays.
+    #
+    # @param arrs [NodeCollection<NodeCollection<Node>>]
+    # @return [NodeCollection<NodeCollection<Node>>]
+    #
+    # @example
+    #   paths([[1, 2], [3, 4], [5]]) #=>
+    #     # [[1, 3, 5],
+    #     #  [2, 3, 5],
+    #     #  [1, 4, 5],
+    #     #  [2, 4, 5]]
+
+   The following is the modified version of the ruby code that was more portable to C++. You
+   should be able to drop it into ruby 3.2.19 and get the same results from ruby sass.
+
+    def paths(arrs)
+        // I changed the inject and maps to an iterative approach to make it easier to implement in C++
+      loopStart = [[]]
+
+      for arr in arrs do
+        permutations = []
+        for e in arr do
+          for path in loopStart do
+            permutations.push(path + [e])
+          end
+        end
+        loopStart = permutations
+      end
+    end
+  */
+  Node paths(const Node& arrs, Context& ctx) {
+    To_String to_string(&ctx);
+
+    Node loopStart = Node::createCollection();
+    loopStart.collection()->push_back(Node::createCollection());
+
+    for (NodeDeque::iterator arrsIter = arrs.collection()->begin(), arrsEndIter = arrs.collection()->end();
+    	arrsIter != arrsEndIter; ++arrsIter) {
+
+      Node& arr = *arrsIter;
+
+      Node permutations = Node::createCollection();
+
+      for (NodeDeque::iterator arrIter = arr.collection()->begin(), arrIterEnd = arr.collection()->end();
+      	arrIter != arrIterEnd; ++arrIter) {
+
+        Node& e = *arrIter;
+
+        for (NodeDeque::iterator loopStartIter = loopStart.collection()->begin(), loopStartIterEnd = loopStart.collection()->end();
+          loopStartIter != loopStartIterEnd; ++loopStartIter) {
+
+          Node& path = *loopStartIter;
+
+          Node newPermutation = Node::createCollection();
+          newPermutation.got_line_feed = arr.got_line_feed;
+          newPermutation.plus(path);
+          newPermutation.collection()->push_back(e);
+
+          permutations.collection()->push_back(newPermutation);
+        }
+      }
+
+      loopStart = permutations;
+    }
+
+    return loopStart;
+  }
+
+
+  /*
+  This is the equivalent of ruby sass' Sass::Util.flatten and [].flatten.
+  Sass::Util.flatten requires the number of levels to flatten, while
+  [].flatten doesn't and will flatten the entire array. This function
+  supports both.
+
+  # Flattens the first `n` nested arrays. If n == -1, all arrays will be flattened
+  #
+  # @param arr [NodeCollection] The array to flatten
+  # @param n [int] The number of levels to flatten
+  # @return [NodeCollection] The flattened array
+
+  The following is the modified version of the ruby code that was more portable to C++. You
+  should be able to drop it into ruby 3.2.19 and get the same results from ruby sass.
+
+  def flatten(arr, n = -1)
+    if n != -1 and n == 0 then
+      return arr
+    end
+
+    flattened = []
+
+    for e in arr do
+      if e.is_a?(Array) then
+        flattened.concat(flatten(e, n - 1))
+      else
+        flattened << e
+      end
+    end
+
+    return flattened
+  end
+  */
+  Node flatten(Node& arr, Context& ctx, int n) {
+    if (n != -1 && n == 0) {
+      return arr;
+    }
+
+    Node flattened = Node::createCollection();
+    if (arr.got_line_feed) flattened.got_line_feed = true;
+
+    for (NodeDeque::iterator iter = arr.collection()->begin(), iterEnd = arr.collection()->end();
+    	iter != iterEnd; iter++) {
+    	Node& e = *iter;
+
+      // e has the lf set
+      if (e.isCollection()) {
+
+      	// e.collection().got_line_feed = e.got_line_feed;
+      	Node recurseFlattened = flatten(e, ctx, n - 1);
+
+      	if(e.got_line_feed) {
+      		 flattened.got_line_feed = e.got_line_feed;
+      	  recurseFlattened.got_line_feed = e.got_line_feed;
+      	}
+
+      	for(auto i : (*recurseFlattened.collection())) {
+          if (recurseFlattened.got_line_feed) {
+
+            i.got_line_feed = true;
+          }
+          flattened.collection()->push_back(i);
+      	}
+
+      } else {
+      	flattened.collection()->push_back(e);
+      }
+    }
+
+    return flattened;
+  }
+}
diff --git a/libsass/src/sass_util.hpp b/libsass/src/sass_util.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/sass_util.hpp
@@ -0,0 +1,256 @@
+#ifndef SASS_SASS_UTIL_H
+#define SASS_SASS_UTIL_H
+
+#include "ast.hpp"
+#include "node.hpp"
+#include "debug.hpp"
+
+namespace Sass {
+
+
+
+
+  /*
+   This is for ports of functions in the Sass:Util module.
+   */
+
+
+  /*
+    # Return a Node collection of all possible paths through the given Node collection of Node collections.
+    #
+    # @param arrs [NodeCollection<NodeCollection<Node>>]
+    # @return [NodeCollection<NodeCollection<Node>>]
+    #
+    # @example
+    #   paths([[1, 2], [3, 4], [5]]) #=>
+    #     # [[1, 3, 5],
+    #     #  [2, 3, 5],
+    #     #  [1, 4, 5],
+    #     #  [2, 4, 5]]
+  */
+  Node paths(const Node& arrs, Context& ctx);
+
+
+  /*
+  This class is a default implementation of a Node comparator that can be passed to the lcs function below.
+  It uses operator== for equality comparision. It then returns one if the Nodes are equal.
+  */
+  class DefaultLcsComparator {
+  public:
+    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) {
+        out = one;
+        return true;
+      }
+
+      return false;
+    }
+  };
+
+
+  typedef std::vector<std::vector<int> > LCSTable;
+
+
+  /*
+  This is the equivalent of ruby's Sass::Util.lcs_backtrace.
+
+  # Computes a single longest common subsequence for arrays x and y.
+  # Algorithm from http://en.wikipedia.org/wiki/Longest_common_subsequence_problem#Reading_out_an_LCS
+  */
+  template<typename ComparatorType>
+  Node lcs_backtrace(const LCSTable& c, const Node& x, const Node& y, int i, int j, const ComparatorType& comparator) {
+    DEBUG_PRINTLN(LCS, "LCSBACK: X=" << x << " Y=" << y << " I=" << i << " J=" << j)
+
+    if (i == 0 || j == 0) {
+      DEBUG_PRINTLN(LCS, "RETURNING EMPTY")
+      return Node::createCollection();
+    }
+
+    NodeDeque& xChildren = *(x.collection());
+    NodeDeque& yChildren = *(y.collection());
+
+    Node compareOut = Node::createNil();
+    if (comparator(xChildren[i], yChildren[j], compareOut)) {
+      DEBUG_PRINTLN(LCS, "RETURNING AFTER ELEM COMPARE")
+      Node result = lcs_backtrace(c, x, y, i - 1, j - 1, comparator);
+      result.collection()->push_back(compareOut);
+      return result;
+    }
+
+    if (c[i][j - 1] > c[i - 1][j]) {
+      DEBUG_PRINTLN(LCS, "RETURNING AFTER TABLE COMPARE")
+      return lcs_backtrace(c, x, y, i, j - 1, comparator);
+    }
+
+    DEBUG_PRINTLN(LCS, "FINAL RETURN")
+    return lcs_backtrace(c, x, y, i - 1, j, comparator);
+  }
+
+
+  /*
+  This is the equivalent of ruby's Sass::Util.lcs_table.
+
+  # Calculates the memoization table for the Least Common Subsequence algorithm.
+  # Algorithm from http://en.wikipedia.org/wiki/Longest_common_subsequence_problem#Computing_the_length_of_the_LCS
+  */
+  template<typename ComparatorType>
+  void lcs_table(const Node& x, const Node& y, const ComparatorType& comparator, LCSTable& out) {
+    DEBUG_PRINTLN(LCS, "LCSTABLE: X=" << x << " Y=" << y)
+
+    NodeDeque& xChildren = *(x.collection());
+    NodeDeque& yChildren = *(y.collection());
+
+    LCSTable c(xChildren.size(), std::vector<int>(yChildren.size()));
+
+    // These shouldn't be necessary since the vector will be initialized to 0 already.
+    // x.size.times {|i| c[i][0] = 0}
+    // y.size.times {|j| c[0][j] = 0}
+
+    for (size_t i = 1; i < xChildren.size(); i++) {
+      for (size_t j = 1; j < yChildren.size(); j++) {
+        Node compareOut = Node::createNil();
+
+        if (comparator(xChildren[i], yChildren[j], compareOut)) {
+          c[i][j] = c[i - 1][j - 1] + 1;
+        } else {
+          c[i][j] = std::max(c[i][j - 1], c[i - 1][j]);
+        }
+      }
+    }
+
+    out = c;
+  }
+
+
+  /*
+  This is the equivalent of ruby's Sass::Util.lcs.
+
+  # Computes a single longest common subsequence for `x` and `y`.
+  # If there are more than one longest common subsequences,
+  # the one returned is that which starts first in `x`.
+
+  # @param x [NodeCollection]
+  # @param y [NodeCollection]
+  # @comparator An equality check between elements of `x` and `y`.
+  # @return [NodeCollection] The LCS
+
+  http://en.wikipedia.org/wiki/Longest_common_subsequence_problem
+  */
+  template<typename ComparatorType>
+  Node lcs(Node& x, Node& y, const ComparatorType& comparator, Context& ctx) {
+    DEBUG_PRINTLN(LCS, "LCS: X=" << x << " Y=" << y)
+
+    Node newX = Node::createCollection();
+    newX.collection()->push_back(Node::createNil());
+    newX.plus(x);
+
+    Node newY = Node::createCollection();
+    newY.collection()->push_back(Node::createNil());
+    newY.plus(y);
+
+    LCSTable table;
+    lcs_table(newX, newY, comparator, table);
+
+    return lcs_backtrace(table, newX, newY, static_cast<int>(newX.collection()->size()) - 1, static_cast<int>(newY.collection()->size()) - 1, comparator);
+  }
+
+
+  /*
+  This is the equivalent of ruby sass' Sass::Util.flatten and [].flatten.
+  Sass::Util.flatten requires the number of levels to flatten, while
+  [].flatten doesn't and will flatten the entire array. This function
+  supports both.
+
+  # Flattens the first `n` nested arrays. If n == -1, all arrays will be flattened
+  #
+  # @param arr [NodeCollection] The array to flatten
+  # @param n [int] The number of levels to flatten
+  # @return [NodeCollection] The flattened array
+  */
+  Node flatten(Node& arr, Context& ctx, int n = -1);
+
+
+  /*
+  This is the equivalent of ruby's Sass::Util.group_by_to_a.
+
+  # Performs the equivalent of `enum.group_by.to_a`, but with a guaranteed
+  # order. Unlike [#hash_to_a], the resulting order isn't sorted key order;
+  # instead, it's the same order as `#group_by` has under Ruby 1.9 (key
+  # appearance order).
+  #
+  # @param enum [Enumerable]
+  # @return [Array<[Object, Array]>] An array of pairs.
+
+  TODO: update @param and @return once I know what those are.
+
+  The following is the modified version of the ruby code that was more portable to C++. You
+  should be able to drop it into ruby 3.2.19 and get the same results from ruby sass.
+
+    def group_by_to_a(enum, &block)
+      order = {}
+
+      arr = []
+
+      grouped = {}
+
+      for e in enum do
+        key = block[e]
+        unless order.include?(key)
+          order[key] = order.size
+        end
+
+        if not grouped.has_key?(key) then
+          grouped[key] = [e]
+        else
+          grouped[key].push(e)
+        end
+      end
+
+      grouped.each do |key, vals|
+        arr[order[key]] = [key, vals]
+      end
+
+      arr
+    end
+
+  */
+  template<typename EnumType, typename KeyType, typename KeyFunctorType>
+  void group_by_to_a(std::vector<EnumType>& enumeration, KeyFunctorType& keyFunc, std::vector<std::pair<KeyType, std::vector<EnumType> > >& arr /*out*/) {
+
+    std::map<unsigned int, KeyType> order;
+
+    std::map<KeyType, 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()) {
+        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));
+      } else {
+        std::vector<EnumType>& collection = grouped.at(key);
+        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::pair<KeyType, std::vector<EnumType> > grouping = std::make_pair(key, values);
+
+      arr.push_back(grouping);
+    }
+  }
+
+
+}
+
+#endif
diff --git a/libsass/src/sass_values.cpp b/libsass/src/sass_values.cpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/sass_values.cpp
@@ -0,0 +1,351 @@
+#include <cstdlib>
+#include <cstring>
+#include "util.hpp"
+#include "eval.hpp"
+#include "values.hpp"
+#include "sass/values.h"
+#include "sass_values.hpp"
+
+extern "C" {
+  using namespace Sass;
+
+  // Return the sass tag for a generic sass value
+  enum Sass_Tag ADDCALL sass_value_get_tag(const union Sass_Value* v) { return v->unknown.tag; }
+
+  // Check value for specified type
+  bool ADDCALL sass_value_is_null(const union Sass_Value* v) { return v->unknown.tag == SASS_NULL; }
+  bool ADDCALL sass_value_is_number(const union Sass_Value* v) { return v->unknown.tag == SASS_NUMBER; }
+  bool ADDCALL sass_value_is_string(const union Sass_Value* v) { return v->unknown.tag == SASS_STRING; }
+  bool ADDCALL sass_value_is_boolean(const union Sass_Value* v) { return v->unknown.tag == SASS_BOOLEAN; }
+  bool ADDCALL sass_value_is_color(const union Sass_Value* v) { return v->unknown.tag == SASS_COLOR; }
+  bool ADDCALL sass_value_is_list(const union Sass_Value* v) { return v->unknown.tag == SASS_LIST; }
+  bool ADDCALL sass_value_is_map(const union Sass_Value* v) { return v->unknown.tag == SASS_MAP; }
+  bool ADDCALL sass_value_is_error(const union Sass_Value* v) { return v->unknown.tag == SASS_ERROR; }
+  bool ADDCALL sass_value_is_warning(const union Sass_Value* v) { return v->unknown.tag == SASS_WARNING; }
+
+  // Getters and setters for Sass_Number
+  double ADDCALL sass_number_get_value(const union Sass_Value* v) { return v->number.value; }
+  void ADDCALL sass_number_set_value(union Sass_Value* v, double value) { v->number.value = value; }
+  const char* ADDCALL sass_number_get_unit(const union Sass_Value* v) { return v->number.unit; }
+  void ADDCALL sass_number_set_unit(union Sass_Value* v, char* unit) { v->number.unit = unit; }
+
+  // Getters and setters for Sass_String
+  const char* ADDCALL sass_string_get_value(const union Sass_Value* v) { return v->string.value; }
+  void ADDCALL sass_string_set_value(union Sass_Value* v, char* value) { v->string.value = value; }
+  bool ADDCALL sass_string_is_quoted(const union Sass_Value* v) { return v->string.quoted; }
+  void ADDCALL sass_string_set_quoted(union Sass_Value* v, bool quoted) { v->string.quoted = quoted; }
+
+  // Getters and setters for Sass_Boolean
+  bool ADDCALL sass_boolean_get_value(const union Sass_Value* v) { return v->boolean.value; }
+  void ADDCALL sass_boolean_set_value(union Sass_Value* v, bool value) { v->boolean.value = value; }
+
+  // Getters and setters for Sass_Color
+  double ADDCALL sass_color_get_r(const union Sass_Value* v) { return v->color.r; }
+  void ADDCALL sass_color_set_r(union Sass_Value* v, double r) { v->color.r = r; }
+  double ADDCALL sass_color_get_g(const union Sass_Value* v) { return v->color.g; }
+  void ADDCALL sass_color_set_g(union Sass_Value* v, double g) { v->color.g = g; }
+  double ADDCALL sass_color_get_b(const union Sass_Value* v) { return v->color.b; }
+  void ADDCALL sass_color_set_b(union Sass_Value* v, double b) { v->color.b = b; }
+  double ADDCALL sass_color_get_a(const union Sass_Value* v) { return v->color.a; }
+  void ADDCALL sass_color_set_a(union Sass_Value* v, double a) { v->color.a = a; }
+
+  // Getters and setters for Sass_List
+  size_t ADDCALL sass_list_get_length(const union Sass_Value* v) { return v->list.length; }
+  enum Sass_Separator ADDCALL sass_list_get_separator(const union Sass_Value* v) { return v->list.separator; }
+  void ADDCALL sass_list_set_separator(union Sass_Value* v, enum Sass_Separator separator) { v->list.separator = separator; }
+  // Getters and setters for Sass_List values
+  union Sass_Value* ADDCALL sass_list_get_value(const union Sass_Value* v, size_t i) { return v->list.values[i]; }
+  void ADDCALL sass_list_set_value(union Sass_Value* v, size_t i, union Sass_Value* value) { v->list.values[i] = value; }
+
+  // Getters and setters for Sass_Map
+  size_t ADDCALL sass_map_get_length(const union Sass_Value* v) { return v->map.length; }
+  // Getters and setters for Sass_List keys and values
+  union Sass_Value* ADDCALL sass_map_get_key(const union Sass_Value* v, size_t i) { return v->map.pairs[i].key; }
+  union Sass_Value* ADDCALL sass_map_get_value(const union Sass_Value* v, size_t i) { return v->map.pairs[i].value; }
+  void ADDCALL sass_map_set_key(union Sass_Value* v, size_t i, union Sass_Value* key) { v->map.pairs[i].key = key; }
+  void ADDCALL sass_map_set_value(union Sass_Value* v, size_t i, union Sass_Value* val) { v->map.pairs[i].value = val; }
+
+  // Getters and setters for Sass_Error
+  char* ADDCALL sass_error_get_message(const union Sass_Value* v) { return v->error.message; };
+  void ADDCALL sass_error_set_message(union Sass_Value* v, char* msg) { v->error.message = msg; };
+
+  // Getters and setters for Sass_Warning
+  char* ADDCALL sass_warning_get_message(const union Sass_Value* v) { return v->warning.message; };
+  void ADDCALL sass_warning_set_message(union Sass_Value* v, char* msg) { v->warning.message = msg; };
+
+  // Creator functions for all value types
+
+  union Sass_Value* ADDCALL sass_make_boolean(bool val)
+  {
+    union Sass_Value* v = (Sass_Value*) calloc(1, sizeof(Sass_Value));
+    if (v == 0) return 0;
+    v->boolean.tag = SASS_BOOLEAN;
+    v->boolean.value = val;
+    return v;
+  }
+
+  union Sass_Value* ADDCALL sass_make_number(double val, const char* unit)
+  {
+    union Sass_Value* v = (Sass_Value*) calloc(1, sizeof(Sass_Value));
+    if (v == 0) return 0;
+    v->number.tag = SASS_NUMBER;
+    v->number.value = val;
+    v->number.unit = unit ? sass_strdup(unit) : 0;
+    if (v->number.unit == 0) { free(v); return 0; }
+    return v;
+  }
+
+  union Sass_Value* ADDCALL sass_make_color(double r, double g, double b, double a)
+  {
+    union Sass_Value* v = (Sass_Value*) calloc(1, sizeof(Sass_Value));
+    if (v == 0) return 0;
+    v->color.tag = SASS_COLOR;
+    v->color.r = r;
+    v->color.g = g;
+    v->color.b = b;
+    v->color.a = a;
+    return v;
+  }
+
+  union Sass_Value* ADDCALL sass_make_string(const char* val)
+  {
+    union Sass_Value* v = (Sass_Value*) calloc(1, sizeof(Sass_Value));
+    if (v == 0) return 0;
+    v->string.quoted = false;
+    v->string.tag = SASS_STRING;
+    v->string.value = val ? sass_strdup(val) : 0;
+    if (v->string.value == 0) { free(v); return 0; }
+    return v;
+  }
+
+  union Sass_Value* ADDCALL sass_make_qstring(const char* val)
+  {
+    union Sass_Value* v = (Sass_Value*) calloc(1, sizeof(Sass_Value));
+    if (v == 0) return 0;
+    v->string.quoted = true;
+    v->string.tag = SASS_STRING;
+    v->string.value = val ? sass_strdup(val) : 0;
+    if (v->string.value == 0) { free(v); return 0; }
+    return v;
+  }
+
+  union Sass_Value* ADDCALL sass_make_list(size_t len, enum Sass_Separator sep)
+  {
+    union Sass_Value* v = (Sass_Value*) calloc(1, sizeof(Sass_Value));
+    if (v == 0) return 0;
+    v->list.tag = SASS_LIST;
+    v->list.length = len;
+    v->list.separator = sep;
+    v->list.values = (union Sass_Value**) calloc(len, sizeof(union Sass_Value*));
+    if (v->list.values == 0) { free(v); return 0; }
+    return v;
+  }
+
+  union Sass_Value* ADDCALL sass_make_map(size_t len)
+  {
+    union Sass_Value* v = (Sass_Value*) calloc(1, sizeof(Sass_Value));
+    if (v == 0) return 0;
+    v->map.tag = SASS_MAP;
+    v->map.length = len;
+    v->map.pairs = (struct Sass_MapPair*) calloc(len, sizeof(struct Sass_MapPair));
+    if (v->map.pairs == 0) { free(v); return 0; }
+    return v;
+  }
+
+  union Sass_Value* ADDCALL sass_make_null(void)
+  {
+    union Sass_Value* v = (Sass_Value*) calloc(1, sizeof(Sass_Value));
+    if (v == 0) return 0;
+    v->null.tag = SASS_NULL;
+    return v;
+  }
+
+  union Sass_Value* ADDCALL sass_make_error(const char* msg)
+  {
+    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;
+    if (v->error.message == 0) { free(v); return 0; }
+    return v;
+  }
+
+  union Sass_Value* ADDCALL sass_make_warning(const char* msg)
+  {
+    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;
+    if (v->warning.message == 0) { free(v); return 0; }
+    return v;
+  }
+
+  // will free all associated sass values
+  void ADDCALL sass_delete_value(union Sass_Value* val) {
+
+    size_t i;
+    if (val == 0) return;
+    switch(val->unknown.tag) {
+        case SASS_NULL: {
+        }   break;
+        case SASS_BOOLEAN: {
+        }   break;
+        case SASS_NUMBER: {
+                free(val->number.unit);
+        }   break;
+        case SASS_COLOR: {
+        }   break;
+        case SASS_STRING: {
+                free(val->string.value);
+        }   break;
+        case SASS_LIST: {
+                for (i=0; i<val->list.length; i++) {
+                    sass_delete_value(val->list.values[i]);
+                }
+                free(val->list.values);
+        }   break;
+        case SASS_MAP: {
+                for (i=0; i<val->map.length; i++) {
+                    sass_delete_value(val->map.pairs[i].key);
+                    sass_delete_value(val->map.pairs[i].value);
+                }
+                free(val->map.pairs);
+        }   break;
+        case SASS_ERROR: {
+                free(val->error.message);
+        }   break;
+        case SASS_WARNING: {
+                free(val->error.message);
+        }   break;
+    }
+
+    free(val);
+
+    }
+
+  // Make a deep cloned copy of the given sass value
+  union Sass_Value* ADDCALL sass_clone_value (const union Sass_Value* val)
+  {
+
+    size_t i;
+    if (val == 0) return 0;
+    switch(val->unknown.tag) {
+        case SASS_NULL: {
+                return sass_make_null();
+        }   break;
+        case SASS_BOOLEAN: {
+                return sass_make_boolean(val->boolean.value);
+        }   break;
+        case SASS_NUMBER: {
+                return sass_make_number(val->number.value, val->number.unit);
+        }   break;
+        case SASS_COLOR: {
+                return sass_make_color(val->color.r, val->color.g, val->color.b, val->color.a);
+        }   break;
+        case SASS_STRING: {
+                return sass_string_is_quoted(val) ? sass_make_qstring(val->string.value) : sass_make_string(val->string.value);
+        }   break;
+        case SASS_LIST: {
+                union Sass_Value* list = sass_make_list(val->list.length, val->list.separator);
+                for (i = 0; i < list->list.length; i++) {
+                    list->list.values[i] = sass_clone_value(val->list.values[i]);
+                }
+                return list;
+        }   break;
+        case SASS_MAP: {
+                union Sass_Value* map = sass_make_map(val->map.length);
+                for (i = 0; i < val->map.length; i++) {
+                    map->map.pairs[i].key = sass_clone_value(val->map.pairs[i].key);
+                    map->map.pairs[i].value = sass_clone_value(val->map.pairs[i].value);
+                }
+                return map;
+        }   break;
+        case SASS_ERROR: {
+                return sass_make_error(val->error.message);
+        }   break;
+        case SASS_WARNING: {
+                return sass_make_warning(val->warning.message);
+        }   break;
+    }
+
+    return 0;
+
+  }
+
+  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));
+    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;
+
+    try {
+
+      Value* lhs = sass_value_to_ast_node(mem, a);
+      Value* rhs = sass_value_to_ast_node(mem, b);
+
+      // 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));
+        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);
+      }
+      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);
+      }
+      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);
+      }
+      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);
+      }
+      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);
+      }
+
+      // ToDo: maybe we should should return null value?
+      if (!rv) return sass_make_error("invalid return value");
+
+      // convert result back to ast node
+      return ast_node_to_sass_value(rv);
+
+    }
+
+    // simply pass the error message back to the caller for now
+    catch (Exception::InvalidSass& e) { return sass_make_error(e.what()); }
+    catch (std::bad_alloc&) { return sass_make_error("memory exhausted"); }
+    catch (std::exception& e) { return sass_make_error(e.what()); }
+    catch (std::string& e) { return sass_make_error(e.c_str()); }
+    catch (const char* e) { return sass_make_error(e); }
+    catch (...) { return sass_make_error("unknown"); }
+
+    return 0;
+
+  }
+
+}
diff --git a/libsass/src/sass_values.hpp b/libsass/src/sass_values.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/sass_values.hpp
@@ -0,0 +1,81 @@
+#ifndef SASS_SASS_VALUES_H
+#define SASS_SASS_VALUES_H
+
+#include "sass.h"
+
+struct Sass_Unknown {
+  enum Sass_Tag tag;
+};
+
+struct Sass_Boolean {
+  enum Sass_Tag tag;
+  bool          value;
+};
+
+struct Sass_Number {
+  enum Sass_Tag tag;
+  double        value;
+  char*         unit;
+};
+
+struct Sass_Color {
+  enum Sass_Tag tag;
+  double        r;
+  double        g;
+  double        b;
+  double        a;
+};
+
+struct Sass_String {
+  enum Sass_Tag tag;
+  bool          quoted;
+  char*         value;
+};
+
+struct Sass_List {
+  enum Sass_Tag       tag;
+  enum Sass_Separator separator;
+  size_t              length;
+  // null terminated "array"
+  union Sass_Value**  values;
+};
+
+struct Sass_Map {
+  enum Sass_Tag        tag;
+  size_t               length;
+  struct Sass_MapPair* pairs;
+};
+
+struct Sass_Null {
+  enum Sass_Tag tag;
+};
+
+struct Sass_Error {
+  enum Sass_Tag tag;
+  char*         message;
+};
+
+struct Sass_Warning {
+  enum Sass_Tag tag;
+  char*         message;
+};
+
+union Sass_Value {
+  struct Sass_Unknown unknown;
+  struct Sass_Boolean boolean;
+  struct Sass_Number  number;
+  struct Sass_Color   color;
+  struct Sass_String  string;
+  struct Sass_List    list;
+  struct Sass_Map     map;
+  struct Sass_Null    null;
+  struct Sass_Error   error;
+  struct Sass_Warning warning;
+};
+
+struct Sass_MapPair {
+  union Sass_Value* key;
+  union Sass_Value* value;
+};
+
+#endif
diff --git a/libsass/src/source_map.cpp b/libsass/src/source_map.cpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/source_map.cpp
@@ -0,0 +1,184 @@
+#include <string>
+#include <sstream>
+#include <iostream>
+#include <cstddef>
+#include <iomanip>
+
+#include "ast.hpp"
+#include "json.hpp"
+#include "context.hpp"
+#include "position.hpp"
+#include "source_map.hpp"
+
+namespace Sass {
+  SourceMap::SourceMap() : current_position(0, 0, 0), file("stdin") { }
+  SourceMap::SourceMap(const std::string& file) : current_position(0, 0, 0), file(file) { }
+
+  std::string SourceMap::render_srcmap(Context &ctx) {
+
+    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);
+
+    JsonNode* json_srcmap = json_mkobject();
+
+    json_append_member(json_srcmap, "version", json_mknumber(3));
+
+    // 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);
+      json_append_element(json_includes, json_include);
+    }
+    json_append_member(json_srcmap, "sources", json_includes);
+
+    if (include_sources) {
+      JsonNode *json_contents = json_mkarray();
+      for (size_t i = 0; i < source_index.size(); ++i) {
+        const Resource& resource(sources[source_index[i]]);
+        JsonNode *json_content = json_mkstring(resource.contents);
+        json_append_element(json_contents, json_content);
+      }
+      if (json_contents->children.head)
+        json_append_member(json_srcmap, "sourcesContent", json_contents);
+    }
+
+    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);
+
+    char *str = json_stringify(json_srcmap, "\t");
+    std::string result = std::string(str);
+    free(str);
+    json_delete(json_srcmap);
+    return result;
+  }
+
+  std::string SourceMap::serialize_mappings() {
+    std::string result = "";
+
+    size_t previous_generated_line = 0;
+    size_t previous_generated_column = 0;
+    size_t previous_original_line = 0;
+    size_t previous_original_column = 0;
+    size_t previous_original_file = 0;
+    for (size_t i = 0; i < mappings.size(); ++i) {
+      const size_t generated_line = mappings[i].generated_position.line;
+      const size_t generated_column = mappings[i].generated_position.column;
+      const size_t original_line = mappings[i].original_position.line;
+      const size_t original_column = mappings[i].original_position.column;
+      const size_t original_file = mappings[i].original_position.file;
+
+      if (generated_line != previous_generated_line) {
+        previous_generated_column = 0;
+        if (generated_line > previous_generated_line) {
+          result += std::string(generated_line - previous_generated_line, ';');
+          previous_generated_line = generated_line;
+        }
+      }
+      else if (i > 0) {
+        result += ",";
+      }
+
+      // generated column
+      result += base64vlq.encode(static_cast<int>(generated_column) - static_cast<int>(previous_generated_column));
+      previous_generated_column = generated_column;
+      // file
+      result += base64vlq.encode(static_cast<int>(original_file) - static_cast<int>(previous_original_file));
+      previous_original_file = original_file;
+      // source line
+      result += base64vlq.encode(static_cast<int>(original_line) - static_cast<int>(previous_original_line));
+      previous_original_line = original_line;
+      // source column
+      result += base64vlq.encode(static_cast<int>(original_column) - static_cast<int>(previous_original_column));
+      previous_original_column = original_column;
+    }
+
+    return result;
+  }
+
+  void SourceMap::prepend(const OutputBuffer& out)
+  {
+    Offset size(out.smap.current_position);
+    for (Mapping mapping : out.smap.mappings) {
+      if (mapping.generated_position.line > size.line) {
+        throw(std::runtime_error("prepend sourcemap has illegal line"));
+      }
+      if (mapping.generated_position.line == size.line) {
+        if (mapping.generated_position.column > size.column) {
+          throw(std::runtime_error("prepend sourcemap has illegal column"));
+        }
+      }
+    }
+    // will adjust the offset
+    prepend(Offset(out.buffer));
+    // now add the new mappings
+    VECTOR_UNSHIFT(mappings, out.smap.mappings);
+  }
+
+  void SourceMap::append(const OutputBuffer& out)
+  {
+    append(Offset(out.buffer));
+  }
+
+  void SourceMap::prepend(const Offset& offset)
+  {
+    if (offset.line != 0 || offset.column != 0) {
+      for (Mapping& mapping : mappings) {
+        // move stuff on the first old line
+        if (mapping.generated_position.line == 0) {
+          mapping.generated_position.column += offset.column;
+        }
+        // make place for the new lines
+        mapping.generated_position.line += offset.line;
+      }
+    }
+    if (current_position.line == 0) {
+      current_position.column += offset.column;
+    }
+    current_position.line += offset.line;
+  }
+
+  void SourceMap::append(const Offset& offset)
+  {
+    current_position += offset;
+  }
+
+  void SourceMap::add_open_mapping(AST_Node* node)
+  {
+    mappings.push_back(Mapping(node->pstate(), current_position));
+  }
+
+  void SourceMap::add_close_mapping(AST_Node* node)
+  {
+    mappings.push_back(Mapping(node->pstate() + node->pstate().offset, current_position));
+  }
+
+  ParserState SourceMap::remap(const ParserState& pstate) {
+    for (size_t i = 0; i < mappings.size(); ++i) {
+      if (
+        mappings[i].generated_position.file == pstate.file &&
+        mappings[i].generated_position.line == pstate.line &&
+        mappings[i].generated_position.column == pstate.column
+      ) return ParserState(pstate.path, pstate.src, mappings[i].original_position, pstate.offset);
+    }
+    return ParserState(pstate.path, pstate.src, Position(-1, -1, -1), Offset(0, 0));
+
+  }
+
+}
diff --git a/libsass/src/source_map.hpp b/libsass/src/source_map.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/source_map.hpp
@@ -0,0 +1,62 @@
+#ifndef SASS_SOURCE_MAP_H
+#define SASS_SOURCE_MAP_H
+
+#include <string>
+#include <vector>
+
+#include "ast_fwd_decl.hpp"
+#include "base64vlq.hpp"
+#include "position.hpp"
+#include "mapping.hpp"
+
+#define VECTOR_PUSH(vec, ins) vec.insert(vec.end(), ins.begin(), ins.end())
+#define VECTOR_UNSHIFT(vec, ins) vec.insert(vec.begin(), ins.begin(), ins.end())
+
+namespace Sass {
+
+  class Context;
+  class OutputBuffer;
+
+  class SourceMap {
+
+  public:
+    std::vector<size_t> source_index;
+    SourceMap();
+    SourceMap(const std::string& file);
+
+    void append(const Offset& offset);
+    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);
+
+    std::string render_srcmap(Context &ctx);
+    ParserState remap(const ParserState& pstate);
+
+  private:
+
+    std::string serialize_mappings();
+
+    std::vector<Mapping> mappings;
+    Position current_position;
+public:
+    std::string file;
+private:
+    Base64VLQ base64vlq;
+  };
+
+  class OutputBuffer {
+    public:
+      OutputBuffer(void)
+      : buffer(""),
+        smap()
+      { }
+    public:
+      std::string buffer;
+      SourceMap smap;
+  };
+
+}
+
+#endif
diff --git a/libsass/src/subset_map.hpp b/libsass/src/subset_map.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/subset_map.hpp
@@ -0,0 +1,145 @@
+#ifndef SASS_SUBSET_MAP_H
+#define SASS_SUBSET_MAP_H
+
+#include <map>
+#include <set>
+#include <vector>
+#include <algorithm>
+#include <iterator>
+
+
+// #include <iostream>
+// #include <sstream>
+// template<typename T>
+// std::string vector_to_string(std::vector<T> v)
+// {
+//   std::stringstream buffer;
+//   buffer << "[";
+
+//   if (!v.empty())
+//   {  buffer << v[0]; }
+//   else
+//   { buffer << "]"; }
+
+//   if (v.size() == 1)
+//   { buffer << "]"; }
+//   else
+//   {
+//     for (size_t i = 1, S = v.size(); i < S; ++i) buffer << ", " << v[i];
+//     buffer << "]";
+//   }
+
+//   return buffer.str();
+// }
+
+// template<typename T>
+// std::string set_to_string(set<T> v)
+// {
+//   std::stringstream buffer;
+//   buffer << "[";
+//   typename std::set<T>::iterator i = v.begin();
+//   if (!v.empty())
+//   {  buffer << *i; }
+//   else
+//   { buffer << "]"; }
+
+//   if (v.size() == 1)
+//   { buffer << "]"; }
+//   else
+//   {
+//     for (++i; i != v.end(); ++i) buffer << ", " << *i;
+//     buffer << "]";
+//   }
+
+//   return buffer.str();
+// }
+
+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_;
+  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);
+    bool empty() { return values_.empty(); }
+    void clear() { values_.clear(); hash_.clear(); }
+    const std::vector<V> 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;
+  }
+
+}
+
+#endif
diff --git a/libsass/src/support/libsass.pc.in b/libsass/src/support/libsass.pc.in
new file mode 100644
--- /dev/null
+++ b/libsass/src/support/libsass.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libsass
+URL: https://github.com/sass/libsass
+Description: A C implementation of a Sass compiler
+Version: @VERSION@
+Libs: -L${libdir} -lsass
+Cflags: -I${includedir}
diff --git a/libsass/src/to_c.cpp b/libsass/src/to_c.cpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/to_c.cpp
@@ -0,0 +1,73 @@
+#include "to_c.hpp"
+#include "ast.hpp"
+
+namespace Sass {
+
+  union Sass_Value* To_C::fallback_impl(AST_Node* n)
+  { return sass_make_error("unknown type for C-API"); }
+
+  union Sass_Value* To_C::operator()(Boolean* b)
+  { return sass_make_boolean(b->value()); }
+
+  union Sass_Value* To_C::operator()(Number* n)
+  { return sass_make_number(n->value(), n->unit().c_str()); }
+
+  union Sass_Value* To_C::operator()(Custom_Warning* w)
+  { return sass_make_warning(w->message().c_str()); }
+
+  union Sass_Value* To_C::operator()(Custom_Error* e)
+  { return sass_make_error(e->message().c_str()); }
+
+  union Sass_Value* To_C::operator()(Color* c)
+  { return sass_make_color(c->r(), c->g(), c->b(), c->a()); }
+
+  union Sass_Value* To_C::operator()(String_Constant* s)
+  {
+    if (s->quote_mark()) {
+      return sass_make_qstring(s->value().c_str());
+    } else {
+      return sass_make_string(s->value().c_str());
+    }
+  }
+
+  union Sass_Value* To_C::operator()(String_Quoted* s)
+  { return sass_make_qstring(s->value().c_str()); }
+
+  union Sass_Value* To_C::operator()(List* l)
+  {
+    union Sass_Value* v = sass_make_list(l->length(), l->separator());
+    for (size_t i = 0, L = l->length(); i < L; ++i) {
+      sass_list_set_value(v, i, (*l)[i]->perform(this));
+    }
+    return v;
+  }
+
+  union Sass_Value* To_C::operator()(Map* m)
+  {
+    union Sass_Value* v = sass_make_map(m->length());
+    int i = 0;
+    for (auto key : m->keys()) {
+      sass_map_set_key(v, i, key->perform(this));
+      sass_map_set_value(v, i, m->at(key)->perform(this));
+      i++;
+    }
+    return v;
+  }
+
+  union Sass_Value* To_C::operator()(Arguments* a)
+  {
+    union Sass_Value* v = sass_make_list(a->length(), SASS_COMMA);
+    for (size_t i = 0, L = a->length(); i < L; ++i) {
+      sass_list_set_value(v, i, (*a)[i]->perform(this));
+    }
+    return v;
+  }
+
+  union Sass_Value* To_C::operator()(Argument* a)
+  { return a->value()->perform(this); }
+
+  // not strictly necessary because of the fallback
+  union Sass_Value* To_C::operator()(Null* n)
+  { return sass_make_null(); }
+
+};
diff --git a/libsass/src/to_c.hpp b/libsass/src/to_c.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/to_c.hpp
@@ -0,0 +1,41 @@
+#ifndef SASS_TO_C_H
+#define SASS_TO_C_H
+
+#include "ast_fwd_decl.hpp"
+#include "operation.hpp"
+#include "sass/values.h"
+
+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);
+
+  public:
+
+    To_C() { }
+    virtual ~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*);
+
+    // dispatch to fallback implementation
+    union Sass_Value* fallback(AST_Node* x)
+    { return fallback_impl(x); }
+  };
+
+}
+
+#endif
diff --git a/libsass/src/to_string.cpp b/libsass/src/to_string.cpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/to_string.cpp
@@ -0,0 +1,48 @@
+#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
new file mode 100644
--- /dev/null
+++ b/libsass/src/to_string.hpp
@@ -0,0 +1,38 @@
+#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
new file mode 100644
--- /dev/null
+++ b/libsass/src/to_value.cpp
@@ -0,0 +1,109 @@
+#include "ast.hpp"
+#include "to_value.hpp"
+#include "to_string.hpp"
+
+namespace Sass {
+
+  Value* To_Value::fallback_impl(AST_Node* n)
+  {
+    // throw a runtime error if this happens
+    // we want a well defined set of possible nodes
+    throw std::runtime_error("invalid node for to_value");
+    // mute warning
+    return 0;
+  }
+
+  // Custom_Error is a valid value
+  Value* To_Value::operator()(Custom_Error* e)
+  {
+    return e;
+  }
+
+  // Custom_Warning is a valid value
+  Value* To_Value::operator()(Custom_Warning* w)
+  {
+    return w;
+  }
+
+  // Boolean is a valid value
+  Value* To_Value::operator()(Boolean* b)
+  {
+    return b;
+  }
+
+  // Number is a valid value
+  Value* To_Value::operator()(Number* n)
+  {
+    return n;
+  }
+
+  // Color is a valid value
+  Value* To_Value::operator()(Color* c)
+  {
+    return c;
+  }
+
+  // String_Constant is a valid value
+  Value* To_Value::operator()(String_Constant* s)
+  {
+    return s;
+  }
+
+  // String_Quoted is a valid value
+  Value* To_Value::operator()(String_Quoted* s)
+  {
+    return s;
+  }
+
+  // List is a valid value
+  Value* To_Value::operator()(List* l)
+  {
+    List* ll = SASS_MEMORY_NEW(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);
+    }
+    return ll;
+  }
+
+  // Map is a valid value
+  Value* To_Value::operator()(Map* m)
+  {
+    return m;
+  }
+
+  // Null is a valid value
+  Value* To_Value::operator()(Null* n)
+  {
+    return n;
+  }
+
+  // Argument returns its value
+  Value* To_Value::operator()(Argument* 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)
+  {
+    To_String to_string(&ctx);
+    return SASS_MEMORY_NEW(mem, String_Quoted,
+                           s->pstate(),
+                           s->perform(&to_string));
+  }
+
+  // Binary_Expression is converted to a string
+  Value* To_Value::operator()(Binary_Expression* s)
+  {
+    To_String to_string(&ctx);
+    return SASS_MEMORY_NEW(mem, String_Quoted,
+                           s->pstate(),
+                           s->perform(&to_string));
+  }
+
+};
diff --git a/libsass/src/to_value.hpp b/libsass/src/to_value.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/to_value.hpp
@@ -0,0 +1,50 @@
+#ifndef SASS_TO_VALUE_H
+#define SASS_TO_VALUE_H
+
+#include "operation.hpp"
+#include "sass/values.h"
+#include "ast_fwd_decl.hpp"
+
+namespace Sass {
+
+  class To_Value : public Operation_CRTP<Value*, To_Value> {
+
+    Value* fallback_impl(AST_Node* n);
+
+  private:
+
+    Context& ctx;
+    Memory_Manager& mem;
+
+  public:
+
+    To_Value(Context& ctx, Memory_Manager& mem)
+    : ctx(ctx), mem(mem)
+    { }
+    virtual ~To_Value() { }
+    using Operation<Value*>::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*);
+
+    // convert to string via `To_String`
+    Value* operator()(Selector_List*);
+    Value* operator()(Binary_Expression*);
+
+    // fallback throws error
+    template <typename U>
+    Value* fallback(U x) { return fallback_impl(x); }
+  };
+
+}
+
+#endif
diff --git a/libsass/src/units.cpp b/libsass/src/units.cpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/units.cpp
@@ -0,0 +1,160 @@
+#include <stdexcept>
+#include "units.hpp"
+
+#ifdef IN
+#undef IN
+#endif
+
+namespace Sass {
+
+  /* the conversion matrix can be readed the following way */
+  /* if you go down, the factor is for the numerator (multiply) */
+  /* if you go right, the factor is for the denominator (divide) */
+  /* and yes, we actually use both, not sure why, but why not!? */
+
+  const double size_conversion_factors[6][6] =
+  {
+             /*  in         cm         pc         mm         pt         px        */
+    /* in   */ { 1,         2.54,      6,         25.4,      72,        96,       },
+    /* cm   */ { 1.0/2.54,  1,         6.0/2.54,  10,        72.0/2.54, 96.0/2.54 },
+    /* pc   */ { 1.0/6.0,   2.54/6.0,  1,         25.4/6.0,  72.0/6.0,  96.0/6.0  },
+    /* mm   */ { 1.0/25.4,  1.0/10.0,  6.0/25.4,  1,         72.0/25.4, 96.0/25.4 },
+    /* pt   */ { 1.0/72.0,  2.54/72.0, 6.0/72.0,  25.4/72.0, 1,         96.0/72.0 },
+    /* px   */ { 1.0/96.0,  2.54/96.0, 6.0/96.0,  25.4/96.0, 72.0/96.0, 1,        }
+  };
+
+  const double angle_conversion_factors[4][4] =
+  {
+             /*  deg        grad       rad        turn      */
+    /* deg  */ { 1,         40.0/36.0, PI/180.0,  1.0/360.0 },
+    /* grad */ { 36.0/40.0, 1,         PI/200.0,  1.0/400.0 },
+    /* rad  */ { 180.0/PI,  200.0/PI,  1,         0.5/PI    },
+    /* turn */ { 360.0,     400.0,     2.0*PI,    1         }
+  };
+
+  const double time_conversion_factors[2][2] =
+  {
+             /*  s          ms        */
+    /* s    */ { 1,         1000.0    },
+    /* ms   */ { 1/1000.0,  1         }
+  };
+  const double frequency_conversion_factors[2][2] =
+  {
+             /*  Hz         kHz       */
+    /* Hz   */ { 1,         1/1000.0  },
+    /* kHz  */ { 1000.0,    1         }
+  };
+  const double resolution_conversion_factors[3][3] =
+  {
+             /*  dpi        dpcm       dppx     */
+    /* dpi  */ { 1,         2.54,      96       },
+    /* dpcm */ { 1/2.54,    1,         96/2.54  },
+    /* dppx */ { 1/96.0,    2.54/96,   1        }
+  };
+
+  SassUnitType get_unit_type(SassUnit unit)
+  {
+    switch (unit & 0xFF00)
+    {
+      case 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;
+    }
+  };
+
+  SassUnit 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;
+    // 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;
+    // time units
+    else if (s == "s")    return SassUnit::SEC;
+    else if (s == "ms")   return SassUnit::MSEC;
+    // frequency units
+    else if (s == "Hz")   return SassUnit::HERTZ;
+    else if (s == "kHz")  return SassUnit::KHERTZ;
+    // resolutions units
+    else if (s == "dpi")  return SassUnit::DPI;
+    else if (s == "dpcm") return SassUnit::DPCM;
+    else if (s == "dppx") return SassUnit::DPPX;
+    // for unknown units
+    else return SassUnit::UNKNOWN;
+  }
+
+  const char* unit_to_string(SassUnit 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;
+      // 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;
+      // time units
+      case SassUnit::SEC:     return "s"; break;
+      case SassUnit::MSEC:    return "ms"; break;
+      // frequency units
+      case SassUnit::HERTZ:   return "Hz"; break;
+      case SassUnit::KHERTZ:  return "kHz"; break;
+      // resolutions units
+      case SassUnit::DPI:     return "dpi"; break;
+      case SassUnit::DPCM:    return "dpcm"; break;
+      case SassUnit::DPPX:    return "dppx"; break;
+      // for unknown units
+      default:                return ""; break;
+    }
+  }
+
+  // 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);
+    // query unit group types
+    SassUnitType t1 = get_unit_type(u1);
+    SassUnitType t2 = get_unit_type(u2);
+    // get absolute offset
+    // used for array acces
+    size_t i1 = u1 - t1;
+    size_t i2 = u2 - t2;
+    // error if units are not of the same group
+    // don't error for multiplication and division
+    if (strict && t1 != t2) throw incompatibleUnits(u1, u2);
+    // only process known units
+    if (u1 != UNKNOWN && u2 != UNKNOWN) {
+      switch (t1) {
+        case 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;
+        // ToDo: should we throw error here?
+        case SassUnitType::INCOMMENSURABLE:   return 0; break;
+      }
+    }
+    // fallback
+    return 1;
+  }
+
+}
diff --git a/libsass/src/units.hpp b/libsass/src/units.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/units.hpp
@@ -0,0 +1,88 @@
+#ifndef SASS_UNITS_H
+#define SASS_UNITS_H
+
+#include <cmath>
+#include <string>
+#include <sstream>
+
+namespace Sass {
+
+  const double PI = acos(-1);
+
+  enum SassUnitType {
+    LENGTH = 0x000,
+    ANGLE = 0x100,
+    TIME = 0x200,
+    FREQUENCY = 0x300,
+    RESOLUTION = 0x400,
+    INCOMMENSURABLE = 0x500
+  };
+
+  enum SassUnit {
+
+    // size units
+    IN = SassUnitType::LENGTH,
+    CM,
+    PC,
+    MM,
+    PT,
+    PX,
+
+    // angle units
+    DEG = ANGLE,
+    GRAD,
+    RAD,
+    TURN,
+
+    // time units
+    SEC = TIME,
+    MSEC,
+
+    // frequency units
+    HERTZ = FREQUENCY,
+    KHERTZ,
+
+    // resolutions units
+    DPI = RESOLUTION,
+    DPCM,
+    DPPX,
+
+    // for unknown units
+    UNKNOWN = INCOMMENSURABLE
+
+  };
+
+  extern const double size_conversion_factors[6][6];
+  extern const double angle_conversion_factors[4][4];
+  extern const double time_conversion_factors[2][2];
+  extern const double frequency_conversion_factors[2][2];
+  extern const double resolution_conversion_factors[3][3];
+
+  enum SassUnit string_to_unit(const std::string&);
+  const char* unit_to_string(SassUnit unit);
+  enum SassUnitType get_unit_type(SassUnit unit);
+  // throws incompatibleUnits exceptions
+  double conversion_factor(const std::string&, const std::string&, bool = true);
+
+  class incompatibleUnits: public std::exception
+  {
+    public:
+      const char* msg;
+      incompatibleUnits(SassUnit a, SassUnit b)
+      : exception()
+      {
+        std::stringstream ss;
+        ss << "Incompatible units: ";
+        ss << "'" << unit_to_string(a) << "' and ";
+        ss << "'" << unit_to_string(b) << "'";
+        msg = ss.str().c_str();
+      }
+      virtual const char* what() const throw()
+      {
+        return msg;
+      }
+  };
+
+}
+
+#endif
diff --git a/libsass/src/utf8.h b/libsass/src/utf8.h
new file mode 100644
--- /dev/null
+++ b/libsass/src/utf8.h
@@ -0,0 +1,34 @@
+// Copyright 2006 Nemanja Trifunovic
+
+/*
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+*/
+
+
+#ifndef UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731
+#define UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731
+
+#include "utf8/checked.h"
+#include "utf8/unchecked.h"
+
+#endif // header guard
diff --git a/libsass/src/utf8/checked.h b/libsass/src/utf8/checked.h
new file mode 100644
--- /dev/null
+++ b/libsass/src/utf8/checked.h
@@ -0,0 +1,327 @@
+// Copyright 2006 Nemanja Trifunovic
+
+/*
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+*/
+
+
+#ifndef UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
+#define UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
+
+#include "core.h"
+#include <stdexcept>
+
+namespace utf8
+{
+    // Base for the exceptions that may be thrown from the library
+    class exception : public ::std::exception {
+    };
+
+    // Exceptions that may be thrown from the library functions.
+    class invalid_code_point : public exception {
+        uint32_t cp;
+    public:
+        invalid_code_point(uint32_t cp) : cp(cp) {}
+        virtual const char* what() const throw() { return "Invalid code point"; }
+        uint32_t code_point() const {return cp;}
+    };
+
+    class invalid_utf8 : public exception {
+        uint8_t u8;
+    public:
+        invalid_utf8 (uint8_t u) : u8(u) {}
+        virtual const char* what() const throw() { return "Invalid UTF-8"; }
+        uint8_t utf8_octet() const {return u8;}
+    };
+
+    class invalid_utf16 : public exception {
+        uint16_t u16;
+    public:
+        invalid_utf16 (uint16_t u) : u16(u) {}
+        virtual const char* what() const throw() { return "Invalid UTF-16"; }
+        uint16_t utf16_word() const {return u16;}
+    };
+
+    class not_enough_room : public exception {
+    public:
+        virtual const char* what() const throw() { return "Not enough space"; }
+    };
+
+    /// The library API - functions intended to be called by the users
+
+    template <typename octet_iterator>
+    octet_iterator append(uint32_t cp, octet_iterator result)
+    {
+        if (!utf8::internal::is_code_point_valid(cp))
+            throw invalid_code_point(cp);
+
+        if (cp < 0x80)                        // one octet
+            *(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);
+        }
+        else if (cp < 0x10000) {              // three octets
+            *(result++) = static_cast<uint8_t>((cp >> 12)           | 0xe0);
+            *(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f)   | 0x80);
+            *(result++) = static_cast<uint8_t>((cp & 0x3f)          | 0x80);
+        }
+        else {                                // four octets
+            *(result++) = static_cast<uint8_t>((cp >> 18)           | 0xf0);
+            *(result++) = static_cast<uint8_t>(((cp >> 12) & 0x3f)  | 0x80);
+            *(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f)   | 0x80);
+            *(result++) = static_cast<uint8_t>((cp & 0x3f)          | 0x80);
+        }
+        return result;
+    }
+
+    template <typename octet_iterator, typename output_iterator>
+    output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out, uint32_t replacement)
+    {
+        while (start != end) {
+            octet_iterator sequence_start = start;
+            internal::utf_error err_code = utf8::internal::validate_next(start, end);
+            switch (err_code) {
+                case internal::UTF8_OK :
+                    for (octet_iterator it = sequence_start; it != start; ++it)
+                        *out++ = *it;
+                    break;
+                case internal::NOT_ENOUGH_ROOM:
+                    throw not_enough_room();
+                case internal::INVALID_LEAD:
+                    out = utf8::append (replacement, out);
+                    ++start;
+                    break;
+                case internal::INCOMPLETE_SEQUENCE:
+                case internal::OVERLONG_SEQUENCE:
+                case internal::INVALID_CODE_POINT:
+                    out = utf8::append (replacement, out);
+                    ++start;
+                    // just one replacement mark for the sequence
+                    while (start != end && utf8::internal::is_trail(*start))
+                        ++start;
+                    break;
+            }
+        }
+        return out;
+    }
+
+    template <typename octet_iterator, typename output_iterator>
+    inline output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out)
+    {
+        static const uint32_t replacement_marker = utf8::internal::mask16(0xfffd);
+        return utf8::replace_invalid(start, end, out, replacement_marker);
+    }
+
+    template <typename octet_iterator>
+    uint32_t next(octet_iterator& it, octet_iterator end)
+    {
+        uint32_t cp = 0;
+        internal::utf_error err_code = utf8::internal::validate_next(it, end, cp);
+        switch (err_code) {
+            case internal::UTF8_OK :
+                break;
+            case internal::NOT_ENOUGH_ROOM :
+                throw not_enough_room();
+            case internal::INVALID_LEAD :
+            case internal::INCOMPLETE_SEQUENCE :
+            case internal::OVERLONG_SEQUENCE :
+                throw invalid_utf8(*it);
+            case internal::INVALID_CODE_POINT :
+                throw invalid_code_point(cp);
+        }
+        return cp;
+    }
+
+    template <typename octet_iterator>
+    uint32_t peek_next(octet_iterator it, octet_iterator end)
+    {
+        return utf8::next(it, end);
+    }
+
+    template <typename octet_iterator>
+    uint32_t prior(octet_iterator& it, octet_iterator start)
+    {
+        // can't do much if it == start
+        if (it == start)
+            throw not_enough_room();
+
+        octet_iterator end = it;
+        // Go back until we hit either a lead octet or start
+        while (utf8::internal::is_trail(*(--it)))
+            if (it == start)
+                throw invalid_utf8(*it); // error - no lead byte in the sequence
+        return utf8::peek_next(it, end);
+    }
+
+    /// Deprecated in versions that include "prior"
+    template <typename octet_iterator>
+    uint32_t previous(octet_iterator& it, octet_iterator pass_start)
+    {
+        octet_iterator end = it;
+        while (utf8::internal::is_trail(*(--it)))
+            if (it == pass_start)
+                throw invalid_utf8(*it); // error - no lead byte in the sequence
+        octet_iterator temp = it;
+        return utf8::next(temp, end);
+    }
+
+    template <typename octet_iterator, typename distance_type>
+    void advance (octet_iterator& it, distance_type n, octet_iterator end)
+    {
+        for (distance_type i = 0; i < n; ++i)
+            utf8::next(it, end);
+    }
+
+    template <typename octet_iterator>
+    typename std::iterator_traits<octet_iterator>::difference_type
+    distance (octet_iterator first, octet_iterator last)
+    {
+        typename std::iterator_traits<octet_iterator>::difference_type dist;
+        for (dist = 0; first < last; ++dist)
+            utf8::next(first, last);
+        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
+            if (utf8::internal::is_lead_surrogate(cp)) {
+                if (start != end) {
+                    uint32_t trail_surrogate = utf8::internal::mask16(*start++);
+                    if (utf8::internal::is_trail_surrogate(trail_surrogate))
+                        cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET;
+                    else
+                        throw invalid_utf16(static_cast<uint16_t>(trail_surrogate));
+                }
+                else
+                    throw invalid_utf16(static_cast<uint16_t>(cp));
+
+            }
+            // Lone trail surrogate
+            else if (utf8::internal::is_trail_surrogate(cp))
+                throw invalid_utf16(static_cast<uint16_t>(cp));
+
+            result = utf8::append(cp, result);
+        }
+        return result;
+    }
+
+    template <typename u16bit_iterator, typename octet_iterator>
+    u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result)
+    {
+        while (start != end) {
+            uint32_t cp = utf8::next(start, end);
+            if (cp > 0xffff) { //make a surrogate pair
+                *result++ = static_cast<uint16_t>((cp >> 10)   + internal::LEAD_OFFSET);
+                *result++ = static_cast<uint16_t>((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN);
+            }
+            else
+                *result++ = static_cast<uint16_t>(cp);
+        }
+        return result;
+    }
+
+    template <typename octet_iterator, typename u32bit_iterator>
+    octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result)
+    {
+        while (start != end)
+            result = utf8::append(*(start++), result);
+
+        return result;
+    }
+
+    template <typename octet_iterator, typename u32bit_iterator>
+    u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result)
+    {
+        while (start != end)
+            (*result++) = utf8::next(start, end);
+
+        return result;
+    }
+
+    // The iterator class
+    template <typename octet_iterator>
+    class iterator : public std::iterator <std::bidirectional_iterator_tag, uint32_t> {
+      octet_iterator it;
+      octet_iterator range_start;
+      octet_iterator range_end;
+      public:
+      iterator () {}
+      explicit iterator (const octet_iterator& octet_it,
+                         const octet_iterator& range_start,
+                         const octet_iterator& range_end) :
+               it(octet_it), range_start(range_start), range_end(range_end)
+      {
+          if (it < range_start || it > range_end)
+              throw std::out_of_range("Invalid utf-8 iterator position");
+      }
+      // the default "big three" are OK
+      octet_iterator base () const { return it; }
+      uint32_t operator * () const
+      {
+          octet_iterator temp = it;
+          return utf8::next(temp, range_end);
+      }
+      bool operator == (const iterator& rhs) const
+      {
+          if (range_start != rhs.range_start || range_end != rhs.range_end)
+              throw std::logic_error("Comparing utf-8 iterators defined with different ranges");
+          return (it == rhs.it);
+      }
+      bool operator != (const iterator& rhs) const
+      {
+          return !(operator == (rhs));
+      }
+      iterator& operator ++ ()
+      {
+          utf8::next(it, range_end);
+          return *this;
+      }
+      iterator operator ++ (int)
+      {
+          iterator temp = *this;
+          utf8::next(it, range_end);
+          return temp;
+      }
+      iterator& operator -- ()
+      {
+          utf8::prior(it, range_start);
+          return *this;
+      }
+      iterator operator -- (int)
+      {
+          iterator temp = *this;
+          utf8::prior(it, range_start);
+          return temp;
+      }
+    }; // class iterator
+
+} // namespace utf8
+
+#endif //header guard
+
+
diff --git a/libsass/src/utf8/core.h b/libsass/src/utf8/core.h
new file mode 100644
--- /dev/null
+++ b/libsass/src/utf8/core.h
@@ -0,0 +1,329 @@
+// Copyright 2006 Nemanja Trifunovic
+
+/*
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+*/
+
+
+#ifndef UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
+#define UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
+
+#include <iterator>
+
+namespace utf8
+{
+    // The typedefs for 8-bit, 16-bit and 32-bit unsigned integers
+    // You may need to change them to match your system.
+    // These typedefs have the same names as ones from cstdint, or boost/cstdint
+    typedef unsigned char   uint8_t;
+    typedef unsigned short  uint16_t;
+    typedef unsigned int    uint32_t;
+
+// Helper code - not intended to be directly called by the library users. May be changed at any time
+namespace internal
+{
+    // Unicode constants
+    // Leading (high) surrogates: 0xd800 - 0xdbff
+    // Trailing (low) surrogates: 0xdc00 - 0xdfff
+    const uint16_t LEAD_SURROGATE_MIN  = 0xd800u;
+    const uint16_t LEAD_SURROGATE_MAX  = 0xdbffu;
+    const uint16_t TRAIL_SURROGATE_MIN = 0xdc00u;
+    const uint16_t TRAIL_SURROGATE_MAX = 0xdfffu;
+    const uint16_t LEAD_OFFSET         = LEAD_SURROGATE_MIN - (0x10000 >> 10);
+    const uint32_t SURROGATE_OFFSET    = 0x10000u - (LEAD_SURROGATE_MIN << 10) - TRAIL_SURROGATE_MIN;
+
+    // Maximum valid value for a Unicode code point
+    const uint32_t CODE_POINT_MAX      = 0x0010ffffu;
+
+    template<typename octet_type>
+    inline uint8_t mask8(octet_type oc)
+    {
+        return static_cast<uint8_t>(0xff & oc);
+    }
+    template<typename u16_type>
+    inline uint16_t mask16(u16_type oc)
+    {
+        return static_cast<uint16_t>(0xffff & oc);
+    }
+    template<typename octet_type>
+    inline bool is_trail(octet_type oc)
+    {
+        return ((utf8::internal::mask8(oc) >> 6) == 0x2);
+    }
+
+    template <typename u16>
+    inline bool is_lead_surrogate(u16 cp)
+    {
+        return (cp >= LEAD_SURROGATE_MIN && cp <= LEAD_SURROGATE_MAX);
+    }
+
+    template <typename u16>
+    inline bool is_trail_surrogate(u16 cp)
+    {
+        return (cp >= TRAIL_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX);
+    }
+
+    template <typename u16>
+    inline bool is_surrogate(u16 cp)
+    {
+        return (cp >= LEAD_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX);
+    }
+
+    template <typename u32>
+    inline bool is_code_point_valid(u32 cp)
+    {
+        return (cp <= CODE_POINT_MAX && !utf8::internal::is_surrogate(cp));
+    }
+
+    template <typename octet_iterator>
+    inline typename std::iterator_traits<octet_iterator>::difference_type
+    sequence_length(octet_iterator lead_it)
+    {
+        uint8_t lead = utf8::internal::mask8(*lead_it);
+        if (lead < 0x80)
+            return 1;
+        else if ((lead >> 5) == 0x6)
+            return 2;
+        else if ((lead >> 4) == 0xe)
+            return 3;
+        else if ((lead >> 3) == 0x1e)
+            return 4;
+        else
+            return 0;
+    }
+
+    template <typename octet_difference_type>
+    inline bool is_overlong_sequence(uint32_t cp, octet_difference_type length)
+    {
+        if (cp < 0x80) {
+            if (length != 1)
+                return true;
+        }
+        else if (cp < 0x800) {
+            if (length != 2)
+                return true;
+        }
+        else if (cp < 0x10000) {
+            if (length != 3)
+                return true;
+        }
+
+        return false;
+    }
+
+    enum utf_error {UTF8_OK, NOT_ENOUGH_ROOM, INVALID_LEAD, INCOMPLETE_SEQUENCE, OVERLONG_SEQUENCE, INVALID_CODE_POINT};
+
+    /// Helper for get_sequence_x
+    template <typename octet_iterator>
+    utf_error increase_safely(octet_iterator& it, octet_iterator end)
+    {
+        if (++it == end)
+            return NOT_ENOUGH_ROOM;
+
+        if (!utf8::internal::is_trail(*it))
+            return INCOMPLETE_SEQUENCE;
+
+        return UTF8_OK;
+    }
+
+    #define UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(IT, END) {utf_error ret = increase_safely(IT, END); if (ret != UTF8_OK) return ret;}
+
+    /// get_sequence_x functions decode utf-8 sequences of the length x
+    template <typename octet_iterator>
+    utf_error get_sequence_1(octet_iterator& it, octet_iterator end, uint32_t& code_point)
+    {
+        if (it == end)
+            return NOT_ENOUGH_ROOM;
+
+        code_point = utf8::internal::mask8(*it);
+
+        return UTF8_OK;
+    }
+
+    template <typename octet_iterator>
+    utf_error get_sequence_2(octet_iterator& it, octet_iterator end, uint32_t& code_point)
+    {
+        if (it == end)
+            return NOT_ENOUGH_ROOM;
+
+        code_point = utf8::internal::mask8(*it);
+
+        UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
+
+        code_point = ((code_point << 6) & 0x7ff) + ((*it) & 0x3f);
+
+        return UTF8_OK;
+    }
+
+    template <typename octet_iterator>
+    utf_error get_sequence_3(octet_iterator& it, octet_iterator end, uint32_t& code_point)
+    {
+        if (it == end)
+            return NOT_ENOUGH_ROOM;
+
+        code_point = utf8::internal::mask8(*it);
+
+        UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
+
+        code_point = ((code_point << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff);
+
+        UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
+
+        code_point += (*it) & 0x3f;
+
+        return UTF8_OK;
+    }
+
+    template <typename octet_iterator>
+    utf_error get_sequence_4(octet_iterator& it, octet_iterator end, uint32_t& code_point)
+    {
+        if (it == end)
+           return NOT_ENOUGH_ROOM;
+
+        code_point = utf8::internal::mask8(*it);
+
+        UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
+
+        code_point = ((code_point << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff);
+
+        UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
+
+        code_point += (utf8::internal::mask8(*it) << 6) & 0xfff;
+
+        UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
+
+        code_point += (*it) & 0x3f;
+
+        return UTF8_OK;
+    }
+
+    #undef UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR
+
+    template <typename octet_iterator>
+    utf_error validate_next(octet_iterator& it, octet_iterator end, uint32_t& code_point)
+    {
+        // Save the original value of it so we can go back in case of failure
+        // Of course, it does not make much sense with i.e. stream iterators
+        octet_iterator original_it = it;
+
+        uint32_t cp = 0;
+        // Determine the sequence length based on the lead octet
+        typedef typename std::iterator_traits<octet_iterator>::difference_type octet_difference_type;
+        const octet_difference_type length = utf8::internal::sequence_length(it);
+
+        // Get trail octets and calculate the code point
+        utf_error err = UTF8_OK;
+        switch (length) {
+            case 0:
+                return INVALID_LEAD;
+            case 1:
+                err = utf8::internal::get_sequence_1(it, end, cp);
+                break;
+            case 2:
+                err = utf8::internal::get_sequence_2(it, end, cp);
+            break;
+            case 3:
+                err = utf8::internal::get_sequence_3(it, end, cp);
+            break;
+            case 4:
+                err = utf8::internal::get_sequence_4(it, end, cp);
+            break;
+        }
+
+        if (err == UTF8_OK) {
+            // Decoding succeeded. Now, security checks...
+            if (utf8::internal::is_code_point_valid(cp)) {
+                if (!utf8::internal::is_overlong_sequence(cp, length)){
+                    // Passed! Return here.
+                    code_point = cp;
+                    ++it;
+                    return UTF8_OK;
+                }
+                else
+                    err = OVERLONG_SEQUENCE;
+            }
+            else
+                err = INVALID_CODE_POINT;
+        }
+
+        // Failure branch - restore the original value of the iterator
+        it = original_it;
+        return err;
+    }
+
+    template <typename octet_iterator>
+    inline utf_error validate_next(octet_iterator& it, octet_iterator end) {
+        uint32_t ignored;
+        return utf8::internal::validate_next(it, end, ignored);
+    }
+
+} // namespace internal
+
+    /// The library API - functions intended to be called by the users
+
+    // Byte order mark
+    const uint8_t bom[] = {0xef, 0xbb, 0xbf};
+
+    template <typename octet_iterator>
+    octet_iterator find_invalid(octet_iterator start, octet_iterator end)
+    {
+        octet_iterator result = start;
+        while (result != end) {
+            utf8::internal::utf_error err_code = utf8::internal::validate_next(result, end);
+            if (err_code != internal::UTF8_OK)
+                return result;
+        }
+        return result;
+    }
+
+    template <typename octet_iterator>
+    inline bool is_valid(octet_iterator start, octet_iterator end)
+    {
+        return (utf8::find_invalid(start, end) == end);
+    }
+
+    template <typename octet_iterator>
+    inline bool starts_with_bom (octet_iterator it, octet_iterator end)
+    {
+        return (
+            ((it != end) && (utf8::internal::mask8(*it++)) == bom[0]) &&
+            ((it != end) && (utf8::internal::mask8(*it++)) == bom[1]) &&
+            ((it != end) && (utf8::internal::mask8(*it))   == bom[2])
+           );
+    }
+
+    //Deprecated in release 2.3
+    template <typename octet_iterator>
+    inline bool is_bom (octet_iterator it)
+    {
+        return (
+            (utf8::internal::mask8(*it++)) == bom[0] &&
+            (utf8::internal::mask8(*it++)) == bom[1] &&
+            (utf8::internal::mask8(*it))   == bom[2]
+           );
+    }
+} // namespace utf8
+
+#endif // header guard
+
+
diff --git a/libsass/src/utf8/unchecked.h b/libsass/src/utf8/unchecked.h
new file mode 100644
--- /dev/null
+++ b/libsass/src/utf8/unchecked.h
@@ -0,0 +1,228 @@
+// Copyright 2006 Nemanja Trifunovic
+
+/*
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+*/
+
+
+#ifndef UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
+#define UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
+
+#include "core.h"
+
+namespace utf8
+{
+    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);  
+            else if (cp < 0x800) {                // two octets
+                *(result++) = static_cast<uint8_t>((cp >> 6)          | 0xc0);
+                *(result++) = static_cast<uint8_t>((cp & 0x3f)        | 0x80);
+            }
+            else if (cp < 0x10000) {              // three octets
+                *(result++) = static_cast<uint8_t>((cp >> 12)         | 0xe0);
+                *(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
+                *(result++) = static_cast<uint8_t>((cp & 0x3f)        | 0x80);
+            }
+            else {                                // four octets
+                *(result++) = static_cast<uint8_t>((cp >> 18)         | 0xf0);
+                *(result++) = static_cast<uint8_t>(((cp >> 12) & 0x3f)| 0x80);
+                *(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
+                *(result++) = static_cast<uint8_t>((cp & 0x3f)        | 0x80);
+            }
+            return result;
+        }
+
+        template <typename octet_iterator>
+        uint32_t next(octet_iterator& it)
+        {
+            uint32_t cp = utf8::internal::mask8(*it);
+            typename std::iterator_traits<octet_iterator>::difference_type length = utf8::internal::sequence_length(it);
+            switch (length) {
+                case 1:
+                    break;
+                case 2:
+                    it++;
+                    cp = ((cp << 6) & 0x7ff) + ((*it) & 0x3f);
+                    break;
+                case 3:
+                    ++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);                
+                    ++it;
+                    cp += (utf8::internal::mask8(*it) << 6) & 0xfff;
+                    ++it;
+                    cp += (*it) & 0x3f; 
+                    break;
+            }
+            ++it;
+            return cp;        
+        }
+
+        template <typename octet_iterator>
+        uint32_t peek_next(octet_iterator it)
+        {
+            return utf8::unchecked::next(it);    
+        }
+
+        template <typename octet_iterator>
+        uint32_t prior(octet_iterator& it)
+        {
+            while (utf8::internal::is_trail(*(--it))) ;
+            octet_iterator temp = it;
+            return utf8::unchecked::next(temp);
+        }
+
+        // Deprecated in versions that include prior, but only for the sake of consistency (see utf8::previous)
+        template <typename octet_iterator>
+        inline uint32_t previous(octet_iterator& it)
+        {
+            return utf8::unchecked::prior(it);
+        }
+
+        template <typename octet_iterator, typename distance_type>
+        void advance (octet_iterator& it, distance_type n)
+        {
+            for (distance_type i = 0; i < n; ++i)
+                utf8::unchecked::next(it);
+        }
+
+        template <typename octet_iterator>
+        typename std::iterator_traits<octet_iterator>::difference_type
+        distance (octet_iterator first, octet_iterator last)
+        {
+            typename std::iterator_traits<octet_iterator>::difference_type 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
+                if (utf8::internal::is_lead_surrogate(cp)) {
+                    uint32_t trail_surrogate = utf8::internal::mask16(*start++);
+                    cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET;
+                }
+                result = utf8::unchecked::append(cp, result);
+            }
+            return result;         
+        }
+
+        template <typename u16bit_iterator, typename octet_iterator>
+        u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result)
+        {
+            while (start < end) {
+                uint32_t cp = utf8::unchecked::next(start);
+                if (cp > 0xffff) { //make a surrogate pair
+                    *result++ = static_cast<uint16_t>((cp >> 10)   + internal::LEAD_OFFSET);
+                    *result++ = static_cast<uint16_t>((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN);
+                }
+                else
+                    *result++ = static_cast<uint16_t>(cp);
+            }
+            return result;
+        }
+
+        template <typename octet_iterator, typename u32bit_iterator>
+        octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result)
+        {
+            while (start != end)
+                result = utf8::unchecked::append(*(start++), result);
+
+            return result;
+        }
+
+        template <typename octet_iterator, typename u32bit_iterator>
+        u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result)
+        {
+            while (start < end)
+                (*result++) = utf8::unchecked::next(start);
+
+            return result;
+        }
+
+        // The iterator class
+        template <typename octet_iterator>
+          class iterator : public std::iterator <std::bidirectional_iterator_tag, uint32_t> { 
+            octet_iterator it;
+            public:
+            iterator () {}
+            explicit iterator (const octet_iterator& octet_it): it(octet_it) {}
+            // the default "big three" are OK
+            octet_iterator base () const { return it; }
+            uint32_t operator * () const
+            {
+                octet_iterator temp = it;
+                return utf8::unchecked::next(temp);
+            }
+            bool operator == (const iterator& rhs) const 
+            { 
+                return (it == rhs.it);
+            }
+            bool operator != (const iterator& rhs) const
+            {
+                return !(operator == (rhs));
+            }
+            iterator& operator ++ () 
+            {
+                ::std::advance(it, utf8::internal::sequence_length(it));
+                return *this;
+            }
+            iterator operator ++ (int)
+            {
+                iterator temp = *this;
+                ::std::advance(it, utf8::internal::sequence_length(it));
+                return temp;
+            }  
+            iterator& operator -- ()
+            {
+                utf8::unchecked::prior(it);
+                return *this;
+            }
+            iterator operator -- (int)
+            {
+                iterator temp = *this;
+                utf8::unchecked::prior(it);
+                return temp;
+            }
+          }; // class iterator
+
+    } // namespace utf8::unchecked
+} // namespace utf8 
+
+
+#endif // header guard
+
diff --git a/libsass/src/utf8_string.cpp b/libsass/src/utf8_string.cpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/utf8_string.cpp
@@ -0,0 +1,97 @@
+#include <string>
+#include <vector>
+#include <cstdlib>
+#include <cmath>
+
+#include "utf8.h"
+
+namespace Sass {
+  namespace UTF_8 {
+    using std::string;
+
+    // naming conventions:
+    // offset: raw byte offset (0 based)
+    // position: code point offset (0 based)
+    // index: code point offset (1 based or negative)
+
+    // function that will count the number of code points (utf-8 characters) from the given beginning to the given end
+    size_t code_point_count(const string& str, size_t start, size_t end) {
+      return utf8::distance(str.begin() + start, str.begin() + end);
+    }
+
+    size_t code_point_count(const string& str) {
+      return utf8::distance(str.begin(), str.end());
+    }
+
+    // function that will return the byte offset at a code point position
+    size_t offset_at_position(const string& str, size_t position) {
+      string::const_iterator it = str.begin();
+      utf8::advance(it, position, str.end());
+      return distance(str.begin(), it);
+    }
+
+    // function that returns number of bytes in a character at offset
+    size_t code_point_size_at_offset(const string& str, size_t offset) {
+      // get iterator from string and forward by offset
+      string::const_iterator stop = str.begin() + offset;
+      // check if beyond boundary
+      if (stop == str.end()) return 0;
+      // advance by one code point
+      utf8::advance(stop, 1, str.end());
+      // calculate offset for code point
+      return  stop - str.begin() - offset;
+    }
+
+    // function that will return a normalized index, given a crazy one
+    size_t normalize_index(int index, size_t len) {
+      long signed_len = static_cast<long>(len);
+      // assuming the index is 1-based
+      // we are returning a 0-based index
+      if (index > 0 && index <= signed_len) {
+        // positive and within string length
+        return index-1;
+      }
+      else if (index > signed_len) {
+        // positive and past string length
+        return len;
+      }
+      else if (index == 0) {
+        return 0;
+      }
+      else if (std::abs((double)index) <= signed_len) {
+        // negative and within string length
+        return index + signed_len;
+      }
+      else {
+        // negative and past string length
+        return 0;
+      }
+    }
+
+    // utf16 functions
+    using std::wstring;
+
+    // convert from utf16/wide string to utf8 string
+    string convert_from_utf16(const wstring& utf16)
+    {
+      string utf8;
+      // pre-allocate expected memory
+      utf8.reserve(sizeof(utf16)/2);
+      utf8::utf16to8(utf16.begin(), utf16.end(),
+                     back_inserter(utf8));
+      return utf8;
+    }
+
+    // convert from utf8 string to utf16/wide string
+    wstring convert_to_utf16(const string& utf8)
+    {
+      wstring utf16;
+      // pre-allocate expected memory
+      utf16.reserve(code_point_count(utf8)*2);
+      utf8::utf8to16(utf8.begin(), utf8.end(),
+                     back_inserter(utf16));
+      return utf16;
+    }
+
+  }
+}
diff --git a/libsass/src/utf8_string.hpp b/libsass/src/utf8_string.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/utf8_string.hpp
@@ -0,0 +1,37 @@
+#ifndef SASS_UTF8_STRING_H
+#define SASS_UTF8_STRING_H
+
+#include <string>
+#include "utf8.h"
+
+namespace Sass {
+  namespace UTF_8 {
+
+    // naming conventions:
+    // offset: raw byte offset (0 based)
+    // position: code point offset (0 based)
+    // index: code point offset (1 based or negative)
+
+    // function that will count the number of code points (utf-8 characters) from the beginning to the given end
+    size_t code_point_count(const std::string& str, size_t start, size_t end);
+    size_t code_point_count(const std::string& str);
+
+    // function that will return the byte offset of a code point in a
+    size_t offset_at_position(const std::string& str, size_t position);
+
+    // function that returns number of bytes in a character in a string
+    size_t code_point_size_at_offset(const std::string& str, size_t offset);
+
+    // function that will return a normalized index, given a crazy one
+    size_t normalize_index(int index, size_t len);
+
+    #ifdef _WIN32
+    // functions to handle unicode paths on windows
+    std::string convert_from_utf16(const std::wstring& wstr);
+    std::wstring convert_to_utf16(const std::string& str);
+    #endif
+
+  }
+}
+
+#endif
diff --git a/libsass/src/util.cpp b/libsass/src/util.cpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/util.cpp
@@ -0,0 +1,780 @@
+#include "sass.h"
+#include "ast.hpp"
+#include "util.hpp"
+#include "lexer.hpp"
+#include "prelexer.hpp"
+#include "constants.hpp"
+#include "utf8/checked.h"
+
+#include <cmath>
+#include <stdint.h>
+
+namespace Sass {
+
+  #define out_of_memory() do {            \
+      std::cerr << "Out of memory.\n";    \
+      exit(EXIT_FAILURE);                 \
+    } while (0)
+
+  double round(double 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)
+  {
+    char separator = *(localeconv()->decimal_point);
+    if(separator != '.'){
+      // The current locale specifies another
+      // separator. convert the separator to the
+      // one understood by the locale if needed
+      const char *found = strchr(str, '.');
+      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);
+        *(copy + (found - str)) = separator;
+        double res = atof(copy);
+        free(copy);
+        return res;
+      }
+    }
+
+    return atof(str);
+  }
+
+  // helper for safe access to c_ctx
+  const char* safe_str (const char* str, const char* alt) {
+    return str == NULL ? alt : str;
+  }
+
+  void free_string_array(char ** arr) {
+    if(!arr)
+        return;
+
+    char **it = arr;
+    while (it && (*it)) {
+      free(*it);
+      ++it;
+    }
+
+    free(arr);
+  }
+
+  char **copy_strings(const std::vector<std::string>& strings, char*** array, int skip) {
+    int num = static_cast<int>(strings.size()) - skip;
+    char** arr = (char**) calloc(num + 1, sizeof(char*));
+    if (arr == 0)
+      return *array = (char **)NULL;
+
+    for(int i = 0; i < num; i++) {
+      arr[i] = (char*) malloc(sizeof(char) * (strings[i + skip].size() + 1));
+      if (arr[i] == 0) {
+        free_string_array(arr);
+        return *array = (char **)NULL;
+      }
+      std::copy(strings[i + skip].begin(), strings[i + skip].end(), arr[i]);
+      arr[i][strings[i + skip].size()] = '\0';
+    }
+
+    arr[num] = 0;
+    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)
+  {
+    std::string out("");
+    bool esc = false;
+    for (auto i : str) {
+      if (i == '\\') {
+        esc = ! esc;
+      } else if (esc && i == '\r') {
+        continue;
+      } else if (esc && i == '\n') {
+        out.resize (out.size () - 1);
+        esc = false;
+        continue;
+      } else {
+        esc = false;
+      }
+      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;
+    }
+    return out;
+  }
+
+  // double escape all escape sequences
+  // keep unescaped quotes and backslashes
+  std::string evacuate_escapes(const std::string& str)
+  {
+    std::string out("");
+    bool esc = false;
+    for (auto i : str) {
+      if (i == '\\' && !esc) {
+        out += '\\';
+        out += '\\';
+        esc = true;
+      } else if (esc && i == '"') {
+        out += '\\';
+        out += i;
+        esc = false;
+      } else if (esc && i == '\'') {
+        out += '\\';
+        out += i;
+        esc = false;
+      } else if (esc && i == '\\') {
+        out += '\\';
+        out += i;
+        esc = false;
+      } else {
+        esc = false;
+        out += i;
+      }
+    }
+    // happens when parsing does not correctly skip
+    // over escaped sequences for ie. interpolations
+    // one example: foo\#{interpolate}
+    // if (esc) out += '\\';
+    return out;
+  }
+
+  // bell character is replaces with space
+  std::string string_to_output(const std::string& str)
+  {
+    std::string out("");
+    bool lf = false;
+    for (auto i : str) {
+      if (i == 10) {
+        out += ' ';
+        lf = true;
+      } else if (!(lf && isspace(i))) {
+        out += i;
+        lf = false;
+      }
+    }
+    return out;
+  }
+
+  std::string comment_to_string(const std::string& text)
+  {
+    std::string str = "";
+    size_t has = 0;
+    char prev = 0;
+    bool clean = false;
+    for (auto i : text) {
+      if (clean) {
+        if (i == '\n') { has = 0; }
+        else if (i == '\r') { has = 0; }
+        else if (i == '\t') { ++ has; }
+        else if (i == ' ') { ++ has; }
+        else if (i == '*') {}
+        else {
+          clean = false;
+          str += ' ';
+          if (prev == '*' && i == '/') str += "*/";
+          else str += i;
+        }
+      } else if (i == '\n') {
+        clean = true;
+      } else if (i == '\r') {
+        clean = true;
+      } else {
+        str += i;
+      }
+      prev = i;
+    }
+    if (has) return str;
+    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
+  // quotes, which will trigger the use of single quotes as best quote_mark.
+  char detect_best_quotemark(const char* s, char qm)
+  {
+    // ensure valid fallback quote_mark
+    char quote_mark = qm && qm != '*' ? qm : '"';
+    while (*s) {
+      // force double quotes as soon
+      // as one single quote is found
+      if (*s == '\'') { return '"'; }
+      // a single does not force quote_mark
+      // maybe we see a double quote later
+      else if (*s == '"') { quote_mark = '\''; }
+      ++ s;
+    }
+    return quote_mark;
+  }
+
+  std::string unquote(const std::string& s, char* qd, bool keep_utf8_sequences)
+  {
+
+    // not enough room for quotes
+    // no possibility to unquote
+    if (s.length() < 2) return s;
+
+    char q;
+    bool skipped = false;
+
+    // this is no guarantee that the unquoting will work
+    // what about whitespace before/after the quote_mark?
+    if      (*s.begin() == '"'  && *s.rbegin() == '"')  q = '"';
+    else if (*s.begin() == '\'' && *s.rbegin() == '\'') q = '\'';
+    else                                                return s;
+
+    std::string unq;
+    unq.reserve(s.length()-2);
+
+    for (size_t i = 1, L = s.length() - 1; i < L; ++i) {
+
+      // implement the same strange ruby sass behavior
+      // an escape sequence can also mean a unicode char
+      if (s[i] == '\\' && !skipped) {
+        // remember
+        skipped = true;
+
+        // skip it
+        // ++ i;
+
+        // if (i == L) break;
+
+        // escape length
+        size_t len = 1;
+
+        // parse as many sequence chars as possible
+        // ToDo: Check if ruby aborts after possible max
+        while (i + len < L && s[i + len] && isxdigit(s[i + len])) ++ len;
+
+        // hex string?
+        if (keep_utf8_sequences) {
+          unq.push_back(s[i]);
+        } else if (len > 1) {
+
+          // convert the extracted hex string to code point value
+          // ToDo: Maybe we could do this without creating a substring
+          uint32_t cp = strtol(s.substr (i + 1, len - 1).c_str(), NULL, 16);
+
+          if (s[i + len] == ' ') ++ len;
+
+          // assert invalid code points
+          if (cp == 0) cp = 0xFFFD;
+          // replace bell character
+          // if (cp == 10) cp = 32;
+
+          // use a very simple approach to convert via utf8 lib
+          // maybe there is a more elegant way; maybe we shoud
+          // convert the whole output from string to a stream!?
+          // allocate memory for utf8 char and convert to utf8
+          unsigned char u[5] = {0,0,0,0,0}; utf8::append(cp, u);
+          for(size_t m = 0; u[m] && m < 5; m++) unq.push_back(u[m]);
+
+          // skip some more chars?
+          i += len - 1; skipped = false;
+
+        }
+
+
+      }
+      // check for unexpected delimiter
+      // be strict and throw error back
+      // else if (!skipped && q == s[i]) {
+      //   // don't be that strict
+      //   return s;
+      //   // this basically always means an internal error and not users fault
+      //   error("Unescaped delimiter in string to unquote found. [" + s + "]", ParserState("[UNQUOTE]"));
+      // }
+      else {
+        skipped = false;
+        unq.push_back(s[i]);
+      }
+
+    }
+    if (skipped) { return s; }
+    if (qd) *qd = q;
+    return unq;
+
+  }
+
+  std::string quote(const std::string& s, char q, bool keep_linefeed_whitespace)
+  {
+
+    // autodetect with fallback to given quote
+    q = detect_best_quotemark(s.c_str(), q);
+
+    // return an empty quoted string
+    if (s.empty()) return std::string(2, q ? q : '"');
+
+    std::string quoted;
+    quoted.reserve(s.length()+2);
+    quoted.push_back(q);
+
+    const char* it = s.c_str();
+    const char* end = it + strlen(it) + 1;
+    while (*it && it < end) {
+      const char* now = it;
+
+      if (*it == q) {
+        quoted.push_back('\\');
+      } else if (*it == '\\') {
+        quoted.push_back('\\');
+      }
+
+      int cp = utf8::next(it, end);
+
+      if (cp == '\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)
+          quoted.push_back(' ');
+      } else if (cp < 127) {
+        quoted.push_back((char) cp);
+      } else {
+        while (now < it) {
+          quoted.push_back(*now);
+          ++ now;
+        }
+      }
+    }
+
+    quoted.push_back(q);
+    return quoted;
+  }
+
+  bool is_hex_doublet(double n)
+  {
+    return n == 0x00 || n == 0x11 || n == 0x22 || n == 0x33 ||
+           n == 0x44 || n == 0x55 || n == 0x66 || n == 0x77 ||
+           n == 0x88 || n == 0x99 || n == 0xAA || n == 0xBB ||
+           n == 0xCC || n == 0xDD || n == 0xEE || n == 0xFF ;
+  }
+
+  bool is_color_doublet(double r, double g, double b)
+  {
+    return is_hex_doublet(r) && is_hex_doublet(g) && is_hex_doublet(b);
+  }
+
+  bool peek_linefeed(const char* start)
+  {
+    using namespace Prelexer;
+    using namespace Constants;
+    return sequence <
+             zero_plus <
+               alternatives <
+                 exactly <' '>,
+                 exactly <'\t'>,
+                 line_comment,
+                 block_comment,
+                 delimited_by <
+                   slash_star,
+                   star_slash,
+                   false
+                 >
+               >
+             >,
+             re_linebreak
+           >(start) != 0;
+  }
+
+  namespace Util {
+    using std::string;
+
+    std::string rtrim(const std::string &str) {
+      std::string trimmed = str;
+      size_t pos_ws = trimmed.find_last_not_of(" \t\n\v\f\r");
+      if (pos_ws != std::string::npos)
+      { trimmed.erase(pos_ws + 1); }
+      else { trimmed.clear(); }
+      return trimmed;
+    }
+
+    std::string normalize_underscores(const std::string& str) {
+      std::string normalized = str;
+      for(size_t i = 0, L = normalized.length(); i < L; ++i) {
+        if(normalized[i] == '_') {
+          normalized[i] = '-';
+        }
+      }
+      return normalized;
+    }
+
+    std::string normalize_decimals(const std::string& str) {
+      std::string prefix = "0";
+      std::string normalized = str;
+
+      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) {
+      if (r == NULL) {
+        return false;
+      }
+
+      Block* b = r->block();
+
+      bool hasSelectors = static_cast<Selector_List*>(r->selector())->length() > 0;
+
+      if (!hasSelectors) {
+        return false;
+      }
+
+      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)) {
+          return true;
+        } else if (dynamic_cast<Has_Block*>(stm)) {
+          Block* pChildBlock = ((Has_Block*)stm)->block();
+          if (isPrintable(pChildBlock, style)) {
+            hasPrintableChildBlocks = true;
+          }
+        } else if (Comment* c = dynamic_cast<Comment*>(stm)) {
+          // keep for uncompressed
+          if (style != SASS_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;
+        }
+
+        if (hasDeclarations || hasPrintableChildBlocks) {
+          return true;
+        }
+      }
+
+      return false;
+    }
+
+    bool isPrintable(String_Constant* s, Sass_Output_Style style)
+    {
+      return ! s->value().empty();
+    }
+
+    bool isPrintable(String_Quoted* s, Sass_Output_Style style)
+    {
+      return true;
+    }
+
+    bool isPrintable(Declaration* 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);
+      return true;
+    }
+
+    bool isPrintable(Supports_Block* f, Sass_Output_Style style) {
+      if (f == NULL) {
+        return false;
+      }
+
+      Block* b = f->block();
+
+//      bool hasSelectors = f->selector() && static_cast<Selector_List*>(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)) {
+          hasDeclarations = true;
+        }
+        else if (dynamic_cast<Has_Block*>(stm)) {
+          Block* pChildBlock = ((Has_Block*)stm)->block();
+          if (isPrintable(pChildBlock, style)) {
+            hasPrintableChildBlocks = true;
+          }
+        }
+
+        if (hasDeclarations || hasPrintableChildBlocks) {
+          return true;
+        }
+      }
+
+      return false;
+    }
+
+    bool isPrintable(Media_Block* m, Sass_Output_Style style)
+    {
+      if (m == 0) return false;
+      Block* 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;
+        }
+      }
+      return false;
+    }
+
+    bool isPrintable(Block* b, Sass_Output_Style style) {
+      if (b == NULL) {
+        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)) {
+          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()) {
+            return true;
+          }
+        }
+        else if (typeid(*stm) == typeid(Ruleset)) {
+          Ruleset* r = (Ruleset*) stm;
+          if (isPrintable(r, style)) {
+            return true;
+          }
+        }
+        else if (typeid(*stm) == typeid(Supports_Block)) {
+          Supports_Block* f = (Supports_Block*) stm;
+          if (isPrintable(f, style)) {
+            return true;
+          }
+        }
+        else if (typeid(*stm) == typeid(Media_Block)) {
+          Media_Block* m = (Media_Block*) stm;
+          if (isPrintable(m, style)) {
+            return true;
+          }
+        }
+        else if (dynamic_cast<Has_Block*>(stm) && isPrintable(((Has_Block*)stm)->block(), style)) {
+          return true;
+        }
+      }
+
+      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;
+     }
+
+  }
+}
diff --git a/libsass/src/util.hpp b/libsass/src/util.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/util.hpp
@@ -0,0 +1,61 @@
+#ifndef SASS_UTIL_H
+#define SASS_UTIL_H
+
+#include <vector>
+#include <string>
+#include <assert.h>
+#include "sass/base.h"
+#include "ast_fwd_decl.hpp"
+
+#define SASS_ASSERT(cond, msg) assert(cond && msg)
+
+namespace Sass {
+
+  double round(double val);
+  char* sass_strdup(const char* str);
+  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);
+
+  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);
+  char detect_best_quotemark(const char* s, char qm = '"');
+
+  bool is_hex_doublet(double n);
+  bool is_color_doublet(double r, double g, double b);
+
+  bool peek_linefeed(const char* start);
+
+  namespace Util {
+
+    std::string rtrim(const std::string& str);
+
+    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 isAscii(const char chr);
+
+  }
+}
+#endif
diff --git a/libsass/src/values.cpp b/libsass/src/values.cpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/values.cpp
@@ -0,0 +1,137 @@
+#include "sass.h"
+#include "values.hpp"
+
+#include <stdint.h>
+
+namespace Sass {
+
+  // convert value from C++ side to C-API
+  union Sass_Value* ast_node_to_sass_value (const Expression* val)
+  {
+    if (val->concrete_type() == Expression::NUMBER)
+    {
+      const Number* res = dynamic_cast<const Number*>(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);
+      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);
+      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]);
+        sass_list_set_value(list, i, val);
+      }
+      return list;
+    }
+    else if (val->concrete_type() == Expression::MAP)
+    {
+      const Map* m = dynamic_cast<const Map*>(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)));
+        ++ i;
+      }
+      return map;
+    }
+    else if (val->concrete_type() == Expression::NULL_VAL)
+    {
+      return sass_make_null();
+    }
+    else if (val->concrete_type() == Expression::BOOLEAN)
+    {
+      const Boolean* res = dynamic_cast<const Boolean*>(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))
+      {
+        return sass_make_qstring(qstr->value().c_str());
+      }
+      else if (const String_Constant* cstr = dynamic_cast<const String_Constant*>(val))
+      {
+        return sass_make_string(cstr->value().c_str());
+      }
+    }
+    return sass_make_error("unknown sass value type");
+  }
+
+  // convert value from C-API to C++ side
+  Value* sass_value_to_ast_node (Memory_Manager& mem, const union Sass_Value* val)
+  {
+    switch (sass_value_get_tag(val)) {
+      case SASS_NUMBER:
+        return SASS_MEMORY_NEW(mem, Number,
+                               ParserState("[C-VALUE]"),
+                               sass_number_get_value(val),
+                               sass_number_get_unit(val));
+      break;
+      case SASS_BOOLEAN:
+        return SASS_MEMORY_NEW(mem, Boolean,
+                               ParserState("[C-VALUE]"),
+                               sass_boolean_get_value(val));
+      break;
+      case SASS_COLOR:
+        return SASS_MEMORY_NEW(mem, Color,
+                               ParserState("[C-VALUE]"),
+                               sass_color_get_r(val),
+                               sass_color_get_g(val),
+                               sass_color_get_b(val),
+                               sass_color_get_a(val));
+      break;
+      case SASS_STRING:
+        if (sass_string_is_quoted(val)) {
+          return SASS_MEMORY_NEW(mem, String_Quoted,
+                                 ParserState("[C-VALUE]"),
+                                 sass_string_get_value(val));
+        } else {
+          return SASS_MEMORY_NEW(mem, String_Constant,
+                                 ParserState("[C-VALUE]"),
+                                 sass_string_get_value(val));
+        }
+      break;
+      case SASS_LIST: {
+        List* l = SASS_MEMORY_NEW(mem, 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));
+        }
+        return l;
+      }
+      break;
+      case SASS_MAP: {
+        Map* m = SASS_MEMORY_NEW(mem, 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)));
+        }
+        return m;
+      }
+      break;
+      case SASS_NULL:
+        return SASS_MEMORY_NEW(mem, Null, ParserState("[C-VALUE]"));
+      break;
+      case SASS_ERROR:
+        return SASS_MEMORY_NEW(mem, Custom_Error,
+                               ParserState("[C-VALUE]"),
+                               sass_error_get_message(val));
+      break;
+      case SASS_WARNING:
+        return SASS_MEMORY_NEW(mem, Custom_Warning,
+                               ParserState("[C-VALUE]"),
+                               sass_warning_get_message(val));
+      break;
+    }
+    return 0;
+  }
+
+}
diff --git a/libsass/src/values.hpp b/libsass/src/values.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/src/values.hpp
@@ -0,0 +1,12 @@
+#ifndef SASS_VALUES_H
+#define SASS_VALUES_H
+
+#include "ast.hpp"
+
+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);
+
+}
+#endif
diff --git a/libsass/subset_map.hpp b/libsass/subset_map.hpp
deleted file mode 100644
--- a/libsass/subset_map.hpp
+++ /dev/null
@@ -1,147 +0,0 @@
-#ifndef SASS_SUBSET_MAP_H
-#define SASS_SUBSET_MAP_H
-
-#include <map>
-#include <set>
-#include <vector>
-#include <algorithm>
-#include <iterator>
-#include <iostream>
-#include <sstream>
-
-// using namespace std;
-
-// template<typename T>
-// string vector_to_string(vector<T> v)
-// {
-//   stringstream buffer;
-//   buffer << "[";
-
-//   if (!v.empty())
-//   {  buffer << v[0]; }
-//   else
-//   { buffer << "]"; }
-
-//   if (v.size() == 1)
-//   { buffer << "]"; }
-//   else
-//   {
-//     for (size_t i = 1, S = v.size(); i < S; ++i) buffer << ", " << v[i];
-//     buffer << "]";
-//   }
-
-//   return buffer.str();
-// }
-
-// template<typename T>
-// string set_to_string(set<T> v)
-// {
-//   stringstream buffer;
-//   buffer << "[";
-//   typename set<T>::iterator i = v.begin();
-//   if (!v.empty())
-//   {  buffer << *i; }
-//   else
-//   { buffer << "]"; }
-
-//   if (v.size() == 1)
-//   { buffer << "]"; }
-//   else
-//   {
-//     for (++i; i != v.end(); ++i) buffer << ", " << *i;
-//     buffer << "]";
-//   }
-
-//   return buffer.str();
-// }
-
-namespace Sass {
-  using namespace std;
-
-  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:
-    vector<V> values_;
-    map<K, vector<triple<vector<K>, set<K>, size_t> > > hash_;
-  public:
-    void put(const vector<K>& s, const V& value);
-    vector<pair<V, vector<K> > > get_kv(const vector<K>& s);
-    vector<V> get_v(const vector<K>& s);
-    bool empty() { return values_.empty(); }
-    void clear() { values_.clear(); hash_.clear(); }
-    const vector<V> values(void) { return values_; }
-  };
-
-  template<typename K, typename V>
-  void Subset_Map<K, V>::put(const 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);
-    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>
-  vector<pair<V, vector<K> > > Subset_Map<K, V>::get_kv(const vector<K>& s)
-  {
-    vector<K> sorted = s;
-    sort(sorted.begin(), sorted.end());
-    vector<pair<size_t, vector<K> > > indices;
-    for (size_t i = 0, S = s.size(); i < S; ++i) {
-      if (!hash_.count(s[i])) {
-        continue;
-      }
-      vector<triple<vector<K>, set<K>, size_t> > subsets = hash_[s[i]];
-      // cerr << "length of subsets: " << subsets.size() << 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())) {
-          // cout << vector_to_string(s) << " doesn't include " << set_to_string(subsets[j].second) << endl;
-          continue;
-        }
-        indices.push_back(make_pair(subsets[j].third, subsets[j].first));
-        // cerr << "pushed " << subsets[j].third << " and " << vector_to_string(subsets[j].first) << " onto indices" << endl;
-      }
-    }
-    sort(indices.begin(), indices.end());
-    typename vector<pair<size_t, vector<K> > >::iterator indices_end = unique(indices.begin(), indices.end());
-    indices.resize(distance(indices.begin(), indices_end));
-
-    vector<pair<V, vector<K> > > results;
-    for (size_t i = 0, S = indices.size(); i < S; ++i) {
-      results.push_back(make_pair(values_[indices[i].first], indices[i].second));
-    }
-    return results;
-  }
-
-  template<typename K, typename V>
-  vector<V> Subset_Map<K, V>::get_v(const vector<K>& s)
-  {
-    vector<pair<V, vector<K> > > kvs = get_kv(s);
-    vector<V> results;
-    for (size_t i = 0, S = kvs.size(); i < S; ++i) results.push_back(kvs[i].first);
-    return results;
-  }
-
-}
-
-#endif
diff --git a/libsass/to_c.cpp b/libsass/to_c.cpp
deleted file mode 100644
--- a/libsass/to_c.cpp
+++ /dev/null
@@ -1,61 +0,0 @@
-#include "to_c.hpp"
-#include "ast.hpp"
-
-#include "sass_values.h"
-
-namespace Sass {
-  using namespace std;
-
-  Sass_Value* To_C::fallback_impl(AST_Node* n)
-  { return sass_make_null(); }
-
-  Sass_Value* To_C::operator()(Boolean* b)
-  { return sass_make_boolean(b->value()); }
-
-  Sass_Value* To_C::operator()(Number* n)
-  { return sass_make_number(n->value(), n->unit().c_str()); }
-
-  Sass_Value* To_C::operator()(Color* c)
-  { return sass_make_color(c->r(), c->g(), c->b(), c->a()); }
-
-  Sass_Value* To_C::operator()(String_Constant* s)
-  { return sass_make_string(s->value().c_str()); }
-
-  Sass_Value* To_C::operator()(List* l)
-  {
-    Sass_Value* v = sass_make_list(l->length(), l->separator() == List::COMMA ? SASS_COMMA : SASS_SPACE);
-    for (size_t i = 0, L = l->length(); i < L; ++i) {
-      sass_list_set_value(v, i, (*l)[i]->perform(this));
-    }
-    return v;
-  }
-
-  Sass_Value* To_C::operator()(Map* m)
-  {
-    Sass_Value* v = sass_make_map(m->length());
-    int i = 0;
-    for (auto key : m->keys()) {
-      sass_map_set_key(v, i, key->perform(this));
-      sass_map_set_value(v, i, m->at(key)->perform(this));
-      i++;
-    }
-    return v;
-  }
-
-  Sass_Value* To_C::operator()(Arguments* a)
-  {
-    Sass_Value* v = sass_make_list(a->length(), SASS_COMMA);
-    for (size_t i = 0, L = a->length(); i < L; ++i) {
-      sass_list_set_value(v, i, (*a)[i]->perform(this));
-    }
-    return v;
-  }
-
-  Sass_Value* To_C::operator()(Argument* a)
-  { return a->value()->perform(this); }
-
-  // not strictly necessary because of the fallback
-  Sass_Value* To_C::operator()(Null* n)
-  { return sass_make_null(); }
-
-};
diff --git a/libsass/to_c.hpp b/libsass/to_c.hpp
deleted file mode 100644
--- a/libsass/to_c.hpp
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifndef SASS_TO_C_H
-#define SASS_TO_C_H
-
-#include "operation.hpp"
-#include "sass_values.h"
-
-namespace Sass {
-  using namespace std;
-
-  class AST_Node;
-  class Boolean;
-  class Number;
-  class String_Constant;
-  class List;
-  class Map;
-  class Null;
-
-  class To_C : public Operation_CRTP<Sass_Value*, To_C> {
-
-    Sass_Value* fallback_impl(AST_Node* n);
-
-  public:
-
-    To_C() { }
-    virtual ~To_C() { }
-    using Operation<Sass_Value*>::operator();
-
-    Sass_Value* operator()(Boolean*);
-    Sass_Value* operator()(Number*);
-    Sass_Value* operator()(Color*);
-    Sass_Value* operator()(String_Constant*);
-    Sass_Value* operator()(List*);
-    Sass_Value* operator()(Map*);
-    Sass_Value* operator()(Null*);
-    Sass_Value* operator()(Arguments*);
-    Sass_Value* operator()(Argument*);
-
-    template <typename U>
-    Sass_Value* fallback(U x) { return fallback_impl(x); }
-  };
-
-}
-
-#endif
diff --git a/libsass/to_string.cpp b/libsass/to_string.cpp
deleted file mode 100644
--- a/libsass/to_string.cpp
+++ /dev/null
@@ -1,34 +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 {
-  using namespace std;
-
-  To_String::To_String(Context* ctx, bool in_declaration)
-  : ctx(ctx), in_declaration(in_declaration) { }
-  To_String::~To_String() { }
-
-  inline string To_String::fallback_impl(AST_Node* n)
-  {
-    Emitter emitter(ctx);
-    Inspect i(emitter);
-    i.in_declaration = in_declaration;
-    n->perform(&i);
-    return i.get_buffer();
-  }
-
-  inline string To_String::operator()(String_Constant* s)
-  {
-    return s->value();
-  }
-
-  inline string To_String::operator()(Null* n)
-  { return ""; }
-}
diff --git a/libsass/to_string.hpp b/libsass/to_string.hpp
deleted file mode 100644
--- a/libsass/to_string.hpp
+++ /dev/null
@@ -1,35 +0,0 @@
-#ifndef SASS_TO_STRING_H
-#define SASS_TO_STRING_H
-
-#include <string>
-
-#include "operation.hpp"
-
-namespace Sass {
-  using namespace std;
-
-  class Context;
-  class Null;
-
-  class To_String : public Operation_CRTP<string, To_String> {
-    // import all the class-specific methods and override as desired
-    using Operation<string>::operator();
-    // override this to define a catch-all
-    string fallback_impl(AST_Node* n);
-
-    Context* ctx;
-    bool in_declaration;
-
-  public:
-    To_String(Context* ctx = 0, bool in_declaration = true);
-    virtual ~To_String();
-
-    string operator()(Null* n);
-    string operator()(String_Constant*);
-
-    template <typename U>
-    string fallback(U n) { return fallback_impl(n); }
-  };
-}
-
-#endif
diff --git a/libsass/units.cpp b/libsass/units.cpp
deleted file mode 100644
--- a/libsass/units.cpp
+++ /dev/null
@@ -1,155 +0,0 @@
-#include <stdexcept>
-#include "units.hpp"
-
-namespace Sass {
-
-  /* the conversion matrix can be readed the following way */
-  /* if you go down, the factor is for the numerator (multiply) */
-  /* if you go right, the factor is for the denominator (divide) */
-  /* and yes, we actually use both, not sure why, but why not!? */
-
-  const double size_conversion_factors[6][6] =
-  {
-             /*  in         cm         pc         mm         pt         px        */
-    /* in   */ { 1,         2.54,      6,         25.4,      72,        96,       },
-    /* cm   */ { 1.0/2.54,  1,         6.0/2.54,  10,        72.0/2.54, 96.0/2.54 },
-    /* pc   */ { 1.0/6.0,   2.54/6.0,  1,         25.4/6.0,  72.0/6.0,  96.0/6.0  },
-    /* mm   */ { 1.0/25.4,  1.0/10.0,  6.0/25.4,  1,         72.0/25.4, 96.0/25.4 },
-    /* pt   */ { 1.0/72.0,  2.54/72.0, 6.0/72.0,  25.4/72.0, 1,         96.0/72.0 },
-    /* px   */ { 1.0/96.0,  2.54/96.0, 6.0/96.0,  25.4/96.0, 72.0/96.0, 1,        }
-  };
-
-  const double angle_conversion_factors[4][4] =
-  {
-             /*  deg        grad       rad        turn      */
-    /* deg  */ { 1,         40.0/36.0, PI/180.0,  1.0/360.0 },
-    /* grad */ { 36.0/40.0, 1,         PI/200.0,  1.0/400.0 },
-    /* rad  */ { 180.0/PI,  200.0/PI,  1,         0.5/PI    },
-    /* turn */ { 360.0,     400.0,     2.0*PI,    1         }
-  };
-
-  const double time_conversion_factors[2][2] =
-  {
-             /*  s          ms        */
-    /* s    */ { 1,         1000.0    },
-    /* ms   */ { 1/1000.0,  1         }
-  };
-  const double frequency_conversion_factors[2][2] =
-  {
-             /*  Hz         kHz       */
-    /* Hz   */ { 1,         1/1000.0  },
-    /* kHz  */ { 1000.0,    1         }
-  };
-  const double resolution_conversion_factors[3][3] =
-  {
-             /*  dpi        dpcm       dppx     */
-    /* dpi  */ { 1,         2.54,      96       },
-    /* dpcm */ { 1/2.54,    1,         96/2.54  },
-    /* dppx */ { 1/96.0,    2.54/96,   1        }
-  };
-
-  SassUnitType get_unit_type(SassUnit unit)
-  {
-    switch (unit & 0xFF00)
-    {
-      case SIZE: return SIZE; break;
-      case ANGLE: return ANGLE; break;
-      case TIME: return TIME; break;
-      case FREQUENCY: return FREQUENCY; break;
-      case RESOLUTION: return RESOLUTION; break;
-      default: return INCOMMENSURABLE; break;
-    }
-  };
-
-  SassUnit string_to_unit(const string& s)
-  {
-    // size units
-    if      (s == "px") return PX;
-    else if (s == "pt") return PT;
-    else if (s == "pc") return PC;
-    else if (s == "mm") return MM;
-    else if (s == "cm") return CM;
-    else if (s == "in") return IN;
-    // angle units
-    else if (s == "deg") return DEG;
-    else if (s == "grad") return GRAD;
-    else if (s == "rad") return RAD;
-    else if (s == "turn") return TURN;
-    // time units
-    else if (s == "s") return SEC;
-    else if (s == "ms") return MSEC;
-    // frequency units
-    else if (s == "Hz") return HERTZ;
-    else if (s == "kHz") return KHERTZ;
-    // resolutions units
-    else if (s == "dpi") return DPI;
-    else if (s == "dpcm") return DPCM;
-    else if (s == "dppx") return DPPX;
-    // for unknown units
-    else return UNKNOWN;
-  }
-
-  const char* unit_to_string(SassUnit unit)
-  {
-    switch (unit) {
-      // size units
-      case PX: return "px"; break;
-      case PT: return "pt"; break;
-      case PC: return "pc"; break;
-      case MM: return "mm"; break;
-      case CM: return "cm"; break;
-      case IN: return "in"; break;
-      // angle units
-      case DEG: return "deg"; break;
-      case GRAD: return "grad"; break;
-      case RAD: return "rad"; break;
-      case TURN: return "turn"; break;
-      // time units
-      case SEC: return "s"; break;
-      case MSEC: return "ms"; break;
-      // frequency units
-      case HERTZ: return "Hz"; break;
-      case KHERTZ: return "kHz"; break;
-      // resolutions units
-      case DPI: return "dpi"; break;
-      case DPCM: return "dpcm"; break;
-      case DPPX: return "dppx"; break;
-      // for unknown units
-      default: return ""; break;;
-    }
-  }
-
-  // throws incompatibleUnits exceptions
-  double conversion_factor(const string& s1, const string& s2)
-  {
-    // assert for same units
-    if (s1 == s2) return 1;
-    // get unit enum from string
-    SassUnit u1 = string_to_unit(s1);
-    SassUnit u2 = string_to_unit(s2);
-    // query unit group types
-    SassUnitType t1 = get_unit_type(u1);
-    SassUnitType t2 = get_unit_type(u2);
-    // get absolute offset
-    // used for array acces
-    size_t i1 = u1 - t1;
-    size_t i2 = u2 - t2;
-    // error if units are not of the same group
-    if (t1 != t2) throw incompatibleUnits(u1, u2);
-    // only process known units
-    if (u1 != UNKNOWN && u2 != UNKNOWN) {
-      switch (t1) {
-        case SIZE: return size_conversion_factors[i1][i2]; break;
-        case ANGLE: return angle_conversion_factors[i1][i2]; break;
-        case TIME: return time_conversion_factors[i1][i2]; break;
-        case FREQUENCY: return frequency_conversion_factors[i1][i2]; break;
-        case RESOLUTION: return resolution_conversion_factors[i1][i2]; break;
-        // ToDo: should we throw error here?
-        case INCOMMENSURABLE: return 0; break;
-      }
-    }
-    // fallback
-    return 1;
-  }
-
-}
diff --git a/libsass/units.hpp b/libsass/units.hpp
deleted file mode 100644
--- a/libsass/units.hpp
+++ /dev/null
@@ -1,89 +0,0 @@
-#ifndef SASS_UNITS_H
-#define SASS_UNITS_H
-
-#include <cmath>
-#include <string>
-#include <sstream>
-
-namespace Sass {
-  using namespace std;
-
-  const double PI = acos(-1);
-
-  enum SassUnitType {
-    SIZE = 0x000,
-    ANGLE = 0x100,
-    TIME = 0x200,
-    FREQUENCY = 0x300,
-    RESOLUTION = 0x400,
-    INCOMMENSURABLE = 0x500
-  };
-
-  enum SassUnit {
-
-    // size units
-    IN = SIZE,
-    CM,
-    PC,
-    MM,
-    PT,
-    PX,
-
-    // angle units
-    DEG = ANGLE,
-    GRAD,
-    RAD,
-    TURN,
-
-    // time units
-    SEC = TIME,
-    MSEC,
-
-    // frequency units
-    HERTZ = FREQUENCY,
-    KHERTZ,
-
-    // resolutions units
-    DPI = RESOLUTION,
-    DPCM,
-    DPPX,
-
-    // for unknown units
-    UNKNOWN = INCOMMENSURABLE
-
-  };
-
-  extern const double size_conversion_factors[6][6];
-  extern const double angle_conversion_factors[4][4];
-  extern const double time_conversion_factors[2][2];
-  extern const double frequency_conversion_factors[2][2];
-  extern const double resolution_conversion_factors[3][3];
-
-  SassUnit string_to_unit(const string&);
-  const char* unit_to_string(SassUnit unit);
-  SassUnitType get_unit_type(SassUnit unit);
-  // throws incompatibleUnits exceptions
-  double conversion_factor(const string&, const string&);
-
-  class incompatibleUnits: public exception
-  {
-    public:
-      const char* msg;
-      incompatibleUnits(SassUnit a, SassUnit b)
-      : exception()
-      {
-        stringstream ss;
-        ss << "Incompatible units: ";
-        ss << "'" << unit_to_string(a) << "' and ";
-        ss << "'" << unit_to_string(b) << "'";
-        msg = ss.str().c_str();
-      };
-      virtual const char* what() const throw()
-      {
-        return msg;
-      }
-  };
-
-}
-
-#endif
diff --git a/libsass/utf8.h b/libsass/utf8.h
deleted file mode 100644
--- a/libsass/utf8.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2006 Nemanja Trifunovic
-
-/*
-Permission is hereby granted, free of charge, to any person or organization
-obtaining a copy of the software and accompanying documentation covered by
-this license (the "Software") to use, reproduce, display, distribute,
-execute, and transmit the Software, and to prepare derivative works of the
-Software, and to permit third-parties to whom the Software is furnished to
-do so, all subject to the following:
-
-The copyright notices in the Software and this entire statement, including
-the above license grant, this restriction and the following disclaimer,
-must be included in all copies of the Software, in whole or in part, and
-all derivative works of the Software, unless such copies or derivative
-works are solely in the form of machine-executable object code generated by
-a source language processor.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
-SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
-FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
-ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-DEALINGS IN THE SOFTWARE.
-*/
-
-
-#ifndef UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731
-#define UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731
-
-#include "utf8/checked.h"
-#include "utf8/unchecked.h"
-
-#endif // header guard
diff --git a/libsass/utf8/checked.h b/libsass/utf8/checked.h
deleted file mode 100644
--- a/libsass/utf8/checked.h
+++ /dev/null
@@ -1,327 +0,0 @@
-// Copyright 2006 Nemanja Trifunovic
-
-/*
-Permission is hereby granted, free of charge, to any person or organization
-obtaining a copy of the software and accompanying documentation covered by
-this license (the "Software") to use, reproduce, display, distribute,
-execute, and transmit the Software, and to prepare derivative works of the
-Software, and to permit third-parties to whom the Software is furnished to
-do so, all subject to the following:
-
-The copyright notices in the Software and this entire statement, including
-the above license grant, this restriction and the following disclaimer,
-must be included in all copies of the Software, in whole or in part, and
-all derivative works of the Software, unless such copies or derivative
-works are solely in the form of machine-executable object code generated by
-a source language processor.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
-SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
-FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
-ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-DEALINGS IN THE SOFTWARE.
-*/
-
-
-#ifndef UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
-#define UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
-
-#include "core.h"
-#include <stdexcept>
-
-namespace utf8
-{
-    // Base for the exceptions that may be thrown from the library
-    class exception : public ::std::exception {
-    };
-
-    // Exceptions that may be thrown from the library functions.
-    class invalid_code_point : public exception {
-        uint32_t cp;
-    public:
-        invalid_code_point(uint32_t cp) : cp(cp) {}
-        virtual const char* what() const throw() { return "Invalid code point"; }
-        uint32_t code_point() const {return cp;}
-    };
-
-    class invalid_utf8 : public exception {
-        uint8_t u8;
-    public:
-        invalid_utf8 (uint8_t u) : u8(u) {}
-        virtual const char* what() const throw() { return "Invalid UTF-8"; }
-        uint8_t utf8_octet() const {return u8;}
-    };
-
-    class invalid_utf16 : public exception {
-        uint16_t u16;
-    public:
-        invalid_utf16 (uint16_t u) : u16(u) {}
-        virtual const char* what() const throw() { return "Invalid UTF-16"; }
-        uint16_t utf16_word() const {return u16;}
-    };
-
-    class not_enough_room : public exception {
-    public:
-        virtual const char* what() const throw() { return "Not enough space"; }
-    };
-
-    /// The library API - functions intended to be called by the users
-
-    template <typename octet_iterator>
-    octet_iterator append(uint32_t cp, octet_iterator result)
-    {
-        if (!utf8::internal::is_code_point_valid(cp))
-            throw invalid_code_point(cp);
-
-        if (cp < 0x80)                        // one octet
-            *(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);
-        }
-        else if (cp < 0x10000) {              // three octets
-            *(result++) = static_cast<uint8_t>((cp >> 12)           | 0xe0);
-            *(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f)   | 0x80);
-            *(result++) = static_cast<uint8_t>((cp & 0x3f)          | 0x80);
-        }
-        else {                                // four octets
-            *(result++) = static_cast<uint8_t>((cp >> 18)           | 0xf0);
-            *(result++) = static_cast<uint8_t>(((cp >> 12) & 0x3f)  | 0x80);
-            *(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f)   | 0x80);
-            *(result++) = static_cast<uint8_t>((cp & 0x3f)          | 0x80);
-        }
-        return result;
-    }
-
-    template <typename octet_iterator, typename output_iterator>
-    output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out, uint32_t replacement)
-    {
-        while (start != end) {
-            octet_iterator sequence_start = start;
-            internal::utf_error err_code = utf8::internal::validate_next(start, end);
-            switch (err_code) {
-                case internal::UTF8_OK :
-                    for (octet_iterator it = sequence_start; it != start; ++it)
-                        *out++ = *it;
-                    break;
-                case internal::NOT_ENOUGH_ROOM:
-                    throw not_enough_room();
-                case internal::INVALID_LEAD:
-                    out = utf8::append (replacement, out);
-                    ++start;
-                    break;
-                case internal::INCOMPLETE_SEQUENCE:
-                case internal::OVERLONG_SEQUENCE:
-                case internal::INVALID_CODE_POINT:
-                    out = utf8::append (replacement, out);
-                    ++start;
-                    // just one replacement mark for the sequence
-                    while (start != end && utf8::internal::is_trail(*start))
-                        ++start;
-                    break;
-            }
-        }
-        return out;
-    }
-
-    template <typename octet_iterator, typename output_iterator>
-    inline output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out)
-    {
-        static const uint32_t replacement_marker = utf8::internal::mask16(0xfffd);
-        return utf8::replace_invalid(start, end, out, replacement_marker);
-    }
-
-    template <typename octet_iterator>
-    uint32_t next(octet_iterator& it, octet_iterator end)
-    {
-        uint32_t cp = 0;
-        internal::utf_error err_code = utf8::internal::validate_next(it, end, cp);
-        switch (err_code) {
-            case internal::UTF8_OK :
-                break;
-            case internal::NOT_ENOUGH_ROOM :
-                throw not_enough_room();
-            case internal::INVALID_LEAD :
-            case internal::INCOMPLETE_SEQUENCE :
-            case internal::OVERLONG_SEQUENCE :
-                throw invalid_utf8(*it);
-            case internal::INVALID_CODE_POINT :
-                throw invalid_code_point(cp);
-        }
-        return cp;
-    }
-
-    template <typename octet_iterator>
-    uint32_t peek_next(octet_iterator it, octet_iterator end)
-    {
-        return utf8::next(it, end);
-    }
-
-    template <typename octet_iterator>
-    uint32_t prior(octet_iterator& it, octet_iterator start)
-    {
-        // can't do much if it == start
-        if (it == start)
-            throw not_enough_room();
-
-        octet_iterator end = it;
-        // Go back until we hit either a lead octet or start
-        while (utf8::internal::is_trail(*(--it)))
-            if (it == start)
-                throw invalid_utf8(*it); // error - no lead byte in the sequence
-        return utf8::peek_next(it, end);
-    }
-
-    /// Deprecated in versions that include "prior"
-    template <typename octet_iterator>
-    uint32_t previous(octet_iterator& it, octet_iterator pass_start)
-    {
-        octet_iterator end = it;
-        while (utf8::internal::is_trail(*(--it)))
-            if (it == pass_start)
-                throw invalid_utf8(*it); // error - no lead byte in the sequence
-        octet_iterator temp = it;
-        return utf8::next(temp, end);
-    }
-
-    template <typename octet_iterator, typename distance_type>
-    void advance (octet_iterator& it, distance_type n, octet_iterator end)
-    {
-        for (distance_type i = 0; i < n; ++i)
-            utf8::next(it, end);
-    }
-
-    template <typename octet_iterator>
-    typename std::iterator_traits<octet_iterator>::difference_type
-    distance (octet_iterator first, octet_iterator last)
-    {
-        typename std::iterator_traits<octet_iterator>::difference_type dist;
-        for (dist = 0; first < last; ++dist)
-            utf8::next(first, last);
-        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
-            if (utf8::internal::is_lead_surrogate(cp)) {
-                if (start != end) {
-                    uint32_t trail_surrogate = utf8::internal::mask16(*start++);
-                    if (utf8::internal::is_trail_surrogate(trail_surrogate))
-                        cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET;
-                    else
-                        throw invalid_utf16(static_cast<uint16_t>(trail_surrogate));
-                }
-                else
-                    throw invalid_utf16(static_cast<uint16_t>(cp));
-
-            }
-            // Lone trail surrogate
-            else if (utf8::internal::is_trail_surrogate(cp))
-                throw invalid_utf16(static_cast<uint16_t>(cp));
-
-            result = utf8::append(cp, result);
-        }
-        return result;
-    }
-
-    template <typename u16bit_iterator, typename octet_iterator>
-    u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result)
-    {
-        while (start != end) {
-            uint32_t cp = utf8::next(start, end);
-            if (cp > 0xffff) { //make a surrogate pair
-                *result++ = static_cast<uint16_t>((cp >> 10)   + internal::LEAD_OFFSET);
-                *result++ = static_cast<uint16_t>((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN);
-            }
-            else
-                *result++ = static_cast<uint16_t>(cp);
-        }
-        return result;
-    }
-
-    template <typename octet_iterator, typename u32bit_iterator>
-    octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result)
-    {
-        while (start != end)
-            result = utf8::append(*(start++), result);
-
-        return result;
-    }
-
-    template <typename octet_iterator, typename u32bit_iterator>
-    u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result)
-    {
-        while (start != end)
-            (*result++) = utf8::next(start, end);
-
-        return result;
-    }
-
-    // The iterator class
-    template <typename octet_iterator>
-    class iterator : public std::iterator <std::bidirectional_iterator_tag, uint32_t> {
-      octet_iterator it;
-      octet_iterator range_start;
-      octet_iterator range_end;
-      public:
-      iterator () {}
-      explicit iterator (const octet_iterator& octet_it,
-                         const octet_iterator& range_start,
-                         const octet_iterator& range_end) :
-               it(octet_it), range_start(range_start), range_end(range_end)
-      {
-          if (it < range_start || it > range_end)
-              throw std::out_of_range("Invalid utf-8 iterator position");
-      }
-      // the default "big three" are OK
-      octet_iterator base () const { return it; }
-      uint32_t operator * () const
-      {
-          octet_iterator temp = it;
-          return utf8::next(temp, range_end);
-      }
-      bool operator == (const iterator& rhs) const
-      {
-          if (range_start != rhs.range_start || range_end != rhs.range_end)
-              throw std::logic_error("Comparing utf-8 iterators defined with different ranges");
-          return (it == rhs.it);
-      }
-      bool operator != (const iterator& rhs) const
-      {
-          return !(operator == (rhs));
-      }
-      iterator& operator ++ ()
-      {
-          utf8::next(it, range_end);
-          return *this;
-      }
-      iterator operator ++ (int)
-      {
-          iterator temp = *this;
-          utf8::next(it, range_end);
-          return temp;
-      }
-      iterator& operator -- ()
-      {
-          utf8::prior(it, range_start);
-          return *this;
-      }
-      iterator operator -- (int)
-      {
-          iterator temp = *this;
-          utf8::prior(it, range_start);
-          return temp;
-      }
-    }; // class iterator
-
-} // namespace utf8
-
-#endif //header guard
-
-
diff --git a/libsass/utf8/core.h b/libsass/utf8/core.h
deleted file mode 100644
--- a/libsass/utf8/core.h
+++ /dev/null
@@ -1,329 +0,0 @@
-// Copyright 2006 Nemanja Trifunovic
-
-/*
-Permission is hereby granted, free of charge, to any person or organization
-obtaining a copy of the software and accompanying documentation covered by
-this license (the "Software") to use, reproduce, display, distribute,
-execute, and transmit the Software, and to prepare derivative works of the
-Software, and to permit third-parties to whom the Software is furnished to
-do so, all subject to the following:
-
-The copyright notices in the Software and this entire statement, including
-the above license grant, this restriction and the following disclaimer,
-must be included in all copies of the Software, in whole or in part, and
-all derivative works of the Software, unless such copies or derivative
-works are solely in the form of machine-executable object code generated by
-a source language processor.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
-SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
-FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
-ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-DEALINGS IN THE SOFTWARE.
-*/
-
-
-#ifndef UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
-#define UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
-
-#include <iterator>
-
-namespace utf8
-{
-    // The typedefs for 8-bit, 16-bit and 32-bit unsigned integers
-    // You may need to change them to match your system.
-    // These typedefs have the same names as ones from cstdint, or boost/cstdint
-    typedef unsigned char   uint8_t;
-    typedef unsigned short  uint16_t;
-    typedef unsigned int    uint32_t;
-
-// Helper code - not intended to be directly called by the library users. May be changed at any time
-namespace internal
-{
-    // Unicode constants
-    // Leading (high) surrogates: 0xd800 - 0xdbff
-    // Trailing (low) surrogates: 0xdc00 - 0xdfff
-    const uint16_t LEAD_SURROGATE_MIN  = 0xd800u;
-    const uint16_t LEAD_SURROGATE_MAX  = 0xdbffu;
-    const uint16_t TRAIL_SURROGATE_MIN = 0xdc00u;
-    const uint16_t TRAIL_SURROGATE_MAX = 0xdfffu;
-    const uint16_t LEAD_OFFSET         = LEAD_SURROGATE_MIN - (0x10000 >> 10);
-    const uint32_t SURROGATE_OFFSET    = 0x10000u - (LEAD_SURROGATE_MIN << 10) - TRAIL_SURROGATE_MIN;
-
-    // Maximum valid value for a Unicode code point
-    const uint32_t CODE_POINT_MAX      = 0x0010ffffu;
-
-    template<typename octet_type>
-    inline uint8_t mask8(octet_type oc)
-    {
-        return static_cast<uint8_t>(0xff & oc);
-    }
-    template<typename u16_type>
-    inline uint16_t mask16(u16_type oc)
-    {
-        return static_cast<uint16_t>(0xffff & oc);
-    }
-    template<typename octet_type>
-    inline bool is_trail(octet_type oc)
-    {
-        return ((utf8::internal::mask8(oc) >> 6) == 0x2);
-    }
-
-    template <typename u16>
-    inline bool is_lead_surrogate(u16 cp)
-    {
-        return (cp >= LEAD_SURROGATE_MIN && cp <= LEAD_SURROGATE_MAX);
-    }
-
-    template <typename u16>
-    inline bool is_trail_surrogate(u16 cp)
-    {
-        return (cp >= TRAIL_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX);
-    }
-
-    template <typename u16>
-    inline bool is_surrogate(u16 cp)
-    {
-        return (cp >= LEAD_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX);
-    }
-
-    template <typename u32>
-    inline bool is_code_point_valid(u32 cp)
-    {
-        return (cp <= CODE_POINT_MAX && !utf8::internal::is_surrogate(cp));
-    }
-
-    template <typename octet_iterator>
-    inline typename std::iterator_traits<octet_iterator>::difference_type
-    sequence_length(octet_iterator lead_it)
-    {
-        uint8_t lead = utf8::internal::mask8(*lead_it);
-        if (lead < 0x80)
-            return 1;
-        else if ((lead >> 5) == 0x6)
-            return 2;
-        else if ((lead >> 4) == 0xe)
-            return 3;
-        else if ((lead >> 3) == 0x1e)
-            return 4;
-        else
-            return 0;
-    }
-
-    template <typename octet_difference_type>
-    inline bool is_overlong_sequence(uint32_t cp, octet_difference_type length)
-    {
-        if (cp < 0x80) {
-            if (length != 1) 
-                return true;
-        }
-        else if (cp < 0x800) {
-            if (length != 2) 
-                return true;
-        }
-        else if (cp < 0x10000) {
-            if (length != 3) 
-                return true;
-        }
-
-        return false;
-    }
-
-    enum utf_error {UTF8_OK, NOT_ENOUGH_ROOM, INVALID_LEAD, INCOMPLETE_SEQUENCE, OVERLONG_SEQUENCE, INVALID_CODE_POINT};
-
-    /// Helper for get_sequence_x
-    template <typename octet_iterator>
-    utf_error increase_safely(octet_iterator& it, octet_iterator end)
-    {
-        if (++it == end)
-            return NOT_ENOUGH_ROOM;
-
-        if (!utf8::internal::is_trail(*it))
-            return INCOMPLETE_SEQUENCE;
-        
-        return UTF8_OK;
-    }
-
-    #define UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(IT, END) {utf_error ret = increase_safely(IT, END); if (ret != UTF8_OK) return ret;}    
-
-    /// get_sequence_x functions decode utf-8 sequences of the length x
-    template <typename octet_iterator>
-    utf_error get_sequence_1(octet_iterator& it, octet_iterator end, uint32_t& code_point)
-    {
-        if (it == end)
-            return NOT_ENOUGH_ROOM;
-
-        code_point = utf8::internal::mask8(*it);
-
-        return UTF8_OK;
-    }
-
-    template <typename octet_iterator>
-    utf_error get_sequence_2(octet_iterator& it, octet_iterator end, uint32_t& code_point)
-    {
-        if (it == end) 
-            return NOT_ENOUGH_ROOM;
-        
-        code_point = utf8::internal::mask8(*it);
-
-        UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
-
-        code_point = ((code_point << 6) & 0x7ff) + ((*it) & 0x3f);
-
-        return UTF8_OK;
-    }
-
-    template <typename octet_iterator>
-    utf_error get_sequence_3(octet_iterator& it, octet_iterator end, uint32_t& code_point)
-    {
-        if (it == end)
-            return NOT_ENOUGH_ROOM;
-            
-        code_point = utf8::internal::mask8(*it);
-
-        UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
-
-        code_point = ((code_point << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff);
-
-        UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
-
-        code_point += (*it) & 0x3f;
-
-        return UTF8_OK;
-    }
-
-    template <typename octet_iterator>
-    utf_error get_sequence_4(octet_iterator& it, octet_iterator end, uint32_t& code_point)
-    {
-        if (it == end)
-           return NOT_ENOUGH_ROOM;
-
-        code_point = utf8::internal::mask8(*it);
-
-        UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
-
-        code_point = ((code_point << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff);
-
-        UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
-
-        code_point += (utf8::internal::mask8(*it) << 6) & 0xfff;
-
-        UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
-
-        code_point += (*it) & 0x3f;
-
-        return UTF8_OK;
-    }
-
-    #undef UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR
-
-    template <typename octet_iterator>
-    utf_error validate_next(octet_iterator& it, octet_iterator end, uint32_t& code_point)
-    {
-        // Save the original value of it so we can go back in case of failure
-        // Of course, it does not make much sense with i.e. stream iterators
-        octet_iterator original_it = it;
-
-        uint32_t cp = 0;
-        // Determine the sequence length based on the lead octet
-        typedef typename std::iterator_traits<octet_iterator>::difference_type octet_difference_type;
-        const octet_difference_type length = utf8::internal::sequence_length(it);
-
-        // Get trail octets and calculate the code point
-        utf_error err = UTF8_OK;
-        switch (length) {
-            case 0: 
-                return INVALID_LEAD;
-            case 1:
-                err = utf8::internal::get_sequence_1(it, end, cp);
-                break;
-            case 2:
-                err = utf8::internal::get_sequence_2(it, end, cp);
-            break;
-            case 3:
-                err = utf8::internal::get_sequence_3(it, end, cp);
-            break;
-            case 4:
-                err = utf8::internal::get_sequence_4(it, end, cp);
-            break;
-        }
-
-        if (err == UTF8_OK) {
-            // Decoding succeeded. Now, security checks...
-            if (utf8::internal::is_code_point_valid(cp)) {
-                if (!utf8::internal::is_overlong_sequence(cp, length)){
-                    // Passed! Return here.
-                    code_point = cp;
-                    ++it;
-                    return UTF8_OK;
-                }
-                else
-                    err = OVERLONG_SEQUENCE;
-            }
-            else 
-                err = INVALID_CODE_POINT;
-        }
-
-        // Failure branch - restore the original value of the iterator
-        it = original_it;
-        return err;
-    }
-
-    template <typename octet_iterator>
-    inline utf_error validate_next(octet_iterator& it, octet_iterator end) {
-        uint32_t ignored;
-        return utf8::internal::validate_next(it, end, ignored);
-    }
-
-} // namespace internal
-
-    /// The library API - functions intended to be called by the users
-
-    // Byte order mark
-    const uint8_t bom[] = {0xef, 0xbb, 0xbf};
-
-    template <typename octet_iterator>
-    octet_iterator find_invalid(octet_iterator start, octet_iterator end)
-    {
-        octet_iterator result = start;
-        while (result != end) {
-            utf8::internal::utf_error err_code = utf8::internal::validate_next(result, end);
-            if (err_code != internal::UTF8_OK)
-                return result;
-        }
-        return result;
-    }
-
-    template <typename octet_iterator>
-    inline bool is_valid(octet_iterator start, octet_iterator end)
-    {
-        return (utf8::find_invalid(start, end) == end);
-    }
-
-    template <typename octet_iterator>
-    inline bool starts_with_bom (octet_iterator it, octet_iterator end)
-    {
-        return (
-            ((it != end) && (utf8::internal::mask8(*it++)) == bom[0]) &&
-            ((it != end) && (utf8::internal::mask8(*it++)) == bom[1]) &&
-            ((it != end) && (utf8::internal::mask8(*it))   == bom[2])
-           );
-    }
-	
-    //Deprecated in release 2.3 
-    template <typename octet_iterator>
-    inline bool is_bom (octet_iterator it)
-    {
-        return (
-            (utf8::internal::mask8(*it++)) == bom[0] &&
-            (utf8::internal::mask8(*it++)) == bom[1] &&
-            (utf8::internal::mask8(*it))   == bom[2]
-           );
-    }
-} // namespace utf8
-
-#endif // header guard
-
-
diff --git a/libsass/utf8/unchecked.h b/libsass/utf8/unchecked.h
deleted file mode 100644
--- a/libsass/utf8/unchecked.h
+++ /dev/null
@@ -1,228 +0,0 @@
-// Copyright 2006 Nemanja Trifunovic
-
-/*
-Permission is hereby granted, free of charge, to any person or organization
-obtaining a copy of the software and accompanying documentation covered by
-this license (the "Software") to use, reproduce, display, distribute,
-execute, and transmit the Software, and to prepare derivative works of the
-Software, and to permit third-parties to whom the Software is furnished to
-do so, all subject to the following:
-
-The copyright notices in the Software and this entire statement, including
-the above license grant, this restriction and the following disclaimer,
-must be included in all copies of the Software, in whole or in part, and
-all derivative works of the Software, unless such copies or derivative
-works are solely in the form of machine-executable object code generated by
-a source language processor.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
-SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
-FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
-ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-DEALINGS IN THE SOFTWARE.
-*/
-
-
-#ifndef UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
-#define UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
-
-#include "core.h"
-
-namespace utf8
-{
-    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);  
-            else if (cp < 0x800) {                // two octets
-                *(result++) = static_cast<uint8_t>((cp >> 6)          | 0xc0);
-                *(result++) = static_cast<uint8_t>((cp & 0x3f)        | 0x80);
-            }
-            else if (cp < 0x10000) {              // three octets
-                *(result++) = static_cast<uint8_t>((cp >> 12)         | 0xe0);
-                *(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
-                *(result++) = static_cast<uint8_t>((cp & 0x3f)        | 0x80);
-            }
-            else {                                // four octets
-                *(result++) = static_cast<uint8_t>((cp >> 18)         | 0xf0);
-                *(result++) = static_cast<uint8_t>(((cp >> 12) & 0x3f)| 0x80);
-                *(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
-                *(result++) = static_cast<uint8_t>((cp & 0x3f)        | 0x80);
-            }
-            return result;
-        }
-
-        template <typename octet_iterator>
-        uint32_t next(octet_iterator& it)
-        {
-            uint32_t cp = utf8::internal::mask8(*it);
-            typename std::iterator_traits<octet_iterator>::difference_type length = utf8::internal::sequence_length(it);
-            switch (length) {
-                case 1:
-                    break;
-                case 2:
-                    it++;
-                    cp = ((cp << 6) & 0x7ff) + ((*it) & 0x3f);
-                    break;
-                case 3:
-                    ++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);                
-                    ++it;
-                    cp += (utf8::internal::mask8(*it) << 6) & 0xfff;
-                    ++it;
-                    cp += (*it) & 0x3f; 
-                    break;
-            }
-            ++it;
-            return cp;        
-        }
-
-        template <typename octet_iterator>
-        uint32_t peek_next(octet_iterator it)
-        {
-            return utf8::unchecked::next(it);    
-        }
-
-        template <typename octet_iterator>
-        uint32_t prior(octet_iterator& it)
-        {
-            while (utf8::internal::is_trail(*(--it))) ;
-            octet_iterator temp = it;
-            return utf8::unchecked::next(temp);
-        }
-
-        // Deprecated in versions that include prior, but only for the sake of consistency (see utf8::previous)
-        template <typename octet_iterator>
-        inline uint32_t previous(octet_iterator& it)
-        {
-            return utf8::unchecked::prior(it);
-        }
-
-        template <typename octet_iterator, typename distance_type>
-        void advance (octet_iterator& it, distance_type n)
-        {
-            for (distance_type i = 0; i < n; ++i)
-                utf8::unchecked::next(it);
-        }
-
-        template <typename octet_iterator>
-        typename std::iterator_traits<octet_iterator>::difference_type
-        distance (octet_iterator first, octet_iterator last)
-        {
-            typename std::iterator_traits<octet_iterator>::difference_type 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
-                if (utf8::internal::is_lead_surrogate(cp)) {
-                    uint32_t trail_surrogate = utf8::internal::mask16(*start++);
-                    cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET;
-                }
-                result = utf8::unchecked::append(cp, result);
-            }
-            return result;         
-        }
-
-        template <typename u16bit_iterator, typename octet_iterator>
-        u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result)
-        {
-            while (start < end) {
-                uint32_t cp = utf8::unchecked::next(start);
-                if (cp > 0xffff) { //make a surrogate pair
-                    *result++ = static_cast<uint16_t>((cp >> 10)   + internal::LEAD_OFFSET);
-                    *result++ = static_cast<uint16_t>((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN);
-                }
-                else
-                    *result++ = static_cast<uint16_t>(cp);
-            }
-            return result;
-        }
-
-        template <typename octet_iterator, typename u32bit_iterator>
-        octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result)
-        {
-            while (start != end)
-                result = utf8::unchecked::append(*(start++), result);
-
-            return result;
-        }
-
-        template <typename octet_iterator, typename u32bit_iterator>
-        u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result)
-        {
-            while (start < end)
-                (*result++) = utf8::unchecked::next(start);
-
-            return result;
-        }
-
-        // The iterator class
-        template <typename octet_iterator>
-          class iterator : public std::iterator <std::bidirectional_iterator_tag, uint32_t> { 
-            octet_iterator it;
-            public:
-            iterator () {}
-            explicit iterator (const octet_iterator& octet_it): it(octet_it) {}
-            // the default "big three" are OK
-            octet_iterator base () const { return it; }
-            uint32_t operator * () const
-            {
-                octet_iterator temp = it;
-                return utf8::unchecked::next(temp);
-            }
-            bool operator == (const iterator& rhs) const 
-            { 
-                return (it == rhs.it);
-            }
-            bool operator != (const iterator& rhs) const
-            {
-                return !(operator == (rhs));
-            }
-            iterator& operator ++ () 
-            {
-                ::std::advance(it, utf8::internal::sequence_length(it));
-                return *this;
-            }
-            iterator operator ++ (int)
-            {
-                iterator temp = *this;
-                ::std::advance(it, utf8::internal::sequence_length(it));
-                return temp;
-            }  
-            iterator& operator -- ()
-            {
-                utf8::unchecked::prior(it);
-                return *this;
-            }
-            iterator operator -- (int)
-            {
-                iterator temp = *this;
-                utf8::unchecked::prior(it);
-                return temp;
-            }
-          }; // class iterator
-
-    } // namespace utf8::unchecked
-} // namespace utf8 
-
-
-#endif // header guard
-
diff --git a/libsass/utf8_string.cpp b/libsass/utf8_string.cpp
deleted file mode 100644
--- a/libsass/utf8_string.cpp
+++ /dev/null
@@ -1,97 +0,0 @@
-#include <string>
-#include <vector>
-#include <cstdlib>
-#include <cmath>
-
-#include "utf8.h"
-
-namespace Sass {
-  namespace UTF_8 {
-    using std::string;
-
-    // naming conventions:
-    // offset: raw byte offset (0 based)
-    // position: code point offset (0 based)
-    // index: code point offset (1 based or negative)
-
-    // function that will count the number of code points (utf-8 characters) from the given beginning to the given end
-    size_t code_point_count(const string& str, size_t start, size_t end) {
-      return utf8::distance(str.begin() + start, str.begin() + end);
-    }
-
-    size_t code_point_count(const string& str) {
-      return utf8::distance(str.begin(), str.end());
-    }
-
-    // function that will return the byte offset at a code point position
-    size_t offset_at_position(const string& str, size_t position) {
-      string::const_iterator it = str.begin();
-      utf8::advance(it, position, str.end());
-      return distance(str.begin(), it);
-    }
-
-    // function that returns number of bytes in a character at offset
-    size_t code_point_size_at_offset(const string& str, size_t offset) {
-      // get iterator from string and forward by offset
-      string::const_iterator stop = str.begin() + offset;
-      // check if beyond boundary
-      if (stop == str.end()) return 0;
-      // advance by one code point
-      utf8::advance(stop, 1, str.end());
-      // calculate offset for code point
-      return  stop - str.begin() - offset;
-    }
-
-    // function that will return a normalized index, given a crazy one
-    size_t normalize_index(int index, size_t len) {
-      long signed_len = static_cast<long>(len);
-      // assuming the index is 1-based
-      // we are returning a 0-based index
-      if (index > 0 && index <= signed_len) {
-        // positive and within string length
-        return index-1;
-      }
-      else if (index > signed_len) {
-        // positive and past string length
-        return len;
-      }
-      else if (index == 0) {
-        return 0;
-      }
-      else if (std::abs((double)index) <= signed_len) {
-        // negative and within string length
-        return index + signed_len;
-      }
-      else {
-        // negative and past string length
-        return 0;
-      }
-    }
-
-    // utf16 functions
-    using std::wstring;
-
-    // convert from utf16/wide string to utf8 string
-    string convert_from_utf16(const wstring& utf16)
-    {
-      string utf8;
-      // pre-allocate expected memory
-      utf8.reserve(sizeof(utf16)/2);
-      utf8::utf16to8(utf16.begin(), utf16.end(),
-                     back_inserter(utf8));
-      return utf8;
-    }
-
-    // convert from utf8 string to utf16/wide string
-    wstring convert_to_utf16(const string& utf8)
-    {
-      wstring utf16;
-      // pre-allocate expected memory
-      utf16.reserve(code_point_count(utf8)*2);
-      utf8::utf8to16(utf8.begin(), utf8.end(),
-                     back_inserter(utf16));
-      return utf16;
-    }
-
-  }
-}
diff --git a/libsass/utf8_string.hpp b/libsass/utf8_string.hpp
deleted file mode 100644
--- a/libsass/utf8_string.hpp
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef SASS_UTF8_STRING_H
-#define SASS_UTF8_STRING_H
-
-#include <string>
-#include "utf8.h"
-
-namespace Sass {
-  namespace UTF_8 {
-
-    // naming conventions:
-    // offset: raw byte offset (0 based)
-    // position: code point offset (0 based)
-    // index: code point offset (1 based or negative)
-
-    // function that will count the number of code points (utf-8 characters) from the beginning to the given end
-    size_t code_point_count(const string& str, size_t start, size_t end);
-    size_t code_point_count(const string& str);
-
-    // function that will return the byte offset of a code point in a
-    size_t offset_at_position(const string& str, size_t position);
-
-    // function that returns number of bytes in a character in a string
-    size_t code_point_size_at_offset(const string& str, size_t offset);
-
-    // function that will return a normalized index, given a crazy one
-    size_t normalize_index(int index, size_t len);
-
-    #ifdef _WIN32
-    // functions to handle unicode paths on windows
-    string convert_from_utf16(const wstring& wstr);
-    wstring convert_to_utf16(const string& str);
-    #endif
-
-  }
-}
-
-#endif
diff --git a/libsass/util.cpp b/libsass/util.cpp
deleted file mode 100644
--- a/libsass/util.cpp
+++ /dev/null
@@ -1,704 +0,0 @@
-#include<stdint.h>
-#include "ast.hpp"
-#include "util.hpp"
-#include "prelexer.hpp"
-#include "utf8/checked.h"
-
-namespace Sass {
-
-  #define out_of_memory() do {                    \
-      fprintf(stderr, "Out of memory.\n");    \
-      exit(EXIT_FAILURE);                     \
-    } while (0)
-
-  /* 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)
-  {
-    char separator = *(localeconv()->decimal_point);
-    if(separator != '.'){
-      // The current locale specifies another
-      // separator. convert the separator to the
-      // one understood by the locale if needed
-      const char *found = strchr(str, '.');
-      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);
-        *(copy + (found - str)) = separator;
-        double res = atof(copy);
-        free(copy);
-        return res;
-      }
-    }
-
-    return atof(str);
-  }
-
-  string string_eval_escapes(const string& s)
-  {
-
-    string out("");
-    bool esc = false;
-    for (size_t i = 0, L = s.length(); i < L; ++i) {
-      if(s[i] == '\\' && esc == false) {
-        esc = true;
-
-        // escape length
-        size_t len = 1;
-
-        // parse as many sequence chars as possible
-        // ToDo: Check if ruby aborts after possible max
-        while (i + len < L && s[i + len] && isxdigit(s[i + len])) ++ len;
-
-        // hex string?
-        if (len > 1) {
-
-          // convert the extracted hex string to code point value
-          // ToDo: Maybe we could do this without creating a substring
-          uint32_t cp = strtol(s.substr (i + 1, len - 1).c_str(), nullptr, 16);
-
-          if (cp == 0) cp = 0xFFFD;
-
-          // assert invalid code points
-          if (cp >= 1) {
-
-            // use a very simple approach to convert via utf8 lib
-            // maybe there is a more elegant way; maybe we shoud
-            // convert the whole output from string to a stream!?
-            // allocate memory for utf8 char and convert to utf8
-            unsigned char u[5] = {0,0,0,0,0}; utf8::append(cp, u);
-            for(size_t m = 0; u[m] && m < 5; m++) out.push_back(u[m]);
-
-            // skip some more chars?
-            i += len - 1; esc = false;
-            if (cp == 10) out += ' ';
-
-          }
-
-        }
-
-      }
-      else {
-        out += s[i];
-        esc = false;
-      }
-    }
-    return out;
-
-  }
-
-  // double escape every escape sequences
-  // escape unescaped quotes and backslashes
-  string string_escape(const string& str)
-  {
-    string out("");
-    for (auto i : str) {
-      // escape some characters
-      if (i == '"') out += '\\';
-      if (i == '\'') out += '\\';
-      if (i == '\\') out += '\\';
-      out += i;
-    }
-    return out;
-  }
-
-  // unescape every escape sequence
-  // only removes unescaped backslashes
-  string string_unescape(const string& str)
-  {
-    string out("");
-    bool esc = false;
-    for (auto i : str) {
-      if (esc || i != '\\') {
-        esc = false;
-        out += i;
-      } else {
-        esc = true;
-      }
-    }
-    // open escape sequence at end
-    // maybe it should thow an error
-    if (esc) { out += '\\'; }
-    return out;
-  }
-
-  // read css string (handle multiline DELIM)
-  string read_css_string(const string& str)
-  {
-    string out("");
-    bool esc = false;
-    for (auto i : str) {
-      if (i == '\\') {
-        esc = ! esc;
-      } else if (esc && i == '\r') {
-        continue;
-      } else if (esc && i == '\n') {
-        out.resize (out.size () - 1);
-        esc = false;
-        continue;
-      } else {
-        esc = false;
-      }
-      out.push_back(i);
-    }
-    if (esc) out += '\\';
-    return out;
-  }
-
-  // evacuate unescaped quoted
-  // leave everything else untouched
-  string evacuate_quotes(const string& str)
-  {
-    string out("");
-    bool esc = false;
-    for (auto i : str) {
-      if (!esc) {
-        // ignore next character
-        if (i == '\\') esc = true;
-        // evacuate unescaped quotes
-        else if (i == '"') out += '\\';
-        else if (i == '\'') out += '\\';
-      }
-      // get escaped char now
-      else { esc = false; }
-      // remove nothing
-      out += i;
-    }
-    return out;
-  }
-
-  // double escape all escape sequences
-  // keep unescaped quotes and backslashes
-  string evacuate_escapes(const string& str)
-  {
-    string out("");
-    bool esc = false;
-    for (auto i : str) {
-      if (i == '\\' && !esc) {
-        out += '\\';
-        out += '\\';
-        esc = true;
-      } else if (esc && i == '"') {
-        out += '\\';
-        out += i;
-        esc = false;
-      } else if (esc && i == '\'') {
-        out += '\\';
-        out += i;
-        esc = false;
-      } else if (esc && i == '\\') {
-        out += '\\';
-        out += i;
-        esc = false;
-      } else {
-        esc = false;
-        out += i;
-      }
-    }
-    // happens when parsing does not correctly skip
-    // over escaped sequences for ie. interpolations
-    // one example: foo\#{interpolate}
-    // if (esc) out += '\\';
-    return out;
-  }
-
-  // bell character is replaces with space
-  string string_to_output(const string& str)
-  {
-    string out("");
-    for (auto i : str) {
-      if (i == 10) {
-        out += ' ';
-      } else {
-        out += i;
-      }
-    }
-    return out;
-  }
-
-  string comment_to_string(const string& text)
-  {
-    string str = "";
-    size_t has = 0;
-    char prev = 0;
-    bool clean = false;
-    for (auto i : text) {
-      if (clean) {
-        if (i == '\n') { has = 0; }
-        else if (i == '\r') { has = 0; }
-        else if (i == '\t') { ++ has; }
-        else if (i == ' ') { ++ has; }
-        else if (i == '*') {}
-        else {
-          clean = false;
-          str += ' ';
-          if (prev == '*' && i == '/') str += "*/";
-          else str += i;
-        }
-      } else if (i == '\n') {
-        clean = true;
-      } else if (i == '\r') {
-        clean = true;
-      } else {
-        str += i;
-      }
-      prev = i;
-    }
-    if (has) return str;
-    else return text;
-  }
-
-   string normalize_wspace(const string& str)
-  {
-    bool ws = false;
-    bool esc = false;
-    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
-  // quotes, which will trigger the use of single quotes as best quote_mark.
-  char detect_best_quotemark(const char* s, char qm)
-  {
-    // ensure valid fallback quote_mark
-    char quote_mark = qm && qm != '*' ? qm : '"';
-    while (*s) {
-      // force double quotes as soon
-      // as one single quote is found
-      if (*s == '\'') { return '"'; }
-      // a single does not force quote_mark
-      // maybe we see a double quote later
-      else if (*s == '"') { quote_mark = '\''; }
-      ++ s;
-    }
-    return quote_mark;
-  }
-
-  string unquote(const string& s, char* qd)
-  {
-
-    // not enough room for quotes
-    // no possibility to unquote
-    if (s.length() < 2) return s;
-
-    char q;
-    bool skipped = false;
-
-    // this is no guarantee that the unquoting will work
-    // what about whitespace before/after the quote_mark?
-    if      (*s.begin() == '"'  && *s.rbegin() == '"')  q = '"';
-    else if (*s.begin() == '\'' && *s.rbegin() == '\'') q = '\'';
-    else                                                return s;
-
-    string unq;
-    unq.reserve(s.length()-2);
-
-    for (size_t i = 1, L = s.length() - 1; i < L; ++i) {
-
-      // implement the same strange ruby sass behavior
-      // an escape sequence can also mean a unicode char
-      if (s[i] == '\\' && !skipped) {
-        // remember
-        skipped = true;
-
-        // skip it
-        // ++ i;
-
-        // if (i == L) break;
-
-        // escape length
-        size_t len = 1;
-
-        // parse as many sequence chars as possible
-        // ToDo: Check if ruby aborts after possible max
-        while (i + len < L && s[i + len] && isxdigit(s[i + len])) ++ len;
-
-        // hex string?
-        if (len > 1) {
-
-          // convert the extracted hex string to code point value
-          // ToDo: Maybe we could do this without creating a substring
-          uint32_t cp = strtol(s.substr (i + 1, len - 1).c_str(), nullptr, 16);
-
-          // assert invalid code points
-          if (cp == 0) cp = 0xFFFD;
-          // replace bell character
-          // if (cp == 10) cp = 32;
-
-          // use a very simple approach to convert via utf8 lib
-          // maybe there is a more elegant way; maybe we shoud
-          // convert the whole output from string to a stream!?
-          // allocate memory for utf8 char and convert to utf8
-          unsigned char u[5] = {0,0,0,0,0}; utf8::append(cp, u);
-          for(size_t m = 0; u[m] && m < 5; m++) unq.push_back(u[m]);
-
-          // skip some more chars?
-          i += len - 1; skipped = false;
-
-        }
-
-
-      }
-      // check for unexpected delimiter
-      // be strict and throw error back
-      // else if (!skipped && q == s[i]) {
-      //   // don't be that strict
-      //   return s;
-      //   // this basically always means an internal error and not users fault
-      //   error("Unescaped delimiter in string to unquote found. [" + s + "]", ParserState("[UNQUOTE]"));
-      // }
-      else {
-        skipped = false;
-        unq.push_back(s[i]);
-      }
-
-    }
-    if (skipped) { return s; }
-    if (qd) *qd = q;
-    return unq;
-
-  }
-
-  string quote(const string& s, char q, bool keep_linefeed_whitespace)
-  {
-
-    // autodetect with fallback to given quote
-    q = detect_best_quotemark(s.c_str(), q);
-
-    // return an empty quoted string
-    if (s.empty()) return string(2, q ? q : '"');
-
-    string quoted;
-    quoted.reserve(s.length()+2);
-    quoted.push_back(q);
-
-    const char* it = s.c_str();
-    const char* end = it + strlen(it) + 1;
-    while (*it && it < end) {
-      const char* now = it;
-
-      if (*it == q) {
-        quoted.push_back('\\');
-      } else if (*it == '\\') {
-        quoted.push_back('\\');
-      }
-
-      int cp = utf8::next(it, end);
-
-      if (cp == 10) {
-        quoted.push_back('\\');
-        quoted.push_back('a');
-        // we hope we can remove this flag once we figure out
-        // why ruby sass has these different output behaviors
-        if (keep_linefeed_whitespace)
-          quoted.push_back(' ');
-      } else if (cp < 127) {
-        quoted.push_back((char) cp);
-      } else {
-        while (now < it) {
-          quoted.push_back(*now);
-          ++ now;
-        }
-      }
-    }
-
-    quoted.push_back(q);
-    return quoted;
-  }
-
-  bool is_hex_doublet(double n)
-  {
-    return n == 0x00 || n == 0x11 || n == 0x22 || n == 0x33 ||
-           n == 0x44 || n == 0x55 || n == 0x66 || n == 0x77 ||
-           n == 0x88 || n == 0x99 || n == 0xAA || n == 0xBB ||
-           n == 0xCC || n == 0xDD || n == 0xEE || n == 0xFF ;
-  }
-
-  bool is_color_doublet(double r, double g, double b)
-  {
-    return is_hex_doublet(r) && is_hex_doublet(g) && is_hex_doublet(b);
-  }
-
-  bool peek_linefeed(const char* start)
-  {
-    while (*start) {
-      if (*start == '\n' || *start == '\r') return true;
-      if (*start != ' ' && *start != '\t') return false;
-      ++ start;
-    }
-    return false;
-  }
-
-  namespace Util {
-    using std::string;
-
-    string normalize_underscores(const string& str) {
-      string normalized = str;
-      for(size_t i = 0, L = normalized.length(); i < L; ++i) {
-        if(normalized[i] == '_') {
-          normalized[i] = '-';
-        }
-      }
-      return normalized;
-    }
-
-    string normalize_decimals(const string& str) {
-      string prefix = "0";
-      string normalized = str;
-
-      return normalized[0] == '.' ? normalized.insert(0, prefix) : normalized;
-    }
-
-    // compress a color sixtuplet if possible
-    // input: "#CC9900" -> output: "#C90"
-    string normalize_sixtuplet(const 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 string("#" + col.substr(1, 1)
-                          + col.substr(3, 1)
-                          + col.substr(5, 1));
-      } else {
-        return string(col);
-      }
-    }
-
-    bool isPrintable(Ruleset* r, Output_Style style) {
-      if (r == NULL) {
-        return false;
-      }
-
-      Block* b = r->block();
-
-      bool hasSelectors = static_cast<Selector_List*>(r->selector())->length() > 0;
-
-      if (!hasSelectors) {
-        return false;
-      }
-
-      bool hasDeclarations = false;
-      bool hasPrintableChildBlocks = false;
-      for (size_t i = 0, L = b->length(); i < L; ++i) {
-        Statement* stm = (*b)[i];
-        if (dynamic_cast<Has_Block*>(stm)) {
-          Block* pChildBlock = ((Has_Block*)stm)->block();
-          if (isPrintable(pChildBlock, style)) {
-            hasPrintableChildBlocks = true;
-          }
-        } else if (Comment* c = dynamic_cast<Comment*>(stm)) {
-          if (style == COMPRESSED) {
-            hasDeclarations = c->is_important();
-          } else {
-            hasDeclarations = true;
-          }
-        } else if (Declaration* d = dynamic_cast<Declaration*>(stm)) {
-          return isPrintable(d, style);
-        } else {
-          hasDeclarations = true;
-        }
-
-        if (hasDeclarations || hasPrintableChildBlocks) {
-          return true;
-        }
-      }
-
-      return false;
-    }
-
-    bool isPrintable(String_Constant* s, Output_Style style)
-    {
-      return ! s->value().empty();
-    }
-
-    bool isPrintable(String_Quoted* s, Output_Style style)
-    {
-      return true;
-    }
-
-    bool isPrintable(Declaration* d, Output_Style style)
-    {
-      Expression* val = d->value();
-      if (String_Quoted* sq = dynamic_cast<String_Quoted*>(val)) return isPrintable(sq, style);
-      if (String_Constant* sc = dynamic_cast<String_Constant*>(val)) return isPrintable(sc, style);
-      return true;
-    }
-
-    bool isPrintable(Expression* e, Output_Style style) {
-      return isPrintable(e, style);
-    }
-
-    bool isPrintable(Feature_Block* f, Output_Style style) {
-      if (f == NULL) {
-        return false;
-      }
-
-      Block* b = f->block();
-
-      bool hasSelectors = f->selector() && static_cast<Selector_List*>(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() && f->selector() != NULL && !hasSelectors) {
-          // 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)) {
-          hasDeclarations = true;
-        }
-        else if (dynamic_cast<Has_Block*>(stm)) {
-          Block* pChildBlock = ((Has_Block*)stm)->block();
-          if (isPrintable(pChildBlock, style)) {
-            hasPrintableChildBlocks = true;
-          }
-        }
-
-        if (hasDeclarations || hasPrintableChildBlocks) {
-          return true;
-        }
-      }
-
-      return false;
-    }
-
-    bool isPrintable(Media_Block* m, Output_Style style) {
-      if (m == NULL) {
-        return false;
-      }
-
-      Block* b = m->block();
-
-      bool hasSelectors = m->selector() && static_cast<Selector_List*>(m->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() && m->selector() != NULL && !hasSelectors) {
-          // 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)) {
-          hasDeclarations = true;
-        }
-        else if (dynamic_cast<Has_Block*>(stm)) {
-          Block* pChildBlock = ((Has_Block*)stm)->block();
-          if (isPrintable(pChildBlock, style)) {
-            hasPrintableChildBlocks = true;
-          }
-        }
-
-        if (hasDeclarations || hasPrintableChildBlocks) {
-          return true;
-        }
-      }
-
-      return false;
-    }
-
-    bool isPrintable(Block* b, Output_Style style) {
-      if (b == NULL) {
-        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)) {
-          return true;
-        }
-        else if (typeid(*stm) == typeid(Comment)) {
-
-        }
-        else if (typeid(*stm) == typeid(Ruleset)) {
-          Ruleset* r = (Ruleset*) stm;
-          if (isPrintable(r, style)) {
-            return true;
-          }
-        }
-        else if (typeid(*stm) == typeid(Feature_Block)) {
-          Feature_Block* f = (Feature_Block*) stm;
-          if (isPrintable(f, style)) {
-            return true;
-          }
-        }
-        else if (typeid(*stm) == typeid(Media_Block)) {
-          Media_Block* m = (Media_Block*) stm;
-          if (isPrintable(m, style)) {
-            return true;
-          }
-        }
-        else if (dynamic_cast<Has_Block*>(stm) && isPrintable(((Has_Block*)stm)->block(), style)) {
-          return true;
-        }
-      }
-
-      return false;
-    }
-
-    string vecJoin(const vector<string>& vec, const string& sep)
-    {
-      switch (vec.size())
-      {
-        case 0:
-            return 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;
-     }
-
-  }
-}
diff --git a/libsass/util.hpp b/libsass/util.hpp
deleted file mode 100644
--- a/libsass/util.hpp
+++ /dev/null
@@ -1,54 +0,0 @@
-#ifndef SASS_UTIL_H
-#define SASS_UTIL_H
-
-#include <cstdio>
-#include <vector>
-#include <string>
-#include "ast_fwd_decl.hpp"
-
-namespace Sass {
-  using namespace std;
-
-  char* sass_strdup(const char* str);
-  double sass_atof(const char* str);
-  string string_escape(const string& str);
-  string string_unescape(const string& str);
-  string string_eval_escapes(const string& str);
-  string read_css_string(const string& str);
-  string evacuate_quotes(const string& str);
-  string evacuate_escapes(const string& str);
-  string string_to_output(const string& str);
-  string comment_to_string(const string& text);
-  string normalize_wspace(const string& str);
-
-  string quote(const string&, char q = 0, bool keep_linefeed_whitespace = false);
-  string unquote(const string&, char* q = 0);
-  char detect_best_quotemark(const char* s, char qm = '"');
-
-  bool is_hex_doublet(double n);
-  bool is_color_doublet(double r, double g, double b);
-
-  bool peek_linefeed(const char* start);
-
-  namespace Util {
-
-    string normalize_underscores(const string& str);
-    string normalize_decimals(const string& str);
-    string normalize_sixtuplet(const string& col);
-
-    string vecJoin(const vector<string>& vec, const string& sep);
-    bool containsAnyPrintableStatements(Block* b);
-
-    bool isPrintable(Ruleset* r, Output_Style style = NESTED);
-    bool isPrintable(Feature_Block* r, Output_Style style = NESTED);
-    bool isPrintable(Media_Block* r, Output_Style style = NESTED);
-    bool isPrintable(Block* b, Output_Style style = NESTED);
-    bool isPrintable(String_Constant* s, Output_Style style = NESTED);
-    bool isPrintable(String_Quoted* s, Output_Style style = NESTED);
-    bool isPrintable(Declaration* d, Output_Style style = NESTED);
-    bool isPrintable(Expression* e, Output_Style style = NESTED);
-    bool isAscii(const char chr);
-
-  }
-}
-#endif
diff --git a/tests/Main.hs b/tests/Main.hs
--- a/tests/Main.hs
+++ b/tests/Main.hs
@@ -35,9 +35,19 @@
 #ifndef EXTERNAL_LIBSASS
     it "should report correct version" $ do
         str <- peekCString libsass_version
-        str `shouldBe` "3.2.4-18-g3672"
+        str `shouldBe` "3.3.2"
 #endif
 
     it "should support quoted strings" $ withCString "sample" $ \cstr -> do
         str <- sass_make_qstring cstr
         sass_string_is_quoted str `shouldReturn` True
+
+    it "should correctly combine two SassValues" $ withCString "" $ \unit -> do
+        val1 <- sass_make_number 1.0 unit
+        val2 <- sass_make_number 2.0 unit
+        val3 <- sass_value_op (fromIntegral $ fromEnum SassAdd) val1 val2
+        result <- sass_number_get_value val3
+        sass_delete_value val1
+        sass_delete_value val2
+        sass_delete_value val3
+        result `shouldBe` 3.0
