 (def ^Character filter-close \})
 (def ^Character tag-second \%)
 
+(definterface INode
+  (render ^String [^clojure.lang.IPersistentMap context-map]))
+
+(deftype FunctionNode [^clojure.lang.IFn handler]
+  INode
+  (render ^String [this ^clojure.lang.IPersistentMap context-map]
+    (handler context-map)))
+
+(deftype TextNode [text]
+  INode
+  (render ^String [this ^clojure.lang.IPersistentMap context-map]
+    text))
+
 (def templates (atom {}))
 
 (declare parse expr-tag tag-content)
 
-(defn render [template args]
+(defn render [template context-map]
   (let [buf (StringBuilder.)]
-    (doseq [element template]
-      (.append buf (if (string? element) element (element args))))
+    (doseq [^INode element template]
+      (.append buf (.render element context-map)))
     (.toString buf)))
 
-(defn render-file [filename args]
+(defn render-file [filename context-map]
   (let [{:keys [template last-modified]} (get @templates filename)
-        last-modified-file (.lastModified (java.io.File. filename))]
+        last-modified-file (.lastModified ^java.io.File (java.io.File. filename))]
     (if (and last-modified (= last-modified last-modified-file))
-      (render template args)
+      (render template context-map)
       (let [template (parse filename)]
         (swap! templates assoc filename {:template template
                                          :last-modified last-modified-file})
-        (render template args)))))
+        (render template context-map)))))
 
-(defn read-char [rdr]
+(defn read-char [^java.io.Reader rdr]
   (let [ch (.read rdr)]
     (if-not (== -1 ch) (char ch))))
 

(ns selmer.parser
  (:require [selmer.filter-parser :refer [compile-filter-body]]))

(def ^Character tag-open \{)
(def ^Character tag-close \})

              (do
                ;we hit a tag so we append the buffer content to the template
                ; and empty the buffer, then we proceed to parse the tag
                (conj! template (TextNode. (.toString buf)))
                (.setLength buf 0)
                (conj! template (FunctionNode. (parse-tag (read-tag-info rdr) rdr)))
                (recur (read-char rdr)))
              (do
                ;default case, here we simply append the character and
