       (nnode tag output))
     nil))
 
-;; atoms
-
-(defn -nl [token] (pattern token :nl :nl))
-(defn -is [token]
-  (pattern token #"is" :is (fn [x] [:is])))
-
-;; values
-
-(defn -value [token]
-  (def nodes (alternatives token [-string -integer -identifier]))
-  (if (> (count nodes) 0)
-    (nnode :value [(first nodes)])
-    nil))
-
-(defn -assignee [token] (pattern token #"[A-Za-z]+" :assignee))
-(defn -identifier [token] (pattern token #"(?!^is$)[A-Za-z]+" :identifier))
-(defn -integer [token]
-  (pattern token #"[0-9]+" :integer (fn [x] [(Integer/parseInt token)])))
-
-(defn -string [token]
-  (pattern token #"'[A-Za-z0-9 ]+'" :string (fn [x] [(str/replace token "'" "")])))
-
+(defn nnode [tag data]
+  {:tag tag :content data})

  (:use [isla.lexer])
  (:require [clojure.string :as str]))

(defn nnode [tag data]
  {:tag tag :content data})

(declare parse alternatives is-type pattern-sequence
         -root -block -expression -assignment -invocation
         -nl -integer -is -string -assignee -value -identifier)

(defn parse [code]
  (-root (lex code)))

(defn alternatives [input types] ;; bit round the houses
  (vec (map (fn [t] (t input)) ;; get nodes for each matching type
            (filter (fn [t] (not= nil (t input))) ;; get matching types
                    types))))

(defmulti is-type (fn [matcher token] (class matcher)))

(defmethod is-type clojure.lang.Keyword [symbol token]
  (= symbol token))

(defmethod is-type java.util.regex.Pattern [re token]
  (if (keyword? token)
    false
    (if (not= nil (re-matches re token))
      true
      false)))


(defn -root [tokens]
  (nnode :root [(-block tokens [])]))

      {:expr (nnode :invocation (take 2 nodes)) :left-tokens (nthrest tokens 3)}
      nil)))

;; atoms

(defn -nl [token] (pattern token :nl :nl))

(defn -is [token]
  (pattern token #"is" :is (fn [x] [:is])))

;; values

(defn -value [token]
  (def nodes (alternatives token [-string -integer -identifier]))
  (if (> (count nodes) 0)
    (nnode :value [(first nodes)])
    nil))

(defn -assignee [token] (pattern token #"[A-Za-z]+" :assignee))

(defn -identifier [token] (pattern token #"(?!^is$)[A-Za-z]+" :identifier))

(defn -integer [token]
  (pattern token #"[0-9]+" :integer (fn [x] [(Integer/parseInt token)])))

(defn -string [token]
  (pattern token #"'[A-Za-z0-9 ]+'" :string (fn [x] [(str/replace token "'" "")])))

;; helpers

(defmulti is-type (fn [matcher token] (class matcher)))

(defmethod is-type clojure.lang.Keyword [symbol token]
  (= symbol token))

(defmethod is-type java.util.regex.Pattern [re token]
  (if (keyword? token)
    false
    (if (not= nil (re-matches re token))
      true
      false)))

(defn alternatives [input types] ;; bit round the houses
  (vec (map (fn [t] (t input)) ;; get nodes for each matching type
            (filter (fn [t] (not= nil (t input))) ;; get matching types
                    types))))

(defn pattern-sequence [tokens patterns collected]
  (if (and (> (count patterns) 0) ;; still patterns to test
           (>= (count tokens) (count patterns))) ;; enough tokens to satisfy pattern
