diff --git a/Binding/Libsass.hs b/Binding/Libsass.hs
new file mode 100644
--- /dev/null
+++ b/Binding/Libsass.hs
@@ -0,0 +1,19 @@
+-- |
+-- This is the main module of the library - it reexports rest of the library, so
+-- you should only import this one.
+
+{-# LANGUAGE ForeignFunctionInterface #-}
+module Binding.Libsass
+  (
+    libsass_version
+  , module Libsass
+  ) where
+
+import           Binding.Libsass.Context   as Libsass
+import           Binding.Libsass.Functions as Libsass
+import           Binding.Libsass.Types     as Libsass
+import           Binding.Libsass.Wrappers  as Libsass
+import           Binding.Libsass.Values    as Libsass
+import           Foreign.C.String
+
+foreign import ccall unsafe "sass.h" libsass_version :: CString
diff --git a/Binding/Libsass/Context.hs b/Binding/Libsass/Context.hs
new file mode 100644
--- /dev/null
+++ b/Binding/Libsass/Context.hs
@@ -0,0 +1,358 @@
+{-# LANGUAGE ForeignFunctionInterface #-}
+module Binding.Libsass.Context where
+
+import           Binding.Libsass.Types
+import           Foreign
+import           Foreign.C.String
+import           Foreign.C.Types
+
+foreign import ccall unsafe "sass_context.h" sass_make_options
+    :: IO (Ptr SassOptions)
+
+foreign import ccall unsafe "sass_context.h" sass_make_file_context
+    :: CString
+    -> IO (Ptr SassFileContext)
+
+-- | Creates and initializes a data context, ie. context that parses string
+--   instead of a file.
+--
+--   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
+    :: CString
+    -> IO (Ptr SassDataContext)
+
+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
+    :: Ptr SassDataContext
+    -> IO CInt
+
+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
+    :: Ptr SassDataContext
+    -> IO (Ptr SassCompiler)
+
+foreign import ccall safe "sass_context.h" sass_compiler_parse
+    :: Ptr SassCompiler
+    -> IO CInt
+
+foreign import ccall safe "sass_context.h" sass_compiler_execute
+    :: Ptr SassCompiler
+    -> IO CInt
+
+foreign import ccall unsafe "sass_context.h" sass_delete_compiler
+    :: Ptr SassCompiler
+    -> IO ()
+
+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
+    :: Ptr SassDataContext
+    -> IO ()
+
+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
+    :: Ptr SassDataContext
+    -> Ptr SassContext
+
+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
+    :: Ptr SassFileContext
+    -> Ptr SassOptions
+
+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
+    :: Ptr SassFileContext
+    -> Ptr SassOptions
+    -> IO ()
+
+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
+    :: Ptr SassOptions
+    -> IO CInt
+
+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
+    :: Ptr SassOptions
+    -> IO Bool
+
+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
+    :: Ptr SassOptions
+    -> IO Bool
+
+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
+    :: Ptr SassOptions
+    -> IO Bool
+
+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
+    :: Ptr SassOptions
+    -> IO CString
+
+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
+    :: Ptr SassOptions
+    -> IO CString
+
+foreign import ccall unsafe "sass_context.h" sass_option_get_plugin_path
+    :: Ptr SassOptions
+    -> IO CString
+
+foreign import ccall unsafe "sass_context.h" sass_option_get_include_path
+    :: Ptr SassOptions
+    -> IO CString
+
+foreign import ccall unsafe "sass_context.h" sass_option_get_source_map_file
+    :: Ptr SassOptions
+    -> IO CString
+
+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
+     :: Ptr SassOptions
+     -> IO SassImporterList
+
+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
+     :: Ptr SassOptions
+     -> IO SassFunctionList
+
+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
+    :: Ptr SassOptions
+    -> CInt -- ^ 'SassOutputStyle'
+    -> IO ()
+
+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
+    :: Ptr SassOptions
+    -> Bool
+    -> IO ()
+
+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
+    :: Ptr SassOptions
+    -> Bool
+    -> IO ()
+
+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
+    :: Ptr SassOptions
+    -> CString
+    -> IO ()
+
+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
+    :: Ptr SassOptions
+    -> CString
+    -> IO ()
+
+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
+    :: Ptr SassOptions
+    -> CString
+    -> IO ()
+
+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
+    :: Ptr SassOptions
+    -> CString
+    -> IO ()
+
+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
+    :: Ptr SassOptions
+    -> SassImporterList
+    -> IO ()
+
+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
+    :: Ptr SassOptions
+    -> SassFunctionList
+    -> IO ()
+
+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
+    :: Ptr SassContext
+    -> IO CInt
+
+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
+    :: Ptr SassContext
+    -> IO CString
+
+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
+    :: Ptr SassContext
+    -> IO CString
+
+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
+    :: Ptr SassContext
+    -> IO CSize
+
+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
+    :: Ptr SassContext
+    -> IO CString
+
+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
+    :: Ptr SassContext
+    -> IO CSize
+
+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
+    :: Ptr SassContext
+    -> IO CString
+
+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
+    :: Ptr SassContext
+    -> IO CString
+
+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
+    :: Ptr SassContext
+    -> IO CString
+
+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
+    :: Ptr SassCompiler
+    -> IO CInt -- ^ Retruns 'SassCompilerState'
+
+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
+    :: Ptr SassCompiler
+    -> IO CSize
+
+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
+    :: Ptr SassCompiler
+    -> CSize
+    -> IO SassImportEntry
+
+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
+    :: Ptr SassOptions
+    -> CString
+    -> IO ()
diff --git a/Binding/Libsass/Functions.hs b/Binding/Libsass/Functions.hs
new file mode 100644
--- /dev/null
+++ b/Binding/Libsass/Functions.hs
@@ -0,0 +1,156 @@
+{-# LANGUAGE ForeignFunctionInterface #-}
+module Binding.Libsass.Functions where
+
+import           Binding.Libsass.Types
+import           Foreign
+import           Foreign.C
+
+foreign import ccall unsafe "sass_function.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_function.h" sass_importer_set_list_entry
+--     :: SassImporterList
+--     -> CSize
+--     -> SassImporterEntry
+--     -> IO ()
+
+foreign import ccall unsafe "sass_function.h" sass_make_importer
+    :: SassImporterFn
+    -> CDouble
+    -> Ptr ()
+    -> IO SassImporterEntry
+
+foreign import ccall unsafe "sass_function.h" sass_importer_get_function
+    :: SassImporterEntry
+    -> IO SassImporterFn
+
+foreign import ccall unsafe "sass_function.h" sass_importer_get_priority
+    :: SassImporterEntry
+    -> IO CDouble
+foreign import ccall unsafe "sass_function.h" sass_importer_get_cookie
+    :: SassImporterEntry
+    -> IO (Ptr ())
+
+foreign import ccall unsafe "sass_function.h" sass_delete_importer
+    :: SassImporterEntry
+    -> IO ()
+
+foreign import ccall unsafe "sass_function.h" sass_make_import_list
+    :: CSize
+    -> IO SassImportList
+
+foreign import ccall unsafe "sass_function.h" sass_make_import_entry
+    :: CString
+    -> CString
+    -> CString
+    -> IO SassImportEntry
+
+foreign import ccall unsafe "sass_function.h" sass_make_import
+    :: CString
+    -> CString
+    -> CString
+    -> CString
+    -> IO SassImportEntry
+
+foreign import ccall unsafe "sass_function.h" sass_import_set_error
+    :: SassImportEntry
+    -> CString
+    -> CSize
+    -> CSize
+    -> IO SassImportEntry
+
+foreign import ccall unsafe "sass_function.h" sass_import_set_list_entry
+    :: SassImportList
+    -> CSize
+    -> SassImportEntry
+    -> IO ()
+
+foreign import ccall unsafe "sass_function.h" sass_import_get_list_entry
+    :: SassImportList
+    -> CSize
+    -> IO SassImportEntry
+
+foreign import ccall unsafe "sass_function.h" sass_import_get_path
+    :: SassImportEntry
+    -> IO CString
+
+foreign import ccall unsafe "sass_function.h" sass_import_get_base
+    :: SassImportEntry
+    -> IO CString
+
+foreign import ccall unsafe "sass_function.h" sass_import_get_source
+    :: SassImportEntry
+    -> IO CString
+
+foreign import ccall unsafe "sass_function.h" sass_import_get_srcmap
+    :: SassImportEntry
+    -> IO CString
+
+foreign import ccall unsafe "sass_function.h" sass_import_take_source
+    :: SassImportEntry
+    -> IO CString
+
+foreign import ccall unsafe "sass_function.h" sass_import_take_srcmap
+    :: SassImportEntry
+    -> IO CString
+
+foreign import ccall unsafe "sass_function.h" sass_import_get_error_line
+    :: SassImportEntry
+    -> IO CSize
+
+foreign import ccall unsafe "sass_function.h" sass_import_get_error_column
+    :: SassImportEntry
+    -> IO CSize
+
+foreign import ccall unsafe "sass_function.h" sass_import_get_error_message
+    :: SassImportEntry
+    -> IO CString
+
+foreign import ccall unsafe "sass_function.h" sass_delete_import_list
+    :: SassImportList
+    -> IO ()
+
+foreign import ccall unsafe "sass_function.h" sass_delete_import
+    :: SassImportEntry
+    -> IO ()
+
+foreign import ccall unsafe "sass_function.h" sass_make_function_list
+    :: CSize
+    -> IO SassFunctionList
+
+foreign import ccall unsafe "sass_function.h" sass_make_function
+    :: CString
+    -> SassFunctionFn
+    -> Ptr ()
+    -> IO SassFunctionEntry
+
+foreign import ccall unsafe "sass_function.h" sass_function_get_list_entry
+    :: SassFunctionList
+    -> CSize
+    -> IO SassFunctionEntry
+
+foreign import ccall unsafe "sass_function.h" sass_function_set_list_entry
+    :: SassFunctionList
+    -> CSize
+    -> SassFunctionEntry
+    -> IO ()
+
+foreign import ccall unsafe "sass_function.h" sass_function_get_signature
+    :: SassFunctionEntry
+    -> IO CString
+
+foreign import ccall unsafe "sass_function.h" sass_function_get_function
+    :: SassFunctionEntry
+    -> IO SassFunctionFn
+
+foreign import ccall unsafe "sass_function.h" sass_function_get_cookie
+    :: SassFunctionEntry
+    -> IO (Ptr ())
diff --git a/Binding/Libsass/Types.hs b/Binding/Libsass/Types.hs
new file mode 100644
--- /dev/null
+++ b/Binding/Libsass/Types.hs
@@ -0,0 +1,127 @@
+{-# LANGUAGE EmptyDataDecls #-}
+module Binding.Libsass.Types where
+
+import           Foreign
+import           Foreign.C.String
+
+-- From sass.h
+
+-- | Defines output style of compiled CSS.
+data SassOutputStyle = SassStyleNested
+                     | SassStyleExpanded
+                     | SassStyleCompact
+                     | SassStyleCompressed
+                     deriving (Eq, Show)
+
+instance Enum SassOutputStyle where
+    fromEnum SassStyleNested     = 0
+    fromEnum SassStyleExpanded   = 1
+    fromEnum SassStyleCompact    = 2
+    fromEnum SassStyleCompressed = 3
+
+    toEnum 0 = SassStyleNested
+    toEnum 1 = SassStyleExpanded
+    toEnum 2 = SassStyleCompact
+    toEnum 3 = SassStyleCompressed
+    toEnum u = error ("SassOutputStyle.toEnum: Cannot match " ++ show u)
+
+-- From sass_context.h
+
+data SassCompiler
+data SassOptions
+data SassContext
+data SassFileContext
+data SassDataContext
+
+data SassCompilerState = SassCompilerCreated
+                       | SassCompilerParsed
+                       | SassCompilerExecuted
+                       deriving (Show, Eq)
+
+instance Enum SassCompilerState where
+    fromEnum SassCompilerCreated  = 0
+    fromEnum SassCompilerParsed   = 1
+    fromEnum SassCompilerExecuted = 2
+
+    toEnum 0 = SassCompilerCreated
+    toEnum 1 = SassCompilerParsed
+    toEnum 2 = SassCompilerExecuted
+    toEnum u = error ("SassCompilerState.toEnum: Cannot match " ++ show u)
+
+-- From sass_functions.h
+
+data SassImport
+data SassImporter
+data SassFunction
+
+type SassImportEntry = Ptr SassImport
+type SassImportList = Ptr (Ptr SassImport)
+type SassImporterEntry = Ptr SassImporter
+type SassImporterList = Ptr (Ptr SassImporter)
+
+type SassImporterFnType = 
+     CString
+  -> SassImporterEntry
+  -> Ptr SassCompiler
+  -> IO SassImportList
+type SassImporterFn = FunPtr SassImporterFnType
+
+type SassFunctionEntry = Ptr SassFunction
+type SassFunctionList = Ptr (Ptr SassFunction)
+
+type SassFunctionFnType =
+     Ptr SassValue
+  -> SassFunctionEntry
+  -> Ptr SassOptions
+  -> IO (Ptr SassValue)
+type SassFunctionFn = FunPtr SassFunctionFnType
+
+-- From sass_values.h
+
+data SassValue
+
+data SassTag = SassBoolean
+             | SassNumber
+             | SassColor
+             | SassString
+             | SassList
+             | SassMap
+             | SassNull
+             | SassError
+             | SassWarning
+             deriving (Eq, Show)
+
+instance Enum SassTag where
+    fromEnum SassBoolean = 0
+    fromEnum SassNumber  = 1
+    fromEnum SassColor   = 2
+    fromEnum SassString  = 3
+    fromEnum SassList    = 4
+    fromEnum SassMap     = 5
+    fromEnum SassNull    = 6
+    fromEnum SassError   = 7
+    fromEnum SassWarning = 8
+
+    toEnum 0 = SassBoolean
+    toEnum 1 = SassNumber
+    toEnum 2 = SassColor
+    toEnum 3 = SassString
+    toEnum 4 = SassList
+    toEnum 5 = SassMap
+    toEnum 6 = SassNull
+    toEnum 7 = SassError
+    toEnum 8 = SassWarning
+    toEnum u = error ("SassTag.toEnum: Cannot match " ++ show u)
+
+-- ^ Separator used in Sass lists.
+data SassSeparator = SassSeparatorComma
+                   | SassSeparatorSpace
+                   deriving (Eq, Show)
+
+instance Enum SassSeparator where
+    fromEnum SassSeparatorComma = 0
+    fromEnum SassSeparatorSpace  = 1
+
+    toEnum 0 = SassSeparatorComma
+    toEnum 1 = SassSeparatorSpace
+    toEnum u = error ("SassSeparator.toEnum: Cannot match " ++ show u)
diff --git a/Binding/Libsass/Values.hs b/Binding/Libsass/Values.hs
new file mode 100644
--- /dev/null
+++ b/Binding/Libsass/Values.hs
@@ -0,0 +1,234 @@
+{-# LANGUAGE ForeignFunctionInterface #-}
+module Binding.Libsass.Values where
+
+import           Binding.Libsass.Types
+import           Foreign
+import           Foreign.C
+
+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
+    :: Ptr SassValue
+    -> IO Bool
+
+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
+    :: Ptr SassValue
+    -> IO Bool
+
+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
+    :: Ptr SassValue
+    -> IO Bool
+
+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
+    :: Ptr SassValue
+    -> IO Bool
+
+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
+    :: Ptr SassValue
+    -> IO Bool
+
+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
+    :: Ptr SassValue
+    -> CDouble
+    -> IO ()
+
+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
+    :: Ptr SassValue
+    -> CString
+    -> IO ()
+
+foreign import ccall unsafe "sass_values.h" sass_string_get_value
+    :: Ptr SassValue
+    -> IO CString
+
+foreign import ccall unsafe "sass_values.h" sass_string_set_value
+    :: Ptr SassValue
+    -> CString
+    -> IO ()
+
+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
+    :: Ptr SassValue
+    -> Bool
+    -> IO ()
+
+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
+    :: Ptr SassValue
+    -> CDouble
+    -> IO ()
+
+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
+    :: Ptr SassValue
+    -> CDouble
+    -> IO ()
+
+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
+    :: Ptr SassValue
+    -> CDouble
+    -> IO ()
+
+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
+    :: Ptr SassValue
+    -> CDouble
+    -> IO ()
+
+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
+    :: Ptr SassValue
+    -> IO CInt -- ^ Retrurns 'SassSeparator'
+
+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
+    :: Ptr SassValue
+    -> CSize
+    -> IO (Ptr SassValue)
+
+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
+    :: Ptr SassValue
+    -> IO CSize
+
+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
+    :: Ptr SassValue
+    -> CSize
+    -> Ptr SassValue
+    -> IO ()
+
+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
+    :: Ptr SassValue
+    -> CSize
+    -> Ptr SassValue
+    -> IO ()
+
+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
+    :: Ptr SassValue
+    -> CString
+    -> IO ()
+
+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
+    :: Ptr SassValue
+    -> CString
+    -> IO ()
+
+foreign import ccall unsafe "sass_values.h" sass_make_null
+    :: IO (Ptr SassValue)
+
+foreign import ccall unsafe "sass_values.h" sass_make_boolean
+    :: Bool
+    -> IO (Ptr SassValue)
+
+foreign import ccall unsafe "sass_values.h" sass_make_string
+    :: CString
+    -> IO (Ptr SassValue)
+
+foreign import ccall unsafe "sass_values.h" sass_make_number
+    :: CDouble
+    -> CString
+    -> IO (Ptr SassValue)
+
+foreign import ccall unsafe "sass_values.h" sass_make_color
+    :: CDouble
+    -> CDouble
+    -> CDouble
+    -> CDouble
+    -> IO (Ptr SassValue)
+
+foreign import ccall unsafe "sass_values.h" sass_make_list
+    :: CSize
+    -> CInt -- ^ 'SassSeparator'
+    -> IO (Ptr SassValue)
+
+foreign import ccall unsafe "sass_values.h" sass_make_map
+    :: CSize
+    -> IO (Ptr SassValue)
+
+foreign import ccall unsafe "sass_values.h" sass_make_error
+    :: CString
+    -> IO (Ptr SassValue)
+
+foreign import ccall unsafe "sass_values.h" sass_make_warning
+    :: CString
+    -> IO (Ptr SassValue)
+
+foreign import ccall unsafe "sass_values.h" sass_delete_value
+    :: Ptr SassValue
+    -> IO ()
+
+foreign import ccall unsafe "sass_values.h" sass_clone_value
+    :: Ptr SassValue
+    -> IO (Ptr SassValue)
diff --git a/Binding/Libsass/Wrappers.hs b/Binding/Libsass/Wrappers.hs
new file mode 100644
--- /dev/null
+++ b/Binding/Libsass/Wrappers.hs
@@ -0,0 +1,34 @@
+{-# LANGUAGE ForeignFunctionInterface #-}
+module Binding.Libsass.Wrappers where
+
+import           Binding.Libsass.Types
+import           Foreign
+
+foreign import ccall safe "wrapper" mkSassImporterFn
+    :: SassImporterFnType
+    -> IO SassImporterFn
+
+foreign import ccall safe "wrapper" mkSassFunctionFn
+    :: SassFunctionFnType
+    -> IO SassFunctionFn
+
+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"
+    p_sass_delete_file_context :: FunPtr (Ptr SassFileContext -> IO ())
+
+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"
+    p_sass_delete_import_list :: FunPtr (SassImportList -> IO ())
+
+foreign import ccall "sass_function.h &sass_delete_import"
+    p_sass_delete_import :: FunPtr (SassImportEntry -> IO ())
+
+foreign import ccall "sass_function.h &sass_delete_importer"
+    p_sass_delete_importer :: FunPtr (SassImporterEntry -> IO ())
+
+foreign import ccall  "sass_values.h &sass_delete_value"
+    p_sass_delete_value :: FunPtr (Ptr SassValue -> IO ())
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2015 Jakub Fijałkowski
+
+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.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,55 @@
+import           Data.Maybe                         (fromJust)
+import           Distribution.PackageDescription
+import           Distribution.Simple
+import           Distribution.Simple.LocalBuildInfo (InstallDirs (..),
+                                                     LocalBuildInfo (..),
+                                                     absoluteInstallDirs,
+                                                     localPkgDescr)
+import           Distribution.Simple.Setup
+import           Distribution.Simple.Utils          (rawSystemExit)
+import           System.Directory                   (getCurrentDirectory)
+
+main = defaultMainWithHooks simpleUserHooks
+  {
+    preConf = \a f -> makeLibsass a f >> preConf simpleUserHooks a f
+  , copyHook = copyLibsass
+  , confHook = \a f -> confHook simpleUserHooks a f >>= updateExtraLibDirs
+  , postClean = cleanLibsass
+  }
+
+makeLibsass :: Args -> ConfigFlags -> IO ()
+makeLibsass _ flags =
+    rawSystemExit (fromFlag $ configVerbosity flags) "env"
+        ["make", "--directory=libsass"]
+
+updateExtraLibDirs :: LocalBuildInfo -> IO LocalBuildInfo
+updateExtraLibDirs localBuildInfo = do
+    let packageDescription = localPkgDescr localBuildInfo
+        lib = fromJust $ library packageDescription
+        libBuild = libBuildInfo lib
+    dir <- getCurrentDirectory
+    return localBuildInfo {
+        localPkgDescr = packageDescription {
+            library = Just $ lib {
+                libBuildInfo = libBuild {
+                    extraLibDirs = (dir ++ "/libsass/lib") :
+                        extraLibDirs libBuild
+                }
+            }
+        }
+    }
+
+copyLibsass :: PackageDescription -> LocalBuildInfo -> UserHooks -> CopyFlags
+            -> IO ()
+copyLibsass pkg_descr lbi _ flags = do
+    let libPref = libdir . absoluteInstallDirs pkg_descr lbi
+                . fromFlag . copyDest
+                $ flags
+    rawSystemExit (fromFlag $ copyVerbosity flags) "cp"
+        ["libsass/lib/libsass.a", libPref]
+
+
+cleanLibsass :: Args -> CleanFlags -> PackageDescription -> () -> IO ()
+cleanLibsass _ flags _ _ =
+    rawSystemExit (fromFlag $ cleanVerbosity flags) "env"
+        ["make", "--directory=libsass", "clean"]
diff --git a/hlibsass.cabal b/hlibsass.cabal
new file mode 100644
--- /dev/null
+++ b/hlibsass.cabal
@@ -0,0 +1,57 @@
+name:                hlibsass
+version:             0.1.0.0
+license:             MIT
+license-file:        LICENSE
+author:              Jakub Fijałkowski <fiolek94@gmail.com>
+maintainer:          fiolek94@gmail.com
+category:            Foreign
+build-type:          Custom
+cabal-version:       >= 1.10
+stability:           experimental
+synopsis:            Low-level bindings to libsass
+description:
+  This package provides (very) low level bindings to libsass. It uses libsass
+  compiled to static library, so if you use this in your project, you have to
+  link your project with C++ runtime(which libsass does automatically - links
+  with libstd++).
+  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/Makefile
+  libsass/LICENSE
+
+source-repository head
+  type:              git
+  location:          git://github.com/jakubfijalkowski/hlibsass.git
+
+library
+  exposed-modules:
+      Binding.Libsass
+    , Binding.Libsass.Types
+    , Binding.Libsass.Wrappers
+    , Binding.Libsass.Context
+    , Binding.Libsass.Functions
+    , Binding.Libsass.Values
+  build-depends:       base >= 4.7 && < 5
+  hs-source-dirs:      .
+  default-language:    Haskell2010
+  default-extensions:  ForeignFunctionInterface
+  extra-libraries:     sass
+  ghc-options:         -Wall
+  extra-libraries:     stdc++, sass
+
+test-suite tests
+  hs-source-dirs:      tests
+  main-is:             Main.hs
+  type:                exitcode-stdio-1.0
+  ghc-options:         -Wall
+  build-depends:       base >= 4.7 && < 5, hspec, hlibsass
+  default-language:    Haskell2010
diff --git a/libsass/LICENSE b/libsass/LICENSE
new file mode 100644
--- /dev/null
+++ b/libsass/LICENSE
@@ -0,0 +1,25 @@
+
+Copyright (C) 2012 by Hampton Catlin
+
+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.
+
+
+The following files in the spec were taken from the original Ruby Sass project which
+is copyright Hampton Catlin, Nathan Weizenbaum, and Chris Eppstein and under
+the same license.
diff --git a/libsass/Makefile b/libsass/Makefile
new file mode 100644
--- /dev/null
+++ b/libsass/Makefile
@@ -0,0 +1,242 @@
+CC       ?= gcc
+CXX      ?= g++
+RM       ?= rm -f
+CP       ?= cp -a
+MKDIR    ?= mkdir
+WINDRES  ?= windres
+CFLAGS   ?= -Wall -O2
+CXXFLAGS ?= -Wall -O2
+LDFLAGS  ?= -Wall -O2 -Wl,--no-undefined
+CAT      ?= $(if $(filter $(OS),Windows_NT),type,cat)
+
+ifneq (,$(findstring /cygdrive/,$(PATH)))
+	UNAME := Cygwin
+else
+	ifneq (,$(findstring WINDOWS,$(PATH)))
+		UNAME := Windows
+	else
+		ifneq (,$(findstring mingw32,$(MAKE)))
+			UNAME := MinGW
+		else
+			ifneq (,$(findstring MINGW32,$(shell uname -s)))
+				UNAME = MinGW
+			else
+				UNAME := $(shell uname -s)
+			endif
+		endif
+	endif
+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)","")
+		LIBSASS_VERSION ?= $(shell $(CAT) VERSION)
+	endif
+endif
+
+ifneq "$(LIBSASS_VERSION)" ""
+	CFLAGS   += -DLIBSASS_VERSION="\"$(LIBSASS_VERSION)\""
+	CXXFLAGS += -DLIBSASS_VERSION="\"$(LIBSASS_VERSION)\""
+endif
+
+# enable mandatory flag
+ifeq (MinGW,$(UNAME))
+	CXXFLAGS += -std=gnu++0x
+	LDFLAGS  += -std=gnu++0x
+else
+	CXXFLAGS += -std=c++0x
+	LDFLAGS  += -std=c++0x
+endif
+
+ifneq "$(SASS_LIBSASS_PATH)" ""
+	CFLAGS   += -I $(SASS_LIBSASS_PATH)
+	CXXFLAGS += -I $(SASS_LIBSASS_PATH)
+endif
+
+ifneq "$(EXTRA_CFLAGS)" ""
+	CFLAGS   += $(EXTRA_CFLAGS)
+endif
+ifneq "$(EXTRA_CXXFLAGS)" ""
+	CXXFLAGS += $(EXTRA_CXXFLAGS)
+endif
+ifneq "$(EXTRA_LDFLAGS)" ""
+	LDFLAGS  += $(EXTRA_LDFLAGS)
+endif
+
+LDLIBS = -lstdc++ -lm
+ifeq ($(UNAME),Darwin)
+	CFLAGS += -stdlib=libc++
+	CXXFLAGS += -stdlib=libc++
+	LDFLAGS += -stdlib=libc++
+endif
+
+ifneq (MinGW,$(UNAME))
+	LDFLAGS += -ldl
+	LDLIBS += -ldl
+endif
+
+ifneq ($(BUILD),shared)
+	BUILD = static
+endif
+
+ifeq (,$(PREFIX))
+	ifeq (,$(TRAVIS_BUILD_DIR))
+		PREFIX = /usr/local
+	else
+		PREFIX = $(TRAVIS_BUILD_DIR)
+	endif
+endif
+
+SASS_SASSC_PATH ?= sassc
+SASS_SPEC_PATH ?= sass-spec
+SASS_SPEC_SPEC_DIR ?= spec
+SASSC_BIN = $(SASS_SASSC_PATH)/bin/sassc
+RUBY_BIN = ruby
+
+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
+
+RESOURCES =
+
+LIBRARIES = lib/libsass.so
+
+ifeq (MinGW,$(UNAME))
+	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
+endif
+
+OBJECTS = $(SOURCES:.cpp=.o)
+COBJECTS = $(CSOURCES:.c=.o)
+RCOBJECTS = $(RESOURCES:.rc=.o)
+
+DEBUG_LVL ?= NONE
+
+all: $(BUILD)
+
+debug: $(BUILD)
+
+debug-static: LDFLAGS := -g $(filter-out -O2,$(LDFLAGS))
+debug-static: CFLAGS := -g -DDEBUG -DDEBUG_LVL="$(DEBUG_LVL)" $(filter-out -O2,$(CFLAGS))
+debug-static: CXXFLAGS := -g -DDEBUG -DDEBUG_LVL="$(DEBUG_LVL)" $(filter-out -O2,$(CXXFLAGS))
+debug-static: static
+
+debug-shared: LDFLAGS := -g $(filter-out -O2,$(LDFLAGS))
+debug-shared: CFLAGS := -g -DDEBUG -DDEBUG_LVL="$(DEBUG_LVL)" $(filter-out -O2,$(CFLAGS))
+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
+
+lib/libsass.a: lib $(COBJECTS) $(OBJECTS)
+	$(AR) rcvs $@ $(COBJECTS) $(OBJECTS)
+
+lib/libsass.so: lib $(COBJECTS) $(OBJECTS)
+	$(CXX) -shared $(LDFLAGS) -o $@ $(COBJECTS) $(OBJECTS) $(LDLIBS)
+
+lib/libsass.dll: lib $(COBJECTS) $(OBJECTS) $(RCOBJECTS)
+	$(CXX) -shared $(LDFLAGS) -o $@ $(COBJECTS) $(OBJECTS) $(RCOBJECTS) $(LDLIBS) -s -Wl,--subsystem,windows,--out-implib,lib/libsass.a
+
+%.o: %.c
+	$(CC) $(CFLAGS) -c -o $@ $<
+
+%.o: %.rc
+	$(WINDRES) -i $< -o $@
+
+%.o: %.cpp
+	$(CXX) $(CXXFLAGS) -c -o $@ $<
+
+%: %.o static
+	$(CXX) $(CXXFLAGS) -o $@ $+ $(LDFLAGS) $(LDLIBS)
+
+install: install-$(BUILD)
+
+install-static: lib/libsass.a
+	install -pm0755 $< $(DESTDIR)$(PREFIX)/$<
+
+install-shared: lib/libsass.so
+	install -pm0755 $< $(DESTDIR)$(PREFIX)/$<
+
+$(SASSC_BIN): $(BUILD)
+	cd $(SASS_SASSC_PATH) && $(MAKE)
+
+sassc: $(SASSC_BIN)
+	$(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)
+
+test_build: $(SASSC_BIN)
+	$(RUBY_BIN) $(SASS_SPEC_PATH)/sass-spec.rb -c $(SASSC_BIN) -s --ignore-todo $(LOG_FLAGS) $(SASS_SPEC_PATH)/$(SASS_SPEC_SPEC_DIR)
+
+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
+
+
+.PHONY: all debug debug-static debug-shared static shared install install-static install-shared sassc clean
diff --git a/libsass/ast.cpp b/libsass/ast.cpp
new file mode 100644
--- /dev/null
+++ b/libsass/ast.cpp
@@ -0,0 +1,591 @@
+#include "ast.hpp"
+#include "context.hpp"
+#include "to_string.hpp"
+#include <set>
+#include <algorithm>
+#include <iostream>
+
+namespace Sass {
+  using namespace std;
+
+  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)
+      { 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 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)
+  {
+    if (length() != 1)
+    { return false; }
+    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()); }
+
+    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
+  }
+
+  /* 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;
+  }*/
+
+}
+
diff --git a/libsass/ast.hpp b/libsass/ast.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/ast.hpp
@@ -0,0 +1,2168 @@
+#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 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    { return elements_.at(k); }
+    bool has_duplicate_key() const         { return duplicate_key_ != 0; }
+    Expression* get_duplicate_key() const  { return duplicate_key_; }
+    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 bool operator==(Expression& rhs) const
+    {
+      try
+      {
+        List& l = dynamic_cast<List&>(rhs);
+        if (!(l && length() == l.length() && separator() == l.separator())) return false;
+        for (size_t i = 0, L = l.length(); i < L; ++i)
+          if (!(*(elements()[i]) == *(l[i]))) return false;
+        return true;
+      }
+      catch (std::bad_cast&)
+      {
+        return false;
+      }
+      catch (...) { throw; }
+
+    }
+
+    virtual size_t 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_;
+    }
+
+    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);
+  public:
+    Binary_Expression(ParserState pstate,
+                      Type t, Expression* lhs, Expression* rhs)
+    : Expression(pstate), type_(t), left_(lhs), right_(rhs)
+    { }
+    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);
+  public:
+    Unary_Expression(ParserState pstate, Type t, Expression* o)
+    : Expression(pstate), type_(t), operand_(o)
+    { }
+    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() == *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)
+    : Expression(pstate),
+      value_(val),
+      zero_(zero),
+      numerator_units_(vector<string>()),
+      denominator_units_(vector<string>()),
+      hash_(0)
+    {
+      if (!u.empty()) numerator_units_.push_back(u);
+      concrete_type(NUMBER);
+    }
+    bool            zero()              { return zero_; }
+    vector<string>& numerator_units()   { return numerator_units_; }
+    vector<string>& denominator_units() { return denominator_units_; }
+    string type() { return "number"; }
+    static string type_name() { return "number"; }
+    string unit() const
+    {
+      stringstream u;
+      for (size_t i = 0, S = numerator_units_.size(); i < S; ++i) {
+        if (i) u << '*';
+        u << numerator_units_[i];
+      }
+      if (!denominator_units_.empty()) u << '/';
+      for (size_t i = 0, S = denominator_units_.size(); i < S; ++i) {
+        if (i) u << '*';
+        u << denominator_units_[i];
+      }
+      return u.str();
+    }
+    bool is_unitless()
+    { return numerator_units_.empty() && denominator_units_.empty(); }
+    void normalize(string to = "")
+    {
+      // (multiple passes because I'm too tired to think up something clever)
+      // Find a unit to convert everything to, if one isn't provided.
+      if (to.empty()) {
+        for (size_t i = 0, S = numerator_units_.size(); i < S; ++i) {
+          string u(numerator_units_[i]);
+          if (string_to_unit(u) == INCOMMENSURABLE) {
+            continue;
+          }
+          else {
+            to = u;
+            break;
+          }
+        }
+      }
+      if (to.empty()) {
+        for (size_t i = 0, S = denominator_units_.size(); i < S; ++i) {
+          string u(denominator_units_[i]);
+          if (string_to_unit(u) == INCOMMENSURABLE) {
+            continue;
+          }
+          else {
+            to = u;
+            break;
+          }
+        }
+      }
+      // Now loop through again and do all the conversions.
+      for (size_t i = 0, S = numerator_units_.size(); i < S; ++i) {
+        string from(numerator_units_[i]);
+        if (string_to_unit(from) == INCOMMENSURABLE) continue;
+        value_ *= conversion_factor(from, to);
+        numerator_units_[i] = to;
+      }
+      for (size_t i = 0, S = denominator_units_.size(); i < S; ++i) {
+        string from(denominator_units_[i]);
+        if (string_to_unit(from) == INCOMMENSURABLE) continue;
+        value_ /= conversion_factor(from, to);
+        denominator_units_[i] = to;
+      }
+      // Now divide out identical units in the numerator and denominator.
+      vector<string> ncopy;
+      ncopy.reserve(numerator_units_.size());
+      for (vector<string>::iterator n = numerator_units_.begin();
+           n != numerator_units_.end();
+           ++n) {
+        vector<string>::iterator d = find(denominator_units_.begin(),
+                                          denominator_units_.end(),
+                                          *n);
+        if (d != denominator_units_.end()) {
+          denominator_units_.erase(d);
+        }
+        else {
+          ncopy.push_back(*n);
+        }
+      }
+      numerator_units_ = ncopy;
+      // Sort the units to make them pretty and, well, normal.
+      sort(numerator_units_.begin(), numerator_units_.end());
+      sort(denominator_units_.begin(), denominator_units_.end());
+    }
+    // useful for making one number compatible with another
+    string find_convertible_unit() const
+    {
+      for (size_t i = 0, S = numerator_units_.size(); i < S; ++i) {
+        string u(numerator_units_[i]);
+        if (string_to_unit(u) != INCOMMENSURABLE) return u;
+      }
+      for (size_t i = 0, S = denominator_units_.size(); i < S; ++i) {
+        string u(denominator_units_[i]);
+        if (string_to_unit(u) != INCOMMENSURABLE) return u;
+      }
+      return string();
+    }
+
+    virtual bool operator==(Expression& rhs) const
+    {
+      try
+      {
+        Number& e(dynamic_cast<Number&>(rhs));
+        if (!e) return false;
+        e.normalize(find_convertible_unit());
+        return unit() == e.unit() && value() == e.value();
+      }
+      catch (std::bad_cast&)
+      {
+        return false;
+      }
+      catch (...) { throw; }
+    }
+
+    virtual 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(string, value);
+  protected:
+    size_t hash_;
+  public:
+    String_Constant(ParserState pstate, string val)
+    : String(pstate), quote_mark_(0), value_(read_css_string(val)), hash_(0)
+    { }
+    String_Constant(ParserState pstate, const char* beg)
+    : String(pstate), quote_mark_(0), value_(read_css_string(string(beg))), hash_(0)
+    { }
+    String_Constant(ParserState pstate, const char* beg, const char* end)
+    : String(pstate), quote_mark_(0), value_(read_css_string(string(beg, end-beg))), hash_(0)
+    { }
+    String_Constant(ParserState pstate, const Token& tok)
+    : String(pstate), quote_mark_(0), 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* rhs);
+    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*);
+    bool is_superselector_of(Complex_Selector*);
+    // 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();
+    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
new file mode 100644
--- /dev/null
+++ b/libsass/ast_def_macros.hpp
@@ -0,0 +1,21 @@
+#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
new file mode 100644
--- /dev/null
+++ b/libsass/ast_factory.hpp
@@ -0,0 +1,92 @@
+#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
new file mode 100644
--- /dev/null
+++ b/libsass/ast_fwd_decl.hpp
@@ -0,0 +1,85 @@
+#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
new file mode 100644
--- /dev/null
+++ b/libsass/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/b64/encode.h b/libsass/b64/encode.h
new file mode 100644
--- /dev/null
+++ b/libsass/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/backtrace.hpp b/libsass/backtrace.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/backtrace.hpp
@@ -0,0 +1,77 @@
+#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
+             << " of "
+             << rel_path;
+        } else {
+          ss << endl
+             << "\t"
+             << rel_path
+             << ":"
+             << this_point->pstate.line
+             << 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
new file mode 100644
--- /dev/null
+++ b/libsass/base64vlq.cpp
@@ -0,0 +1,43 @@
+#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
new file mode 100644
--- /dev/null
+++ b/libsass/base64vlq.hpp
@@ -0,0 +1,31 @@
+#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
new file mode 100644
--- /dev/null
+++ b/libsass/bind.cpp
@@ -0,0 +1,186 @@
+#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) {
+      if (ip >= LP) {
+        stringstream msg;
+        msg << callee << " only takes " << LP << " arguments; "
+            << "given " << LA;
+        error(msg.str(), as->pstate());
+      }
+      Parameter* p = (*ps)[ip];
+      Argument*  a = (*as)[ia];
+
+      // If the current parameter is the rest parameter, process and break the loop
+      if (p->is_rest_parameter()) {
+        if (a->is_rest_argument()) {
+          // rest param and rest arg -- just add one to the other
+          if (env->has_local(p->name())) {
+            *static_cast<List*>(env->local_frame()[p->name()])
+            += static_cast<List*>(a->value());
+          }
+          else {
+            env->local_frame()[p->name()] = a->value();
+          }
+        } else {
+
+          // copy all remaining arguments into the rest parameter, preserving names
+          List* arglist = new (ctx.mem) List(p->pstate(),
+                                             0,
+                                             List::COMMA,
+                                             true);
+          env->local_frame()[p->name()] = arglist;
+          while (ia < LA) {
+            a = (*as)[ia];
+            (*arglist) << new (ctx.mem) Argument(a->pstate(),
+                                                 a->value(),
+                                                 a->name(),
+                                                 false);
+            ++ia;
+          }
+        }
+        ++ip;
+        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);
+        }
+        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();
+      }
+    }
+
+    // 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
new file mode 100644
--- /dev/null
+++ b/libsass/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(string caller, Parameters*, Arguments*, Context&, Env*, Eval*);
+}
+
+#endif
diff --git a/libsass/cencode.c b/libsass/cencode.c
new file mode 100644
--- /dev/null
+++ b/libsass/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 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
new file mode 100644
--- /dev/null
+++ b/libsass/color_names.hpp
@@ -0,0 +1,327 @@
+#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
new file mode 100644
--- /dev/null
+++ b/libsass/constants.cpp
@@ -0,0 +1,166 @@
+#include "constants.hpp"
+
+namespace Sass {
+  namespace Constants {
+
+    // 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
new file mode 100644
--- /dev/null
+++ b/libsass/constants.hpp
@@ -0,0 +1,170 @@
+#ifndef SASS_CONSTANTS_H
+#define SASS_CONSTANTS_H
+
+namespace Sass {
+  namespace Constants {
+
+    // 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
new file mode 100644
--- /dev/null
+++ b/libsass/context.cpp
@@ -0,0 +1,560 @@
+#ifdef _WIN32
+#define PATH_SEP ';'
+#else
+#define PATH_SEP ':'
+#endif
+
+#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"
+
+#include <string>
+#include <cstdlib>
+#include <cstring>
+#include <iomanip>
+#include <sstream>
+#include <iostream>
+
+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, compact_sig, compact, 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);
+  }
+
+  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
new file mode 100644
--- /dev/null
+++ b/libsass/context.hpp
@@ -0,0 +1,157 @@
+#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
new file mode 100644
--- /dev/null
+++ b/libsass/contextualize.cpp
@@ -0,0 +1,141 @@
+#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());
+      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 {
+      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
new file mode 100644
--- /dev/null
+++ b/libsass/contextualize.hpp
@@ -0,0 +1,46 @@
+#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
new file mode 100644
--- /dev/null
+++ b/libsass/contextualize_eval.cpp
@@ -0,0 +1,93 @@
+#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(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
new file mode 100644
--- /dev/null
+++ b/libsass/contextualize_eval.hpp
@@ -0,0 +1,44 @@
+#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
new file mode 100644
--- /dev/null
+++ b/libsass/cssize.cpp
@@ -0,0 +1,549 @@
+#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));
+          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
new file mode 100644
--- /dev/null
+++ b/libsass/cssize.hpp
@@ -0,0 +1,82 @@
+#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
new file mode 100644
--- /dev/null
+++ b/libsass/debug.hpp
@@ -0,0 +1,39 @@
+#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
new file mode 100644
--- /dev/null
+++ b/libsass/debugger.hpp
@@ -0,0 +1,391 @@
+#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 void debug_ast(AST_Node* node, string ind = "", Env* env = 0)
+{
+  if (node == 0) return;
+  if (ind == "") cerr << "####################################################################\n";
+  if (dynamic_cast<Bubble*>(node)) {
+    Bubble* bubble = dynamic_cast<Bubble*>(node);
+    cerr << ind << "Bubble " << bubble << " " << bubble->tabs() << endl;
+  } else if (dynamic_cast<At_Root_Block*>(node)) {
+    At_Root_Block* root_block = dynamic_cast<At_Root_Block*>(node);
+    cerr << ind << "At_Root_Block " << root_block << " " << root_block->tabs() << endl;
+    if (root_block->block()) for(auto i : root_block->block()->elements()) { debug_ast(i, ind + " ", env); }
+  } else if (dynamic_cast<Selector_List*>(node)) {
+    Selector_List* selector = dynamic_cast<Selector_List*>(node);
+
+    cerr << ind << "Selector_List " << selector
+      << " [block:" << selector->last_block() << "]"
+      << (selector->last_block() && selector->last_block()->is_root() ? " [root]" : "")
+      << " [@media:" << selector->media_block() << "]"
+      << (selector->is_optional() ? " [is_optional]": " -")
+      << (selector->has_line_break() ? " [line-break]": " -")
+      << (selector->has_line_feed() ? " [line-feed]": " -")
+    << endl;
+
+    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 << " <" << 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
+      << " [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 << " [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 << " " << selector->tabs() << endl;
+    if (selector->block()) for(auto i : selector->block()->elements()) { debug_ast(i, ind + " ", env); }
+  } else if (dynamic_cast<Wrapped_Selector*>(node)) {
+    Wrapped_Selector* selector = dynamic_cast<Wrapped_Selector*>(node);
+    cerr << ind << "Wrapped_Selector " << selector << " <<" << selector->name() << ">>" << (selector->has_line_break() ? " [line-break]": " -") << (selector->has_line_feed() ? " [line-feed]": " -") << endl;
+    debug_ast(selector->selector(), ind + " () ", env);
+  } else if (dynamic_cast<Pseudo_Selector*>(node)) {
+    Pseudo_Selector* selector = dynamic_cast<Pseudo_Selector*>(node);
+    cerr << ind << "Pseudo_Selector " << selector << " <<" << selector->name() << ">>" << (selector->has_line_break() ? " [line-break]": " -") << (selector->has_line_feed() ? " [line-feed]": " -") << endl;
+    debug_ast(selector->expression(), ind + " <= ", env);
+  } else if (dynamic_cast<Attribute_Selector*>(node)) {
+    Attribute_Selector* selector = dynamic_cast<Attribute_Selector*>(node);
+    cerr << ind << "Attribute_Selector " << selector << " <<" << selector->name() << ">>" << (selector->has_line_break() ? " [line-break]": " -") << (selector->has_line_feed() ? " [line-feed]": " -") << endl;
+    debug_ast(selector->value(), ind + "[" + selector->matcher() + "] ", env);
+  } else if (dynamic_cast<Selector_Qualifier*>(node)) {
+    Selector_Qualifier* selector = dynamic_cast<Selector_Qualifier*>(node);
+    cerr << ind << "Selector_Qualifier " << selector << " <<" << selector->name() << ">>" << (selector->has_line_break() ? " [line-break]": " -") << (selector->has_line_feed() ? " [line-feed]": " -") << endl;
+  } else if (dynamic_cast<Type_Selector*>(node)) {
+    Type_Selector* selector = dynamic_cast<Type_Selector*>(node);
+    cerr << ind << "Type_Selector " << selector << " <<" << selector->name() << ">>" << (selector->has_line_break() ? " [line-break]": " -") <<
+      " <" << prettyprint(selector->pstate().token.ws_before()) << ">" << 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 << " @ref " << selector->selector() << endl;
+  } else if (dynamic_cast<Simple_Selector*>(node)) {
+    Simple_Selector* selector = dynamic_cast<Simple_Selector*>(node);
+    cerr << ind << "Simple_Selector " << selector << (selector->has_line_break() ? " [line-break]": " -") << (selector->has_line_feed() ? " [line-feed]": " -") << endl;
+
+  } else if (dynamic_cast<Selector_Schema*>(node)) {
+    Selector_Schema* selector = dynamic_cast<Selector_Schema*>(node);
+    cerr << ind << "Selector_Schema " << selector
+      << " [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
+      << (selector->has_line_break() ? " [line-break]": " -")
+      << (selector->has_line_feed() ? " [line-feed]": " -")
+    << endl;
+
+  } else if (dynamic_cast<Media_Query_Expression*>(node)) {
+    Media_Query_Expression* block = dynamic_cast<Media_Query_Expression*>(node);
+    cerr << ind << "Media_Query_Expression " << block
+      << (block->is_interpolated() ? " [is_interpolated]": " -")
+    << endl;
+    debug_ast(block->feature(), ind + " f) ");
+    debug_ast(block->value(), ind + " v) ");
+
+  } else if (dynamic_cast<Media_Query*>(node)) {
+    Media_Query* block = dynamic_cast<Media_Query*>(node);
+    cerr << ind << "Media_Query " << block
+      << (block->is_negated() ? " [is_negated]": " -")
+      << (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 << " " << block->tabs() << endl;
+    debug_ast(block->media_queries(), ind + " =@ ");
+    debug_ast(block->selector(), ind + " -@ ");
+    if (block->block()) for(auto i : block->block()->elements()) { debug_ast(i, ind + " ", env); }
+  } else if (dynamic_cast<Feature_Block*>(node)) {
+    Feature_Block* block = dynamic_cast<Feature_Block*>(node);
+    cerr << ind << "Feature_Block " << block << " " << block->tabs() << endl;
+    if (block->block()) for(auto i : block->block()->elements()) { debug_ast(i, ind + " ", env); }
+  } else if (dynamic_cast<Block*>(node)) {
+    Block* root_block = dynamic_cast<Block*>(node);
+    cerr << ind << "Block " << root_block << " " << root_block->tabs() << endl;
+    if (root_block->block()) for(auto i : root_block->block()->elements()) { debug_ast(i, ind + " ", env); }
+  } else if (dynamic_cast<Warning*>(node)) {
+    Warning* block = dynamic_cast<Warning*>(node);
+    cerr << ind << "Warning " << block << " " << block->tabs() << endl;
+  } else if (dynamic_cast<Error*>(node)) {
+    Error* block = dynamic_cast<Error*>(node);
+    cerr << ind << "Error " << block << " " << block->tabs() << endl;
+  } else if (dynamic_cast<Debug*>(node)) {
+    Debug* block = dynamic_cast<Debug*>(node);
+    cerr << ind << "Debug " << block << " " << block->tabs() << endl;
+  } else if (dynamic_cast<Comment*>(node)) {
+    Comment* block = dynamic_cast<Comment*>(node);
+    cerr << ind << "Comment " << block << " " << block->tabs() <<
+      " <" << prettyprint(block->pstate().token.ws_before()) << ">" << endl;
+    debug_ast(block->text(), ind + "// ", env);
+  } else if (dynamic_cast<If*>(node)) {
+    If* block = dynamic_cast<If*>(node);
+    cerr << ind << "If " << block << " " << block->tabs() << endl;
+  } else if (dynamic_cast<Return*>(node)) {
+    Return* block = dynamic_cast<Return*>(node);
+    cerr << ind << "Return " << block << " " << block->tabs() << endl;
+  } else if (dynamic_cast<Extension*>(node)) {
+    Extension* block = dynamic_cast<Extension*>(node);
+    cerr << ind << "Extension " << block << " " << block->tabs() << endl;
+    debug_ast(block->selector(), ind + "-> ", env);
+  } else if (dynamic_cast<Content*>(node)) {
+    Content* block = dynamic_cast<Content*>(node);
+    cerr << ind << "Content " << block << " " << block->tabs() << endl;
+  } else if (dynamic_cast<Import_Stub*>(node)) {
+    Import_Stub* block = dynamic_cast<Import_Stub*>(node);
+    cerr << ind << "Import_Stub " << block << " " << block->tabs() << endl;
+  } else if (dynamic_cast<Import*>(node)) {
+    Import* block = dynamic_cast<Import*>(node);
+    cerr << ind << "Import " << block << " " << block->tabs() << endl;
+    // vector<string>         files_;
+    for (auto imp : block->urls()) debug_ast(imp, "@ ", env);
+  } else if (dynamic_cast<Assignment*>(node)) {
+    Assignment* block = dynamic_cast<Assignment*>(node);
+    cerr << ind << "Assignment " << block << " <<" << block->variable() << ">> " << block->tabs() << endl;
+    debug_ast(block->value(), ind + "=", env);
+  } else if (dynamic_cast<Declaration*>(node)) {
+    Declaration* block = dynamic_cast<Declaration*>(node);
+    cerr << ind << "Declaration " << block << " " << block->tabs() << endl;
+    debug_ast(block->property(), ind + " prop: ", env);
+    debug_ast(block->value(), ind + " value: ", env);
+  } else if (dynamic_cast<Keyframe_Rule*>(node)) {
+    Keyframe_Rule* has_block = dynamic_cast<Keyframe_Rule*>(node);
+    cerr << ind << "Keyframe_Rule " << has_block << " " << has_block->tabs() << endl;
+    if (has_block->selector()) debug_ast(has_block->selector(), ind + "@");
+    if (has_block->block()) for(auto i : has_block->block()->elements()) { debug_ast(i, ind + " ", env); }
+  } else if (dynamic_cast<At_Rule*>(node)) {
+    At_Rule* block = dynamic_cast<At_Rule*>(node);
+    cerr << ind << "At_Rule " << block << " [" << block->keyword() << "] " << block->tabs() << endl;
+    debug_ast(block->value(), ind + "+", env);
+    debug_ast(block->selector(), ind + "~", env);
+    if (block->block()) for(auto i : block->block()->elements()) { debug_ast(i, ind + " ", env); }
+  } else if (dynamic_cast<Each*>(node)) {
+    Each* block = dynamic_cast<Each*>(node);
+    cerr << ind << "Each " << block << " " << block->tabs() << endl;
+    if (block->block()) for(auto i : block->block()->elements()) { debug_ast(i, ind + " ", env); }
+  } else if (dynamic_cast<For*>(node)) {
+    For* block = dynamic_cast<For*>(node);
+    cerr << ind << "For " << block << " " << block->tabs() << endl;
+    if (block->block()) for(auto i : block->block()->elements()) { debug_ast(i, ind + " ", env); }
+  } else if (dynamic_cast<While*>(node)) {
+    While* block = dynamic_cast<While*>(node);
+    cerr << ind << "While " << block << " " << block->tabs() << endl;
+    if (block->block()) for(auto i : block->block()->elements()) { debug_ast(i, ind + " ", env); }
+  } else if (dynamic_cast<Definition*>(node)) {
+    Definition* block = dynamic_cast<Definition*>(node);
+    cerr << ind << "Definition " << block << " " << block->tabs() << endl;
+    if (block->block()) for(auto i : block->block()->elements()) { debug_ast(i, ind + " ", env); }
+  } else if (dynamic_cast<Mixin_Call*>(node)) {
+    Mixin_Call* block = dynamic_cast<Mixin_Call*>(node);
+    cerr << ind << "Mixin_Call " << block << " " << block->tabs() << endl;
+    if (block->block()) for(auto i : block->block()->elements()) { debug_ast(i, ind + " ", env); }
+  } else if (dynamic_cast<Ruleset*>(node)) {
+    Ruleset* ruleset = dynamic_cast<Ruleset*>(node);
+    cerr << ind << "Ruleset " << ruleset << " " << ruleset->tabs() << endl;
+    debug_ast(ruleset->selector(), ind + " ");
+    if (ruleset->block()) for(auto i : ruleset->block()->elements()) { debug_ast(i, ind + " ", env); }
+  } else if (dynamic_cast<Block*>(node)) {
+    Block* block = dynamic_cast<Block*>(node);
+    cerr << ind << "Block " << block << " " << block->tabs() << endl;
+    for(auto i : block->elements()) { debug_ast(i, ind + " ", env); }
+  } else if (dynamic_cast<Textual*>(node)) {
+    Textual* expression = dynamic_cast<Textual*>(node);
+    cerr << ind << "Textual ";
+    if (expression->type() == Textual::NUMBER) cerr << " [NUMBER]";
+    else if (expression->type() == Textual::PERCENTAGE) cerr << " [PERCENTAGE]";
+    else if (expression->type() == Textual::DIMENSION) cerr << " [DIMENSION]";
+    else if (expression->type() == Textual::HEX) cerr << " [HEX]";
+    cerr << expression << " [" << expression->value() << "]" << endl;
+  } else if (dynamic_cast<Variable*>(node)) {
+    Variable* expression = dynamic_cast<Variable*>(node);
+    cerr << ind << "Variable " << expression << " [" << expression->name() << "]" << endl;
+    string name(expression->name());
+    if (env && env->has(name)) debug_ast(static_cast<Expression*>((*env)[name]), ind + " -> ", env);
+  } else if (dynamic_cast<Function_Call_Schema*>(node)) {
+    Function_Call_Schema* expression = dynamic_cast<Function_Call_Schema*>(node);
+    cerr << ind << "Function_Call_Schema " << expression << "]" << endl;
+    debug_ast(expression->name(), ind + "name: ", env);
+    debug_ast(expression->arguments(), ind + " args: ", env);
+  } else if (dynamic_cast<Function_Call*>(node)) {
+    Function_Call* expression = dynamic_cast<Function_Call*>(node);
+    cerr << ind << "Function_Call " << expression << " [" << expression->name() << "]" << endl;
+    debug_ast(expression->arguments(), ind + " args: ", env);
+  } else if (dynamic_cast<Arguments*>(node)) {
+    Arguments* expression = dynamic_cast<Arguments*>(node);
+    cerr << ind << "Arguments " << expression << "]" << endl;
+    for(auto i : expression->elements()) { debug_ast(i, ind + " ", env); }
+  } else if (dynamic_cast<Argument*>(node)) {
+    Argument* expression = dynamic_cast<Argument*>(node);
+    cerr << ind << "Argument " << expression << " [" << expression->value() << "]" << endl;
+    debug_ast(expression->value(), ind + " value: ", env);
+  } else if (dynamic_cast<Unary_Expression*>(node)) {
+    Unary_Expression* expression = dynamic_cast<Unary_Expression*>(node);
+    cerr << ind << "Unary_Expression " << expression << " [" << expression->type() << "]" << endl;
+    debug_ast(expression->operand(), ind + " operand: ", env);
+  } else if (dynamic_cast<Binary_Expression*>(node)) {
+    Binary_Expression* expression = dynamic_cast<Binary_Expression*>(node);
+    cerr << ind << "Binary_Expression " << expression << " [" << expression->type() << "]" << endl;
+    debug_ast(expression->left(), ind + " left:  ", env);
+    debug_ast(expression->right(), ind + " right: ", env);
+  } else if (dynamic_cast<Map*>(node)) {
+    Map* expression = dynamic_cast<Map*>(node);
+    cerr << ind << "Map " << expression << " [Hashed]" << endl;
+  } else if (dynamic_cast<List*>(node)) {
+    List* expression = dynamic_cast<List*>(node);
+    cerr << ind << "List " << expression << " (" << expression->length() << ") " <<
+      (expression->separator() == Sass::List::Separator::COMMA ? "Comma " : "Space ") <<
+      " [delayed: " << expression->is_delayed() << "] " <<
+      " [interpolant: " << expression->is_interpolant() << "] " <<
+      endl;
+    for(auto i : expression->elements()) { debug_ast(i, ind + " ", env); }
+  } else if (dynamic_cast<Content*>(node)) {
+    Content* expression = dynamic_cast<Content*>(node);
+    cerr << ind << "Content " << expression << " [Statement]" << endl;
+  } else if (dynamic_cast<Boolean*>(node)) {
+    Boolean* expression = dynamic_cast<Boolean*>(node);
+    cerr << ind << "Boolean " << expression << " [" << expression->value() << "]" << endl;
+  } else if (dynamic_cast<Color*>(node)) {
+    Color* expression = dynamic_cast<Color*>(node);
+    cerr << ind << "Color " << expression << " [" << expression->r() << ":"  << expression->g() << ":" << expression->b() << "@" << expression->a() << "]" << endl;
+  } else if (dynamic_cast<Number*>(node)) {
+    Number* expression = dynamic_cast<Number*>(node);
+    cerr << ind << "Number " << expression << " [" << expression->value() << expression->unit() << "]" << endl;
+  } else if (dynamic_cast<String_Quoted*>(node)) {
+    String_Quoted* expression = dynamic_cast<String_Quoted*>(node);
+    cerr << ind << "String_Quoted : " << expression << " [" << prettyprint(expression->value()) << "]" <<
+      (expression->is_delayed() ? " {delayed}" : "") <<
+      (expression->sass_fix_1291() ? " {sass_fix_1291}" : "") <<
+      (expression->quote_mark() != 0 ? " {qm:" + string(1, expression->quote_mark()) + "}" : "") <<
+      " <" << prettyprint(expression->pstate().token.ws_before()) << ">" << endl;
+  } else if (dynamic_cast<String_Constant*>(node)) {
+    String_Constant* expression = dynamic_cast<String_Constant*>(node);
+    cerr << ind << "String_Constant : " << expression << " [" << prettyprint(expression->value()) << "]" <<
+      (expression->is_delayed() ? " {delayed}" : "") <<
+      (expression->sass_fix_1291() ? " {sass_fix_1291}" : "") <<
+      " <" << prettyprint(expression->pstate().token.ws_before()) << ">" << endl;
+  } else if (dynamic_cast<String_Schema*>(node)) {
+    String_Schema* expression = dynamic_cast<String_Schema*>(node);
+    cerr << ind << "String_Schema " << expression << " " << expression->concrete_type() <<
+      (expression->has_interpolants() ? " {has_interpolants}" : "") <<
+      endl;
+    for(auto i : expression->elements()) { debug_ast(i, ind + " ", env); }
+  } else if (dynamic_cast<String*>(node)) {
+    String* expression = dynamic_cast<String*>(node);
+    cerr << ind << "String " << expression << expression->concrete_type() <<
+      " " << (expression->sass_fix_1291() ? "{sass_fix_1291}" : "") <<
+      endl;
+  } else if (dynamic_cast<Expression*>(node)) {
+    Expression* expression = dynamic_cast<Expression*>(node);
+    cerr << ind << "Expression " << expression;
+    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 << " " << has_block->tabs() << endl;
+    if (has_block->block()) for(auto i : has_block->block()->elements()) { debug_ast(i, ind + " ", env); }
+  } else if (dynamic_cast<Statement*>(node)) {
+    Statement* statement = dynamic_cast<Statement*>(node);
+    cerr << ind << "Statement " << statement << " " << statement->tabs() << endl;
+  }
+
+  if (ind == "") cerr << "####################################################################\n";
+}
+
+#endif // SASS_DEBUGGER
diff --git a/libsass/emitter.cpp b/libsass/emitter.cpp
new file mode 100644
--- /dev/null
+++ b/libsass/emitter.cpp
@@ -0,0 +1,255 @@
+#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_declaration_list(false)
+  { }
+
+  // return buffer as string
+  string Emitter::get_buffer(void)
+  {
+    return wbuf.buffer;
+  }
+
+  Output_Style Emitter::output_style(void)
+  {
+    return ctx ? ctx->output_style : COMPRESSED;
+  }
+
+  // PROXY METHODS FOR SOURCE MAPS
+
+  void Emitter::add_source_index(size_t idx)
+  { wbuf.smap.source_index.push_back(idx); }
+
+  string Emitter::generate_source_map(Context &ctx)
+  { return wbuf.smap.generate_source_map(ctx); }
+
+  void Emitter::set_filename(const string& str)
+  { wbuf.smap.file = str; }
+
+  void Emitter::add_open_mapping(AST_Node* node)
+  { wbuf.smap.add_open_mapping(node); }
+  void Emitter::add_close_mapping(AST_Node* node)
+  { wbuf.smap.add_close_mapping(node); }
+  ParserState Emitter::remap(const ParserState& pstate)
+  { return wbuf.smap.remap(pstate); }
+
+  // MAIN BUFFER MANIPULATION
+
+  // add outstanding delimiter
+  void Emitter::finalize(void)
+  {
+    scheduled_space = 0;
+    if (scheduled_linefeed)
+      scheduled_linefeed = 1;
+    flush_schedules();
+  }
+
+  // flush scheduled space/linefeed
+  void Emitter::flush_schedules(void)
+  {
+    // check the schedule
+    if (scheduled_linefeed) {
+      string linefeeds = "";
+
+      for (size_t i = 0; i < scheduled_linefeed; i++)
+        linefeeds += ctx ? ctx->linefeed : "\n";
+      scheduled_space = 0;
+      scheduled_linefeed = 0;
+      append_string(linefeeds);
+
+    } else if (scheduled_space) {
+      string spaces(scheduled_space, ' ');
+      scheduled_space = 0;
+      append_string(spaces);
+    }
+    if (scheduled_delimiter) {
+      scheduled_delimiter = false;
+      append_string(";");
+    }
+  }
+
+  // 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)) 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
new file mode 100644
--- /dev/null
+++ b/libsass/emitter.hpp
@@ -0,0 +1,83 @@
+#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:
+      bool in_comment;
+      bool in_wrapped;
+      bool in_media_block;
+      bool in_declaration;
+      bool in_declaration_list;
+
+    public:
+      // return buffer as string
+      string get_buffer(void);
+      // flush scheduled space/linefeed
+      Output_Style output_style(void);
+      // add outstanding linefeed
+      void finalize(void);
+      // flush scheduled space/linefeed
+      void flush_schedules(void);
+      // 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
new file mode 100644
--- /dev/null
+++ b/libsass/environment.hpp
@@ -0,0 +1,167 @@
+#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, bool global = false)
+    {
+      auto cur = this;
+      while (cur->is_lexical()) {
+        if (cur->has_local(key)) {
+          cur->set_local(key, val);
+          return;
+        }
+        cur = cur->parent_;
+      }
+      if (global) {
+        set_global(key, val);
+      } else {
+        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
new file mode 100644
--- /dev/null
+++ b/libsass/error_handling.cpp
@@ -0,0 +1,25 @@
+#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 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 += top.to_string();
+
+    throw Sass_Error(Sass_Error::syntax, pstate, msg);
+  }
+
+}
diff --git a/libsass/error_handling.hpp b/libsass/error_handling.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/error_handling.hpp
@@ -0,0 +1,29 @@
+#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 error(string msg, ParserState pstate);
+  void error(string msg, ParserState pstate, Backtrace* bt);
+
+}
+
+#endif
diff --git a/libsass/eval.cpp b/libsass/eval.cpp
new file mode 100644
--- /dev/null
+++ b/libsass/eval.cpp
@@ -0,0 +1,1288 @@
+#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"
+
+#include <cstdlib>
+#include <cmath>
+#include <iostream>
+#include <iomanip>
+#include <typeinfo>
+
+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()) {
+      env->set_global(var, a->value()->perform(this));
+    }
+    else if (a->is_default()) {
+      if (env->has_lexical(var)) return 0;
+      if (env->has_global(var)) {
+        Expression* e = static_cast<Expression*>(env->get_global(var));
+        if (e->concrete_type() == Expression::NULL_VAL) {
+          env->set_global(var, a->value()->perform(this));
+        }
+      } else {
+        env->set_global(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->get_local(variable);
+    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->get_local(variables[i]);
+      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));
+    }
+    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);
+    rhs->is_delayed(false);
+    while (typeid(*rhs) == typeid(Binary_Expression)) 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)
+  {
+    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)) {
+        value = new (ctx.mem) String_Constant(*str);
+      }
+    }
+    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)
+  {
+    // 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()) {
+        return string_escape(str_quoted->value());
+      } else {
+        return evacuate_escapes(str_quoted->value());
+      }
+    } else if (String_Constant* str_constant = dynamic_cast<String_Constant*>(s)) {
+      return evacuate_escapes(str_constant->value());
+    } else if (String_Schema* str_schema = dynamic_cast<String_Schema*>(s)) {
+      string res = "";
+      for(auto i : str_schema->elements())
+        res += (interpolation(i));
+      //ToDo: do this in one step
+      auto esc = evacuate_escapes(res);
+      auto unq = unquote(esc);
+      if (unq == esc) {
+        return string_to_output(res);
+      } else {
+        return evacuate_quotes(unq);
+      }
+    } else if (List* list = dynamic_cast<List*>(s)) {
+      string acc = ""; // ToDo: different output styles
+      string sep = list->separator() == List::Separator::COMMA ? "," : " ";
+      if (ctx.output_style != COMPRESSED && sep == ",") sep += " ";
+      bool initial = false;
+      for(auto item : list->elements()) {
+        if (initial) acc += sep;
+        acc += interpolation(item);
+        initial = true;
+      }
+      return evacuate_quotes(acc);
+    } else if (Variable* var = dynamic_cast<Variable*>(s)) {
+      string name(var->name());
+      if (!env->has(name)) 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)) {
+      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) {
+      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);
+    Expression* value = e->value();
+    value = (value ? value->perform(this) : 0);
+    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)
+  {
+    Selector* s = p->perform(contextualize);
+    // access to parent selector may return 0
+    Selector_List* l = static_cast<Selector_List*>(s);
+    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: {
+        Number* l = static_cast<Number*>(lhs);
+        Number* r = static_cast<Number*>(rhs);
+        Number tmp_r(*r);
+        tmp_r.normalize(l->find_convertible_unit());
+        return l->unit() == tmp_r.unit() && l->value() == tmp_r.value()
+               ? true
+               : false;
+      } 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: {
+        return unquote(static_cast<String_Constant*>(lhs)->value()) ==
+               unquote(static_cast<String_Constant*>(rhs)->value());
+      } 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();
+    }
+
+    v->value(ops[op](lv, tmp.value()));
+    if (op == Binary_Expression::MUL) {
+      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) {
+      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]);
+      }
+    }
+    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
new file mode 100644
--- /dev/null
+++ b/libsass/eval.hpp
@@ -0,0 +1,88 @@
+#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
new file mode 100644
--- /dev/null
+++ b/libsass/expand.cpp
@@ -0,0 +1,538 @@
+#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(at_root_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()) {
+      env->set_global(var, a->value()->perform(eval->with(p, env, backtrace)));
+    }
+    else if (a->is_default()) {
+      if (env->has_lexical(var)) return 0;
+      if (env->has_global(var)) {
+        Expression* e = static_cast<Expression*>(env->get_global(var));
+        if (e->concrete_type() == Expression::NULL_VAL) {
+          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_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->get_local(variable);
+    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->get_local(variables[i]);
+      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
new file mode 100644
--- /dev/null
+++ b/libsass/expand.hpp
@@ -0,0 +1,78 @@
+#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
new file mode 100644
--- /dev/null
+++ b/libsass/extend.cpp
@@ -0,0 +1,2010 @@
+#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
new file mode 100644
--- /dev/null
+++ b/libsass/extend.hpp
@@ -0,0 +1,45 @@
+#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
new file mode 100644
--- /dev/null
+++ b/libsass/file.cpp
@@ -0,0 +1,349 @@
+#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
new file mode 100644
--- /dev/null
+++ b/libsass/file.hpp
@@ -0,0 +1,60 @@
+#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
new file mode 100644
--- /dev/null
+++ b/libsass/functions.cpp
@@ -0,0 +1,1567 @@
+#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::floor(w1*color1->r() + w2*color2->r()),
+                                 std::floor(w1*color1->g() + w2*color2->g()),
+                                 std::floor(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 / (2.0 * l);
+        else         s = del / (2.0 - 2.0 * l);
+
+        if      (r == max) h = 60 * (g - b) / del;
+        else if (g == max) h = 60 * (b - r) / del + 120;
+        else if (b == max) h = 60 * (r - g) / del + 240;
+      }
+
+      HSL hsl_struct;
+      hsl_struct.h = h;
+      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;
+
+      // Algorithm from the CSS3 spec: http://www.w3.org/TR/css3-color/#hsl-color.
+      double m2;
+      if (l <= 0.5) m2 = l*(s+1.0);
+      else m2 = (l+s)-(l*s);
+      double m1 = (l*2)-m2;
+      // 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)
+    {
+      To_String to_string(&ctx);
+      AST_Node* arg = env["$string"];
+      if (String_Quoted* string_quoted = dynamic_cast<String_Quoted*>(arg)) {
+        String_Constant* result = new (ctx.mem) String_Constant(pstate, string_quoted->value());
+        // remember if the string was quoted (color tokens)
+        result->sass_fix_1291(string_quoted->quote_mark() != 0);
+        return result;
+      }
+      return new (ctx.mem) String_Constant(pstate, string(arg->perform(&to_string)));
+    }
+
+    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);
+        Number* n = ARG("$start-at", Number);
+        Number* m = ARG("$end-at", Number);
+
+        string str = unquote(s->value());
+
+        // normalize into 0-based indices
+        size_t start = UTF_8::offset_at_position(str, UTF_8::normalize_index(static_cast<int>(n->value()), UTF_8::code_point_count(str)));
+        size_t end = UTF_8::offset_at_position(str, UTF_8::normalize_index(static_cast<int>(m->value()), UTF_8::code_point_count(str)));
+
+        // `str-slice` should always return an empty string when $end-at == 0
+        // `normalize_index` normalizes 1 -> 0 so we need to check the original value
+        if(m->value() == 0) {
+          if (String_Quoted* ss = dynamic_cast<String_Quoted*>(s)) {
+            if(!ss->quote_mark()) return new (ctx.mem) Null(pstate);
+          } else {
+            return new (ctx.mem) Null(pstate);
+          }
+          newstr = "";
+        } else if(start == end && m->value() != 0) {
+          newstr = str.substr(start, 1);
+        } else if(end > start) {
+          newstr = str.substr(start, end - start + UTF_8::code_point_size_at_offset(str, end));
+        }
+        if (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 && trunc(l->value()) != l->value()) error("argument $limit of `" + string(sig) + "` must be an integer", pstate);
+      if (l) {
+        uniform_real_distribution<> distributor(1, l->value() + 1);
+        uint_fast32_t distributed = static_cast<uint_fast32_t>(distributor(rand));
+        return new (ctx.mem) Number(pstate, (double)distributed);
+      }
+      else {
+        uniform_real_distribution<> distributor(0, 1);
+        uint_fast32_t distributed = static_cast<uint_fast32_t>(distributor(rand));
+        return new (ctx.mem) Number(pstate, trunc(distributed));
+     }
+    }
+
+    /////////////////
+    // 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->length() : 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;
+      *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 compact_sig = "compact($values...)";
+    BUILT_IN(compact)
+    {
+      error("`compact` has been removed from libsass because it's not part of the Sass spec", pstate);
+      return 0; // suppress warning, error will exit anyway
+    }
+
+    Signature list_separator_sig = "list_separator($list)";
+    BUILT_IN(list_separator)
+    {
+      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);
+      // The parser ensures the ordering of arguments so we can assert this
+      // isn't keyword argument list the first argument isn't a keyword argument
+      if (!(arglist->empty() || ((Argument*)(*arglist)[0])->is_keyword_argument())) return result;
+      for (size_t i = 0, L = arglist->length(); i < L; ++i) {
+        string name = string(((Argument*)(*arglist)[i])->name());
+        string sanitized_name = string(name, 1);
+        *result << make_pair(new (ctx.mem) String_Constant(pstate, sanitized_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*>(expr);
+          *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 {
+        Output_Style old_style;
+        old_style = ctx.output_style;
+        ctx.output_style = NESTED;
+        To_String to_string(&ctx);
+        string inspect = v->perform(&to_string);
+        ctx.output_style = old_style;
+        return new (ctx.mem) String_Constant(pstate, inspect);
+
+
+      }
+      // return v;
+    }
+
+    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
new file mode 100644
--- /dev/null
+++ b/libsass/functions.hpp
@@ -0,0 +1,184 @@
+#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 compact_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;
+
+    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(compact);
+    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);
+
+  }
+}
+
+#endif
diff --git a/libsass/inspect.cpp b/libsass/inspect.cpp
new file mode 100644
--- /dev/null
+++ b/libsass/inspect.cpp
@@ -0,0 +1,866 @@
+#include "inspect.hpp"
+#include "ast.hpp"
+#include "context.hpp"
+#include "utf8/checked.h"
+#include <cmath>
+#include <string>
+#include <iostream>
+#include <iomanip>
+#include <stdint.h>
+#include <stdint.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();
+      in_wrapped = true;
+      at_rule->selector()->perform(this);
+      in_wrapped = false;
+    }
+    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;
+    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 = false;
+  }
+
+  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;
+    in_declaration_list = in_declaration;
+    for (size_t i = 0, L = list->length(); 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_declaration_list = false;
+  }
+
+  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)
+  {
+    stringstream ss;
+    ss.precision(ctx ? ctx->precision : 5);
+    ss << fixed << n->value();
+    string d(ss.str());
+    // store if the value did not equal zero
+    // if after applying precsision, the value gets
+    // truncated to zero, sass emits 0.0 instead of 0
+    bool nonzero = n->value() != 0;
+    for (size_t i = d.length()-1; d[i] == '0'; --i) {
+      d.resize(d.length()-1);
+    }
+    if (d[d.length()-1] == '.') d.resize(d.length()-1);
+    if (n->numerator_units().size() > 1 ||
+        n->denominator_units().size() > 0 ||
+        (n->numerator_units().size() && n->numerator_units()[0].find_first_of('/') != string::npos) ||
+        (n->numerator_units().size() && n->numerator_units()[0].find_first_of('*') != string::npos)
+    ) {
+      error(d + n->unit() + " isn't a valid CSS value.", n->pstate());
+    }
+    if (!n->zero() && !in_declaration_list) {
+      if (d.substr(0, 3) == "-0.") d.erase(1, 1);
+      if (d.substr(0, 2) == "0.") d.erase(0, 1);
+    }
+    // remove the leading minus
+    if (d == "-0") d.erase(0, 1);
+    // use fractional output if we had
+    // a value before it got truncated
+    if (d == "0" && nonzero) d = "0.0";
+    // append number and unit
+    append_token(d + n->unit(), n);
+  }
+
+  // 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()), 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
new file mode 100644
--- /dev/null
+++ b/libsass/inspect.hpp
@@ -0,0 +1,98 @@
+#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
new file mode 100644
--- /dev/null
+++ b/libsass/json.cpp
@@ -0,0 +1,1411 @@
+/*
+  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.
+ */
+
+/*
+ * Type for Unicode codepoints.
+ * We need our own because wchar_t might be 16 bits.
+ */
+typedef uint32_t uchar_t;
+
+/*
+ * Validate a single UTF-8 character starting at @s.
+ * 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, uchar_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 = ((uchar_t)c[0] & 0x1F) << 6 |
+           ((uchar_t)c[1] & 0x3F);
+    return 2;
+  } else if (c[0] <= 0xEF) {
+    /* E0..EF */
+    *out = ((uchar_t)c[0] &  0xF) << 12 |
+           ((uchar_t)c[1] & 0x3F) << 6  |
+           ((uchar_t)c[2] & 0x3F);
+    return 3;
+  } else {
+    /* F0..F4 (unless input is invalid) */
+    *out = ((uchar_t)c[0] &  0x7) << 18 |
+           ((uchar_t)c[1] & 0x3F) << 12 |
+           ((uchar_t)c[2] & 0x3F) << 6  |
+           ((uchar_t)c[3] & 0x3F);
+    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(uchar_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, uchar_t *unicode)
+{
+  if (uc >= 0xD800 && uc <= 0xDBFF && lc >= 0xDC00 && lc <= 0xDFFF) {
+    *unicode = 0x10000 + ((((uchar_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(uchar_t unicode, uint16_t *uc, uint16_t *lc)
+{
+  uchar_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;
+          uchar_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
new file mode 100644
--- /dev/null
+++ b/libsass/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/kwd_arg_macros.hpp b/libsass/kwd_arg_macros.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/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/lexer.cpp b/libsass/lexer.cpp
new file mode 100644
--- /dev/null
+++ b/libsass/lexer.cpp
@@ -0,0 +1,133 @@
+#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
+    //####################################
+
+    const bool is_alpha(const char& chr)
+    {
+      return unsigned(chr - 'A') <= 'Z' - 'A' ||
+             unsigned(chr - 'a') <= 'z' - 'a';
+    }
+
+    const bool is_space(const char& chr)
+    {
+      // adapted the technique from is_alpha
+      return chr == ' ' || unsigned(chr - '\t') <= '\r' - '\t';
+    }
+
+    const bool is_digit(const char& chr)
+    {
+      // adapted the technique from is_alpha
+      return unsigned(chr - '0') <= '9' - '0';
+    }
+
+    const 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';
+    }
+
+    const bool is_punct(const char& chr)
+    {
+      // locale independent
+      return chr == '.';
+    }
+
+    const bool is_alnum(const char& chr)
+    {
+      return is_alpha(chr) || is_digit(chr);
+    }
+
+    // check if char is outside ascii range
+    const bool is_unicode(const char& chr)
+    {
+      // check for unicode range
+      return unsigned(chr) > 127;
+    }
+
+    // Match word character (look ahead)
+    const 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
new file mode 100644
--- /dev/null
+++ b/libsass/lexer.hpp
@@ -0,0 +1,239 @@
+#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
+    const bool is_space(const char& src);
+    const bool is_alpha(const char& src);
+    const bool is_punct(const char& src);
+    const bool is_digit(const char& src);
+    const bool is_alnum(const char& src);
+    const bool is_xdigit(const char& src);
+    const bool is_unicode(const char& src);
+    const bool is_character(const char& src);
+
+    // 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
new file mode 100644
--- /dev/null
+++ b/libsass/listize.cpp
@@ -0,0 +1,83 @@
+#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
new file mode 100644
--- /dev/null
+++ b/libsass/listize.hpp
@@ -0,0 +1,41 @@
+#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
new file mode 100644
--- /dev/null
+++ b/libsass/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/memory_manager.hpp b/libsass/memory_manager.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/memory_manager.hpp
@@ -0,0 +1,57 @@
+#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
new file mode 100644
--- /dev/null
+++ b/libsass/node.cpp
@@ -0,0 +1,251 @@
+#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
new file mode 100644
--- /dev/null
+++ b/libsass/node.hpp
@@ -0,0 +1,121 @@
+#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
new file mode 100644
--- /dev/null
+++ b/libsass/operation.hpp
@@ -0,0 +1,166 @@
+#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
new file mode 100644
--- /dev/null
+++ b/libsass/output.cpp
@@ -0,0 +1,400 @@
+#include "ast.hpp"
+#include "output.hpp"
+#include "to_string.hpp"
+
+namespace Sass {
+  using namespace std;
+
+  Output::Output(Context* ctx)
+  : Inspect(Emitter(ctx)),
+    charset(""),
+    top_imports(0),
+    top_comments(0)
+  {}
+
+  Output::~Output() { }
+
+  void Output::fallback_impl(AST_Node* n)
+  {
+    return n->perform(this);
+  }
+
+  void Output::operator()(Import* imp)
+  {
+    top_imports.push_back(imp);
+  }
+
+  OutputBuffer Output::get_buffer(void)
+  {
+
+    Emitter emitter(ctx);
+    Inspect inspect(emitter);
+
+    size_t size_com = top_comments.size();
+    for (size_t i = 0; i < size_com; i++) {
+      top_comments[i]->perform(&inspect);
+      inspect.append_mandatory_linefeed();
+    }
+
+    size_t size_imp = top_imports.size();
+    for (size_t i = 0; i < size_imp; i++) {
+      top_imports[i]->perform(&inspect);
+      inspect.append_mandatory_linefeed();
+    }
+
+    // flush scheduled outputs
+    inspect.finalize();
+    // 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() + top_imports.size() == 0) {
+        top_comments.push_back(c);
+      } else {
+        in_comment = true;
+        append_indentation();
+        c->text()->perform(this);
+        in_comment = false;
+        if (indentation == 0) {
+          append_mandatory_linefeed();
+        } else {
+          append_optional_linefeed();
+        }
+      }
+    }
+  }
+
+  void Output::operator()(Ruleset* r)
+  {
+    Selector* s     = r->selector();
+    Block*    b     = r->block();
+    bool      decls = false;
+
+    // Filter out rulesets that aren't printable (process its children though)
+    if (!Util::isPrintable(r, output_style())) {
+      for (size_t i = 0, L = b->length(); i < L; ++i) {
+        Statement* stm = (*b)[i];
+        if (dynamic_cast<Has_Block*>(stm)) {
+          stm->perform(this);
+        }
+      }
+      return;
+    }
+
+    if (b->has_non_hoistable()) {
+      decls = true;
+      if (output_style() == NESTED) indentation += r->tabs();
+      if (ctx && ctx->source_comments) {
+        stringstream ss;
+        append_indentation();
+        ss << "/* line " << r->pstate().line+1 << ", " << r->pstate().path << " */";
+        append_string(ss.str());
+        append_optional_linefeed();
+      }
+      s->perform(this);
+      append_scope_opener(b);
+      for (size_t i = 0, L = b->length(); i < L; ++i) {
+        Statement* stm = (*b)[i];
+        bool bPrintExpression = true;
+        // Check print conditions
+        if (typeid(*stm) == typeid(Declaration)) {
+          Declaration* dec = static_cast<Declaration*>(stm);
+          if (dec->value()->concrete_type() == Expression::STRING) {
+            String_Constant* valConst = static_cast<String_Constant*>(dec->value());
+            string val(valConst->value());
+            if (dynamic_cast<String_Quoted*>(valConst)) {
+              if (!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();
+
+    for (size_t i = 0, L = b->length(); i < L; ++i) {
+      Statement* stm = (*b)[i];
+      if (!stm->is_hoistable()) {
+        stm->perform(this);
+        if (i < L - 1) append_special_linefeed();
+      }
+    }
+
+    for (size_t i = 0, L = b->length(); i < L; ++i) {
+      Statement* stm = (*b)[i];
+      if (stm->is_hoistable()) {
+        stm->perform(this);
+        if (i < L - 1) append_special_linefeed();
+      }
+    }
+
+    append_scope_closer();
+  }
+
+  void Output::operator()(String_Quoted* s)
+  {
+    if (s->quote_mark()) {
+      append_token(quote(s->value(), s->quote_mark()), s);
+    } else if (!in_comment) {
+      append_token(string_to_output(s->value()), s);
+    } else {
+      append_token(s->value(), s);
+    }
+  }
+
+  void Output::operator()(String_Constant* s)
+  {
+    if (String_Quoted* quoted = dynamic_cast<String_Quoted*>(s)) {
+      return Output::operator()(quoted);
+    } else if (!in_comment) {
+      append_token(string_to_output(s->value()), s);
+    } else {
+      append_token(s->value(), s);
+    }
+  }
+
+}
diff --git a/libsass/output.hpp b/libsass/output.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/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;
+  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<Import*> top_imports;
+    vector<Comment*> top_comments;
+
+  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
new file mode 100644
--- /dev/null
+++ b/libsass/parser.cpp
@@ -0,0 +1,2228 @@
+#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;
+  }
+
+  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]);
+        }
+      }
+    }
+
+    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]);
+          }
+        }
+        if (!lex< one_plus< exactly<';'> > >()) error("top-level @import directive must be terminated by ';'", pstate);
+      }
+      else if (peek< kwd_mixin >() || peek< kwd_function >()) {
+        (*root) << parse_definition();
+      }
+      else if (peek< variable >()) {
+        (*root) << parse_assignment();
+        if (!lex< one_plus< exactly<';'> > >()) error("top-level variable binding must be terminated by ';'", pstate);
+      }
+      /*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() && !lex< one_plus< exactly<';'> > >()) error("top-level @include directive must be terminated by ';'", pstate);
+      }
+      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();
+        if (!lex< one_plus< exactly<';'> > >()) error("top-level @warn directive must be terminated by ';'", pstate);
+      }
+      else if (peek< kwd_err >()) {
+        (*root) << parse_error();
+        if (!lex< one_plus< exactly<';'> > >()) error("top-level @error directive must be terminated by ';'", pstate);
+      }
+      else if (peek< kwd_dbg >()) {
+        (*root) << parse_debug();
+        if (!lex< one_plus< exactly<';'> > >()) error("top-level @debug directive must be terminated by ';'", pstate);
+      }
+      // 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() && !lex< one_plus< exactly<';'> > >()) error("top-level directive must be terminated by ';'", pstate);
+      }
+      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);
+      }
+      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 < uri_value >()) { // chunk seems to work too!
+          String* the_url = 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 = 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;
+    lex < css_comments >();
+    in_at_root = false;
+    ParserState r_source_position = pstate;
+    if (!peek< exactly<'{'> >()) error("expected a '{' after the selector", pstate);
+    Block* block = parse_block();
+    in_at_root = old_in_at_root;
+    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
+        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< 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 (peek< binomial >(position)) {
+        lex< sequence< optional< coefficient >, exactly<'n'> > >();
+        String_Constant* var_coef = new (ctx.mem) String_Quoted(p, lexed);
+        lex< sign >();
+        String_Constant* op = new (ctx.mem) String_Quoted(p, lexed);
+        // Binary_Expression::Type op = (lexed == "+" ? Binary_Expression::ADD : Binary_Expression::SUB);
+        lex< one_plus < digit > >();
+        String_Constant* constant = new (ctx.mem) String_Quoted(p, lexed);
+        // expr = new (ctx.mem) Binary_Expression(p, op, var_coef, constant);
+        String_Schema* schema = new (ctx.mem) String_Schema(p, 3);
+        *schema << var_coef << op << constant;
+        expr = schema;
+      }
+      else if (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* list_ex = parse_list();
+      if (List* list = dynamic_cast<List*>(list_ex)) {
+        if (list->length() == 0 && !peek< exactly <'{'> >()) {
+          css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
+        }
+      }
+      return new (ctx.mem) Declaration(prop->pstate(), prop, list_ex/*, 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()
+  {
+    To_String to_string(&ctx);
+    Expression* key = parse_list();
+
+    // 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(pstate, 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 (!(lex< exactly<':'> >()))
+      { error("invalid syntax", pstate); }
+
+      Expression* value = parse_space_list();
+
+      (*map) << make_pair(key, value);
+    }
+
+    if (map->has_duplicate_key())
+    { error("Duplicate key \"" + map->get_duplicate_key()->perform(&to_string) + "\" in map " + map->perform(&to_string) + ".", pstate); }
+
+    return map;
+  }
+
+  Expression* Parser::parse_list()
+  {
+    return parse_comma_list();
+  }
+
+  Expression* Parser::parse_comma_list()
+  {
+    if (peek< 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< exactly<','> >(position)) return list1;
+
+    List* comma_list = new (ctx.mem) List(pstate, 2, List::COMMA);
+    (*comma_list) << list1;
+
+    while (lex< exactly<','> >())
+    {
+      if (peek< 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< 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< alternatives <
+               // exactly<'!'>,
+               exactly<';'>,
+               exactly<'}'>,
+               exactly<'{'>,
+               exactly<')'>,
+               exactly<','>,
+               exactly<':'>,
+               exactly<ellipsis>,
+               default_flag,
+               global_flag
+           > >(position))
+    ) {
+      (*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;
+    // 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< exactly<'('> >()) {
+      Expression* value = parse_map();
+      if (!lex< 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
+        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_value()
+  {
+    lex< static_value >();
+    Token str(lexed);
+    --str.end;
+    --position;
+    String_Constant* str_node = new (ctx.mem) String_Constant(pstate, str);
+    // 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);
+      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) {
+          (*schema) << new (ctx.mem) String_Constant(pstate, string(i, p)); // accumulate the preceding segment if it's nonempty
+        }
+        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) << new (ctx.mem) String_Constant(pstate, string(i, str.end));
+        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_Quoted(pstate, lexed);
+    }
+    lex< exactly<'='> >();
+    *kwd_arg << new (ctx.mem) String_Quoted(pstate, lexed);
+    if (peek< variable >()) *kwd_arg << parse_list();
+    else if (lex< number >()) *kwd_arg << new (ctx.mem) Textual(pstate, Textual::NUMBER, Util::normalize_decimals(lexed));
+    else if (lex< alternatives< identifier_schema, identifier, number, hexa, hex > >()) {
+      *kwd_arg << new (ctx.mem) String_Quoted(pstate, lexed);
+    }
+    return kwd_arg;
+  }
+
+  String_Schema* Parser::parse_value_schema(const char* stop)
+  {
+    String_Schema* schema = new (ctx.mem) String_Schema(pstate);
+    size_t num_items = 0;
+    while (position < stop) {
+      if (lex< interpolant >()) {
+        Token insides(Token(lexed.begin + 2, lexed.end - 1));
+        Expression* interp_node = Parser::from_token(insides, ctx, pstate).parse_list();
+        interp_node->is_interpolant(true);
+        (*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 >()) {
+        (*schema) << new (ctx.mem) Textual(pstate, Textual::NUMBER, lexed);
+      }
+      else if (lex< hex >()) {
+        (*schema) << new (ctx.mem) Textual(pstate, Textual::HEX, unquote(lexed));
+      }
+      else if (lex< quoted_string >()) {
+        (*schema) << new (ctx.mem) String_Constant(pstate, lexed);
+      }
+      else if (lex< variable >()) {
+        (*schema) << new (ctx.mem) Variable(pstate, Util::normalize_underscores(lexed));
+      }
+      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
+        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);
+    Arguments* args = parse_arguments(name == "url");
+    return new (ctx.mem) Function_Call(pstate, 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< 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;
+  }
+
+  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;
+      }
+      if (*pos_left == '\r') break;
+      if (*pos_left == '\n') break;
+      -- pos_left;
+    }
+    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;
+      ++ 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
new file mode 100644
--- /dev/null
+++ b/libsass/parser.hpp
@@ -0,0 +1,280 @@
+#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("[NULL]"), 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]"));
+
+#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()
+    {
+      // throw away comments
+      // update srcmap position
+      lex < css_comments >();
+      // now lex a token
+      return lex< mx >();
+    }
+
+    // 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_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();
+    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_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
new file mode 100644
--- /dev/null
+++ b/libsass/paths.hpp
@@ -0,0 +1,74 @@
+#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
new file mode 100644
--- /dev/null
+++ b/libsass/plugins.cpp
@@ -0,0 +1,168 @@
+#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
new file mode 100644
--- /dev/null
+++ b/libsass/plugins.hpp
@@ -0,0 +1,58 @@
+#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
new file mode 100644
--- /dev/null
+++ b/libsass/position.cpp
@@ -0,0 +1,163 @@
+#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
new file mode 100644
--- /dev/null
+++ b/libsass/position.hpp
@@ -0,0 +1,120 @@
+#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); }
+
+    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; };
+
+    public:
+      string path;
+      const char* src;
+      Offset offset;
+      Token token;
+
+  };
+
+}
+
+#endif
diff --git a/libsass/posix/getopt.c b/libsass/posix/getopt.c
new file mode 100644
--- /dev/null
+++ b/libsass/posix/getopt.c
@@ -0,0 +1,562 @@
+/*	$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
new file mode 100644
--- /dev/null
+++ b/libsass/posix/getopt.h
@@ -0,0 +1,95 @@
+#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
new file mode 100644
--- /dev/null
+++ b/libsass/prelexer.cpp
@@ -0,0 +1,724 @@
+#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 all escaped chars first
+            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 all escaped chars first
+            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
+      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>, delimited_by< '(', ')', true> >(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(const char* src) {
+      return sequence<
+        alternatives< variable, identifier_schema, identifier >,
+        optional_css_whitespace,
+        exactly<'='>,
+        optional_css_whitespace,
+        alternatives< variable, identifier_schema, identifier, quoted_string, number, hexa >
+      >(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< static_component,
+                       zero_plus < sequence<
+                                   alternatives<
+                                     sequence< optional_spaces, alternatives<
+                                       exactly < '/' >,
+                                       exactly < ',' >,
+                                       exactly < ' ' >
+                                     >, optional_spaces >,
+                                     spaces
+                                   >,
+                                   static_component
+                       > >,
+                       alternatives< exactly<';'>, exactly<'}'> >
+                      >(src);
+    }
+  }
+}
diff --git a/libsass/prelexer.hpp b/libsass/prelexer.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/prelexer.hpp
@@ -0,0 +1,360 @@
+#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 = 0) {
+
+      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 (start(src)) {
+          ++ level; // increase counter
+        }
+
+        // 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;
+        }
+
+        // next
+        ++ src;
+      }
+
+      return 0;
+    }
+
+    // Match a sequence of characters delimited by the supplied chars.
+    template <prelexer start, prelexer stop>
+    const char* recursive_scopes(const char* src) {
+      // parse opener
+      src = start(src);
+      // abort if not found
+      if (!src) return 0;
+      // parse the rest until final closer
+      return skip_over_scopes<start, stop>(src);
+    }
+
+    // Match a sequence of characters delimited by the supplied strings.
+    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);
+
+    // 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
new file mode 100644
--- /dev/null
+++ b/libsass/remove_placeholders.cpp
@@ -0,0 +1,59 @@
+#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
new file mode 100644
--- /dev/null
+++ b/libsass/remove_placeholders.hpp
@@ -0,0 +1,43 @@
+#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
new file mode 100644
--- /dev/null
+++ b/libsass/sass.cpp
@@ -0,0 +1,43 @@
+#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
new file mode 100644
--- /dev/null
+++ b/libsass/sass.h
@@ -0,0 +1,68 @@
+#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
new file mode 100644
--- /dev/null
+++ b/libsass/sass2scss.cpp
@@ -0,0 +1,835 @@
+// 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
new file mode 100644
--- /dev/null
+++ b/libsass/sass2scss.h
@@ -0,0 +1,115 @@
+#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
new file mode 100644
--- /dev/null
+++ b/libsass/sass_context.cpp
@@ -0,0 +1,894 @@
+#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
new file mode 100644
--- /dev/null
+++ b/libsass/sass_context.h
@@ -0,0 +1,149 @@
+#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
new file mode 100644
--- /dev/null
+++ b/libsass/sass_functions.cpp
@@ -0,0 +1,173 @@
+#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
new file mode 100644
--- /dev/null
+++ b/libsass/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.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
new file mode 100644
--- /dev/null
+++ b/libsass/sass_interface.cpp
@@ -0,0 +1,287 @@
+#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
new file mode 100644
--- /dev/null
+++ b/libsass/sass_interface.h
@@ -0,0 +1,102 @@
+#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
new file mode 100644
--- /dev/null
+++ b/libsass/sass_util.cpp
@@ -0,0 +1,132 @@
+#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
new file mode 100644
--- /dev/null
+++ b/libsass/sass_util.hpp
@@ -0,0 +1,260 @@
+#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
new file mode 100644
--- /dev/null
+++ b/libsass/sass_values.cpp
@@ -0,0 +1,339 @@
+#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;
+    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; }
+
+  // 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.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
new file mode 100644
--- /dev/null
+++ b/libsass/sass_values.h
@@ -0,0 +1,124 @@
+#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);
+
+// 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_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
new file mode 100644
--- /dev/null
+++ b/libsass/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/source_map.cpp b/libsass/source_map.cpp
new file mode 100644
--- /dev/null
+++ b/libsass/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 {
+  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
new file mode 100644
--- /dev/null
+++ b/libsass/source_map.hpp
@@ -0,0 +1,65 @@
+#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/subset_map.hpp b/libsass/subset_map.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/subset_map.hpp
@@ -0,0 +1,147 @@
+#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
new file mode 100644
--- /dev/null
+++ b/libsass/to_c.cpp
@@ -0,0 +1,61 @@
+#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
new file mode 100644
--- /dev/null
+++ b/libsass/to_c.hpp
@@ -0,0 +1,44 @@
+#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
new file mode 100644
--- /dev/null
+++ b/libsass/to_string.cpp
@@ -0,0 +1,34 @@
+#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)
+  : ctx(ctx) { }
+  To_String::~To_String() { }
+
+  inline string To_String::fallback_impl(AST_Node* n)
+  {
+    Emitter emitter(ctx);
+    Inspect i(emitter);
+    i.in_declaration_list = true;
+    n->perform(&i);
+    return i.get_buffer();
+  }
+
+  inline string To_String::operator()(String_Constant* s)
+  {
+    return s->value();
+  }
+
+  inline string To_String::operator()(Null* n)
+  { return ""; }
+}
diff --git a/libsass/to_string.hpp b/libsass/to_string.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/to_string.hpp
@@ -0,0 +1,34 @@
+#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;
+
+  public:
+    To_String(Context* ctx = 0);
+    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
new file mode 100644
--- /dev/null
+++ b/libsass/units.cpp
@@ -0,0 +1,55 @@
+#include "units.hpp"
+
+#define PI 3.14159265358979323846
+
+namespace Sass {
+
+  double conversion_factors[10][10] = {
+             /*  in         cm         pc         mm         pt         px                 deg        grad       rad        turn      */
+    /* in   */ { 1,         2.54,      6,         25.4,      72,        96,                1,         1,         1,         1         },
+    /* cm   */ { 1.0/2.54,  1,         6.0/2.54,  10,        72.0/2.54, 96.0/2.54,         1,         1,         1,         1         },
+    /* pc   */ { 1.0/6.0,   2.54/6.0,  1,         25.4/6.0,  72.0/6.0,  96.0/6.0,          1,         1,         1,         1         },
+    /* mm   */ { 1.0/25.4,  1.0/10.0,  6.0/25.4,  1,         72.0/25.4, 96.0/25.4,         1,         1,         1,         1         },
+    /* pt   */ { 1.0/72.0,  2.54/72.0, 6.0/72.0,  25.4/72.0, 1,         96.0/72.0,         1,         1,         1,         1         },
+    /* px   */ { 1.0/96.0,  2.54/96.0, 6.0/96.0,  25.4/96.0, 72.0/96.0, 1,                 1,         1,         1,         1         },
+    /* deg  */ { 1       ,  1        , 1       ,  1        , 1        , 1,                 1,         40.0/36.0, PI/180.0,  1.0/360.0 },
+    /* grad */ { 1       ,  1        , 1       ,  1        , 1        , 1,                 36.0/40.0, 1,         PI/200.0,  1.0/400.0 },
+    /* rad  */ { 1       ,  1        , 1       ,  1        , 1        , 1,                 180.0/PI,  200.0/PI,  1,         PI/2.0    },
+    /* turn */ { 1       ,  1        , 1       ,  1        , 1        , 1,                 360.0/1.0, 400.0/1.0, 2.0*PI,    1         }
+  };
+
+  Unit string_to_unit(const string& s)
+  {
+    if      (s == "in") return IN;
+    else if (s == "cm") return CM;
+    else if (s == "pc") return PC;
+    else if (s == "mm") return MM;
+    else if (s == "pt") return PT;
+    else if (s == "px") return PX;
+    else if (s == "deg") return DEG;
+    else if (s == "grad") return GRAD;
+    else if (s == "rad") return RAD;
+    else if (s == "turn") return TURN;
+    else                return INCOMMENSURABLE;
+  }
+
+  double conversion_factor(const string& s1, const string& s2)
+  {
+    Unit u1 = string_to_unit(s1);
+    Unit u2 = string_to_unit(s2);
+    double factor;
+    if (u1 == INCOMMENSURABLE || u2 == INCOMMENSURABLE)
+      factor = 0;
+    else
+      factor = conversion_factors[u1][u2];
+    return factor;
+  }
+
+  /* not used anymore - remove?
+  double convert(double n, const string& from, const string& to)
+  {
+    double factor = conversion_factor(from, to);
+    return factor ? factor * n : n;
+  } */
+
+}
diff --git a/libsass/units.hpp b/libsass/units.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/units.hpp
@@ -0,0 +1,15 @@
+#ifndef SASS_UNITS_H
+#define SASS_UNITS_H
+
+#include <string>
+
+namespace Sass {
+  using namespace std;
+  enum Unit { IN, CM, PC, MM, PT, PX, DEG, GRAD, RAD, TURN, INCOMMENSURABLE };
+  extern double conversion_factors[10][10];
+  Unit string_to_unit(const string&);
+  double conversion_factor(const string&, const string&);
+  // double convert(double, const string&, const string&);
+}
+
+#endif
diff --git a/libsass/utf8.h b/libsass/utf8.h
new file mode 100644
--- /dev/null
+++ b/libsass/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/utf8/checked.h b/libsass/utf8/checked.h
new file mode 100644
--- /dev/null
+++ b/libsass/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/utf8/core.h b/libsass/utf8/core.h
new file mode 100644
--- /dev/null
+++ b/libsass/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/utf8/unchecked.h b/libsass/utf8/unchecked.h
new file mode 100644
--- /dev/null
+++ b/libsass/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/utf8_string.cpp b/libsass/utf8_string.cpp
new file mode 100644
--- /dev/null
+++ b/libsass/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/utf8_string.hpp b/libsass/utf8_string.hpp
new file mode 100644
--- /dev/null
+++ b/libsass/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 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
new file mode 100644
--- /dev/null
+++ b/libsass/util.cpp
@@ -0,0 +1,626 @@
+#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);
+  }
+
+  // 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;
+    bool clean = false;
+    for (auto i : text) {
+      if (clean) {
+        if (i == '\n') { has = 0; }
+        else if (i == '\r') { has = 0; }
+        else if (i == '\t') { ++ has; }
+        else if (i == ' ') { ++ has; }
+        else if (i == '*') {}
+        else {
+          clean = false;
+          str += ' ';
+          str += i;
+        }
+      } else if (i == '\n') {
+        clean = true;
+      } else if (i == '\r') {
+        clean = true;
+      } else {
+        str += i;
+      }
+    }
+    if (has) return str;
+    else return text;
+  }
+
+   string normalize_wspace(const string& str)
+  {
+    bool ws = false;
+    bool esc = false;
+    char inside_str = 0;
+    string text = "";
+    for(auto i : str) {
+      if (!esc && i == '\\') {
+        esc = true;
+        text += i;
+      } else if (esc) {
+        esc = false;
+        text += i;
+      } else if (!inside_str && (i == '"' || i == '\'')) {
+        inside_str = i;
+        text += i;
+      } else if (inside_str) {
+        if (i == inside_str)
+          inside_str = false;
+        text += i;
+      } else if (
+        i == ' ' ||
+        i == '\r' ||
+        i == '\n' ||
+        i == '	'
+      ) {
+        // only add one space
+        if (!ws) text += ' ';
+        ws = true;
+      } else {
+        ws = false;
+        text += i;
+      }
+    }
+    if (esc) text += '\\';
+    return text;
+  }
+
+  // find best quote_mark by detecting if the string contains any single
+  // or double quotes. When a single quote is found, we not we want a double
+  // quote as quote_mark. Otherwise we check if the string cotains any double
+  // quotes, which will trigger the use of single quotes as best quote_mark.
+  char detect_best_quotemark(const char* s, char qm)
+  {
+    // ensure valid fallback quote_mark
+    char quote_mark = qm && qm != '*' ? qm : '"';
+    while (*s) {
+      // force double quotes as soon
+      // as one single quote is found
+      if (*s == '\'') { return '"'; }
+      // a single does not force quote_mark
+      // maybe we see a double quote later
+      else if (*s == '"') { quote_mark = '\''; }
+      ++ s;
+    }
+    return quote_mark;
+  }
+
+  string unquote(const string& s, char* qd)
+  {
+
+    // not enough room for quotes
+    // no possibility to unquote
+    if (s.length() < 2) return s;
+
+    char q;
+    bool skipped = false;
+
+    // this is no guarantee that the unquoting will work
+    // what about whitespace before/after the quote_mark?
+    if      (*s.begin() == '"'  && *s.rbegin() == '"')  q = '"';
+    else if (*s.begin() == '\'' && *s.rbegin() == '\'') q = '\'';
+    else                                                return s;
+
+    string unq;
+    unq.reserve(s.length()-2);
+
+    for (size_t i = 1, L = s.length() - 1; i < L; ++i) {
+
+      // implement the same strange ruby sass behavior
+      // an escape sequence can also mean a unicode char
+      if (s[i] == '\\' && !skipped) {
+        // remember
+        skipped = true;
+
+        // skip it
+        // ++ i;
+
+        // if (i == L) break;
+
+        // escape length
+        size_t len = 1;
+
+        // parse as many sequence chars as possible
+        // ToDo: Check if ruby aborts after possible max
+        while (i + len < L && s[i + len] && isxdigit(s[i + len])) ++ len;
+
+        // hex string?
+        if (len > 1) {
+
+          // convert the extracted hex string to code point value
+          // ToDo: Maybe we could do this without creating a substring
+          uint32_t cp = strtol(s.substr (i + 1, len - 1).c_str(), nullptr, 16);
+
+          // assert invalid code points
+          if (cp == 0) cp = 0xFFFD;
+          // replace bell character
+          // if (cp == 10) cp = 32;
+
+          // use a very simple approach to convert via utf8 lib
+          // maybe there is a more elegant way; maybe we shoud
+          // convert the whole output from string to a stream!?
+          // allocate memory for utf8 char and convert to utf8
+          unsigned char u[5] = {0,0,0,0,0}; utf8::append(cp, u);
+          for(size_t m = 0; u[m] && m < 5; m++) unq.push_back(u[m]);
+
+          // skip some more chars?
+          i += len - 1; skipped = false;
+
+        }
+
+
+      }
+      // check for unexpected delimiter
+      // be strict and throw error back
+      else if (!skipped && q == s[i]) {
+        // don't be that strict
+        return s;
+        // this basically always means an internal error and not users fault
+        error("Unescaped delimiter in string to unquote found. [" + s + "]", ParserState("[UNQUOTE]"));
+      }
+      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)
+  {
+
+    // 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');
+      } 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 {
+          hasDeclarations = true;
+        }
+
+        if (hasDeclarations || hasPrintableChildBlocks) {
+          return true;
+        }
+      }
+
+      return false;
+    }
+
+    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
new file mode 100644
--- /dev/null
+++ b/libsass/util.hpp
@@ -0,0 +1,48 @@
+#ifndef SASS_UTIL_H
+#define SASS_UTIL_H
+
+#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 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);
+  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 isAscii(const char chr);
+
+  }
+}
+#endif
diff --git a/tests/Main.hs b/tests/Main.hs
new file mode 100644
--- /dev/null
+++ b/tests/Main.hs
@@ -0,0 +1,32 @@
+{-# LANGUAGE BangPatterns #-}
+import           Binding.Libsass
+import           Foreign
+import           Foreign.C
+import           Test.Hspec
+
+simpleCompile :: String -> IO String
+simpleCompile str = do
+    cstr <- newCString str
+    ctx <- sass_make_data_context cstr
+    status <- sass_compile_data_context ctx
+    if status /= 0
+        then do
+            sass_delete_data_context ctx
+            return ""
+        else do
+            cres <- sass_context_get_output_string (castPtr ctx)
+            !res <- peekCString cres
+            sass_delete_data_context ctx
+            return res
+
+sampleInput :: String
+sampleInput = "foo { margin: 21px * 2; }"
+
+sampleOutput :: String
+sampleOutput = "foo {\n  margin: 42px; }\n"
+
+main :: IO ()
+main = hspec $ do
+  describe "Libsass" $ do
+    it "should correctly compile simple expression" $ do
+      simpleCompile sampleInput `shouldReturn` sampleOutput
