   and the engine together by handling the tokens and invoking
   the engine every time a full expression or text is received.
   """
-  def compile(source, options) do
-    line   = Keyword.get(options, :line, 1)
+  def compile(source, opts) do
+    file   = opts[:file] || "nofile"
+    line   = opts[:line] || 1
     tokens = EEx.Tokenizer.tokenize(source, line)
-    state  = EEx.State.new(options)
+    state  = %{engine: opts[:engine] || EEx.SmartEngine,
+               file: file, line: line, quoted: [], start_line: nil}
     generate_buffer(tokens, "", [], state)
   end
 


  # Changes placeholder to real expression

  defp insert_quotes({:__EEX__, _, [key]}, dict) do
    {^key, value} = List.keyfind dict, key, 0
    value
  end

  defp insert_quotes({left, line, right}, dict) do
    {insert_quotes(left, dict), line, insert_quotes(right, dict)}
  end

  defp insert_quotes({left, right}, dict) do
    {insert_quotes(left, dict), insert_quotes(right, dict)}
  end

  defp insert_quotes(list, dict) when is_list(list) do
    Enum.map list, &insert_quotes(&1, dict)
  end

  defp insert_quotes(other, _dict) do
    other
  end
end


  defp wrap_expr(current, line, buffer, chars, state) do
    new_lines = List.duplicate(?\n, line - state.line)
    key = length(state.quoted)
    placeholder = '__EEX__(' ++ integer_to_list(key) ++ ');'
    {current ++ placeholder ++ new_lines ++ chars,
     %{state | quoted: [{key, buffer}|state.quoted]}}
  end

  # Look text ahead on expressions
