   [obj vars]
   (with-meta obj (assoc (meta obj) "_vars" vars))
   )
+
+(defn- is-str
+  [x]
+  (= (get-type x) [:string]))
+
+(defn- is-bool
+  [x]
+  (= (get-type x) [:bool]))
+
+(defn- is-int
+  [x]
+  (= (get-type x) [:int]))
+
+(defn annotate-erel
+  [vars lexpr rexpr relop location]
+  (match/match [lexpr rexpr relop]
+    [(lexpr :guard #(is-str %)) (rexpr :guard #(is-str %)) [:eq]]
+    (util/succ [vars (with-type [:eapp [:ident "_eqStrings"] [lexpr rexpr]] [:bool])])
+
+    [(lexpr :guard #(is-str %)) (rexpr :guard #(is-str %)) [:ieq]]
+      (util/succ [vars (with-type [:not [:eapp [:ident "_eqStrings"] [lexpr rexpr]]] [:bool])])
+
+    [(lexpr :guard #(is-bool %)) (rexpr :guard #(is-bool %)) (:or [:eq] [:ieq])]
+    (util/succ [vars (with-type [:erel lexpr relop rexpr] [:bool])])
+
+    [(lexpr :guard #(is-int %)) (rexpr :guard #(is-int %)) relop]
+    (util/succ [vars (with-type [:erel lexpr relop rexpr] [:bool])])
+
+    [ _ _  (:or [:eq] [:ieq])]
+    (util/err (str "expr invalid; expected int,int or bool,bool or string,string, "
+                "found " (print-type (get-type lexpr)) ", " (print-type (get-type rexpr)) " in: " location))
+
+    :else
+    (util/err (str "expr invalid; expected int,int, "
+                "found " (print-type (get-type lexpr)) ", " (print-type (get-type rexpr)) " in: " location))
+    ))
+
+(defn annotate-eadd
+  [vars lexpr rexpr relop location]
+  (match/match [lexpr rexpr relop]
+    [(lexpr :guard #(is-str %)) (rexpr :guard #(is-str %)) [:plus]]
+    (util/succ [vars (with-type [:eapp [:ident "_concatStrings"] [lexpr rexpr]] [:string])])
+
+    [(lexpr :guard #(is-int %)) (rexpr :guard #(is-int %)) relop]
+    (util/succ [vars (with-type [:eadd lexpr relop rexpr] [:int])])
+
+    [ _ _  [:plus]]
+    (util/err (str "expr invalid; expected int,int or string,string, "
+                "found " (print-type (get-type lexpr)) ", " (print-type (get-type rexpr)) " in: " location))
+
+    :else
+    (util/err (str "expr invalid; expected int,int, "
+                "found " (print-type (get-type lexpr)) ", " (print-type (get-type rexpr)) " in: " location)
+    )))
 
 (defn annotate-expr
   [glob-state vars expr]

(ns latte-compiler.static-analysis
  (:require [clojure.core.match :as match]
            [clojure.algo.monads :as m]
            [latte-compiler.util :as util]))

(defrecord ClassDef [extends fields funs])
(defrecord FunDef [name outType inTypes])

                     )
               ]
              res)
      :eadd  (m/domonad util/phase-m
               [[vars1 lexpr] (annotate-expr glob-state vars (second expr))
                [vars2 rexpr] (annotate-expr glob-state vars1 (fourth expr))
                op (m-result (third expr))
                res (annotate-eadd vars2 lexpr rexpr op location)
                ]
               res)
      :eapp (m/domonad util/phase-m
              [ident (m-result (second expr))
               [nvar args] (reduce (fn [buff tmp] (m/domonad util/phase-m [[tmvar tmargs] buff [ntmvar nexpr] (annotate-expr glob-state tmvar tmp)] [ntmvar (conj tmargs nexpr)])) (m-result [vars []]) (rest (rest expr)))
