 								arg2 (if (not (= :minijava.ir/Call (type (:exp2 s)))) (:exp2 s)
 											;;;exp2 is a call, so wrap it in an eseq  
 											(let [t (tm/temp)] (ExpSeq (Move (:exp2 s) t) t)))]
-								(canon (BinaryOp (:op s) arg1 arg2)));;ok; now create a new binop with these arguments, and run canon on it		
+								(canon-local (BinaryOp (:op s) arg1 arg2)));;ok; now create a new binop with these arguments, and run canon-local on it		
 				(= :minijava.ir/ExpSeq (type s))
 					;;s is an expseq, and its expression is a call	
-					(canon (ExpSeq (:seqs s) 	
+					(canon-local (ExpSeq (:seqs s) 	
 								 (let [t (tm/temp)] (ExpSeq (Move (:exp s) t) t))))
 			(= :minijava.ir/Conditional (type s))
 							;;s is an conditional, and one or both arguments are calls

  [s]
  (commutes (second (first s)) (second (second s))))

(defn canon
  "Converts a Seq to linear IR form."
  [s]
	    (cond 
			 (matches-eseq-left? s) (remove-eseq-left s)
			 (matches-double-eseq? s) (remove-double-eseq s)
			 (matches-eseq-commute? s)
			       (if (commutes? s)
			         (remove-eseq-commute s)
			         (remove-eseq-no-commute s))
						;;If s contains Call as an argument, and s is NOT a move, then construct a new ESeq node moving the result of the call into the return value register.
						;;Then recurse on the newly created node.
					 (contains-call? s)
							(reorganize-call s)
		(= :minijava.ir/Seq (type s))
				(flatten;;run canon on each element of the sequence
					  (for [s (:seqs s)] (canon s)))
		(= :minijava.ir/ExpSeq (type s)) ;;is this right?
			   (list (canon (:seqs s)) (canon (:exp s)))
		(= :minijava.ir/BinaryOp (type s))
				(BinaryOp (:op s) (canon (:exp1 s))  (canon (:exp2 s)))
		(= :minijava.ir/Conditional (type s))
				(Conditional (:op s) (canon (:exp1 s))  (canon (:exp2 s)) (:t s) (:f s))
		(= :minijava.ir/Call (type s))
				(Call (:lbl s) (canon (:args s)))
		(= :minijava.ir/Statement (type s))
				(Statement (canon (:exp s)))
		:else
				s;;no changes or recursion needed for Consts, Jmps, NoOps,Temp, Name, etc
))

;; BASIC BLOCKS


(ns minijava.canon
  "Implementation of the canon-localicalization algorithms for IR."
  (:use (minijava ir)
        clojure.contrib.seq)
  (:require [minijava.temp :as tm]))

(declare canon-local)

(defn raise-double-eseq
  "(ExpSeq s1 (ExpSeq s2 e)) -> (ExpSeq (Seq s1 s2) e)"
  [tree]
  (let [s1 (canon-local (:seqs tree ))
        s2 (canon-local (get-in tree [:exp :seqs]))
        e  (canon-local  (get-in tree [:exp :exp]))]
   		(ExpSeq (Seq s1 s2) e)))

(defn raise-eseq-left-binop
  "(BinaryOp op (ExpSeq stmt expr) e2) -> (ExpSeq stmt (BinaryOp op expr e2))"
  [tree] 
  (let [stmt (canon-local (get-in tree [:exp1 :seqs]))
        expr (canon-local (get-in tree [:exp1 :exp]))]
				(ExpSeq stmt (merge tree [:exp1 expr]))
))

(defn raise-eseq-left-cond
  "(BinaryOp op (ExpSeq stmt expr) e2) -> (ExpSeq stmt (BinaryOp op expr e2))"
  [tree] 
  (let [stmt (canon-local (get-in tree [:exp1 :seqs]))
        expr (canon-local (get-in tree [:exp1 :exp]))]
				(Seq [stmt (merge tree [:exp1 expr])])
))

(defn raise-eseq-center
  "(Mem (ExpSeq stmt expr)) -> (ExpSeq stmt (Mem expr))"
  [tree] 
(cond (= :minijava.ir/Mem (type tree))
		  (let [stmt (canon-local (get-in tree [:adr :seqs]))
		        expr (canon-local (get-in tree [:adr :exp]))]
						(ExpSeq (merge tree [:adr expr])))
			(= :minijava.ir/Jump (type tree))
		  (let [stmt (canon-local (get-in tree [:lbl :seqs]))
		        expr (canon-local (get-in tree [:lbl :exp]))]
						(ExpSeq stmt (merge tree [:lbl expr])))
))


 ;; is this correct for CJumps, or just for Binops? As seen in figure
 ;; 8.1 (3), if a Cjump is fed into this, it should end up with no
 ;; ESeqs, just Seqs.
(defn raise-eseq-commute-binop
  "(BinaryOp op e1 (ExpSeq s2 e2)) -> (ExpSeq s2 (BinaryOp op e1 e2))"
  [tree]
  (let [e1 (canon-local (get tree :exp1))
        s2 (canon-local (get-in tree [:exp2 :seqs]))
        e2 (canon-local (get-in tree [:exp2 :exp]))]
   			(ExpSeq s2 (merge tree [:exp2 e2]))))

(defn raise-eseq-commute-cond
  "(Conditional op e1 (ExpSeq s2 e2) t f) -> (ExpSeq s2 (Conditional op e1 e2 t f))"
  [tree]
  (let [e1 (canon-local (get tree :exp1))
        s2 (canon-local (get-in tree [:exp2 :seqs]))
        e2 (canon-local (get-in tree [:exp2 :exp]))]
   			(Seq [s2 (merge tree [:exp2 e2])])))





(defn raise-eseq-no-commute-binop
  "(BinaryOp op e1 (ExpSeq s1 e2))
     -> (ExpSeq (Move e1 (Temp t)) (ExpSeq s1 (BinaryOp op (Temp t e2))))"
  [tree]
  (let [e1 (canon-local (get tree :exp1))
        s1 (canon-local (get-in tree [:exp2 :seqs]))
        e2 (canon-local (get-in tree [:exp2 :exp]))
        t  (tm/temp)]
			(ExpSeq (Move e1 (Temp t)) (ExpSeq s1 (merge tree [:exp1 (Temp t)] [:exp2 e2])))
)) 

(defn raise-eseq-no-commute-cond
  "(Conditional op e1 (ExpSeq s1 e2))
     -> (Seq (Move e1 (Temp t)) s1 (Conditional op (Temp t e2)))"
  [tree]
  (let [e1 (canon-local (get tree :exp1))
        s1 (canon-local (get-in tree [:exp2 :seqs]))
        e2 (canon-local (get-in tree [:exp2 :exp]))
        t  (tm/temp)]
			(Seq [(Move e1 (Temp t)) (Seq s1 (merge tree [:exp1 (Temp t)] [:exp2 e2]))])
)) 


(defn matches-double-eseq?
  [s]
  (and (= :minijava.ir/ExpSeq (type s))
       (= :minijava.ir/ExpSeq (type (:exp s)))))

(defn matches-eseq-left-cond?
  [s]
   (and (= :minijava.ir/Conditional (type s))
           (= :minijava.ir/ExpSeq (type (:exp1 s)))))

(defn matches-eseq-left-binop?
  [s]
  (and (= :minijava.ir/BinaryOp (type s)) ;; see figure 8.1
           (= :minijava.ir/ExpSeq (type (:exp1 s)))))

;;For things like Mem, Jump, that have only one argument
(defn matches-eseq-center [s]
		 (and (= :minijava.ir/Mem (type s))
           (= :minijava.ir/ExpSeq (type (:adr s))))
      (and (= :minijava.ir/Jump (type s))
           (= :minijava.ir/ExpSeq (type (:lbl s))))
)


(defn matches-eseq-commute-binop?
  [s]
 (and (= :minijava.ir/BinaryOp (type s)) ;; see figure 8.1
           (= :minijava.ir/ExpSeq (type (:exp2 s))))
    )
(defn matches-eseq-commute-cond?
  [s]
  (and (= :minijava.ir/Conditional (type s));; see figure 8.1
           (= :minijava.ir/ExpSeq (type (:exp2 s))))
 )
 

(defn isit? [x t]
  (= (type x) t))

;; support function for Commutes, taken from canon-local.java
(defn isNop [a]
  (and (isit? a :minijava.ir/Statement) (isit? (:exp a) :minijava.ir/Const)))

;; commutes, translated from canon-local.java
(defn commutes
  [a b]
  (or (isNop a) (isit? b :minijava.ir/Name) (isit? b :minijava.ir/Const)))
