 
 (defn add-arg
   [vmap arg]
-  (match/match arg [_ type ident]
-    (add-var vmap ident type)
+  (match/match arg [:arg type ident]
+    (m/domonad util/phase-m
+      [[num vmap2] (add-arg-var vmap ident type)]
+      [[:arg type [:ident num]] vmap2]
+      )
     )
   )
 
 (defn add-args
   [vmap args]
-  (loop
-    [vmap vmap
-     args (rest args)]
-    (if (empty? args)
-      vmap
-      (recur (add-arg vmap (first args)) (rest args))))
+  (reduce (fn [buf arg]
+            (m/domonad util/phase-m
+              [[tmprgs vmap2] buf
+               [narg vmap3] (add-arg vmap2 arg)] [(conj tmprgs narg) vmap3]))
+    [:succ [[:args] vmap]] (rest args))
   )
 
 (defn terminated

                           (and
                             (= (get-type lexpr) [:string])
                             (= (get-type rexpr) [:string])))
                       (util/succ (with-type [:eadd lexpr [:plus] rexpr] (get-type lexpr)))
                       (util/err (str "expected int,int or string,string, found " (print-type (get-type lexpr)) ", " (print-type (get-type rexpr)) " in: " location))
                       )
                 ]

      ))
  )

(defn process-decl
  [glob-state type]
  (fn [vars decl]
    (match/match decl
      [:noinit ident] (m/domonad util/phase-m
                        [
                         [tvars decls] vars
                         [num [a b c d]] (add-var tvars ident type)
                         ]
                        [[a b c d] (conj decls [:noinit [:ident num]])]
                        )
      [:init ident expr] (m/domonad util/phase-m
                           [
                            [tvars decls] vars
                            [ntvars nexpr] (annotate-expr glob-state tvars expr)
                            [num [a b c d]] (add-var ntvars ident type)
                            ntype (m-result (get-type nexpr))
                            res (if (= type ntype)
                                  (util/succ [[a b c d] (conj decls [:init [:ident num] nexpr])])
                                  (util/err (str "expected " (print-type type) ", found " (print-type ntype) " in " (util/ip-meta decl))))]
                           res
                           )
      )))

(defn annotate-code
  [glob-state vars code]
  (let [location (util/ip-meta code)]
    (match/match (first code)
      :block (m/domonad util/phase-m
               [[avars result] (reduce (fn [env code]
                                 (m/domonad util/phase-m
                                   [[vars blk] env
                                    [nvars res] (annotate-code glob-state vars code)]
                                   [nvars (conj blk res)]
                                   )
                                 ) (m-result [(new-scope vars) [:block]]) (rest code))]
               [(rm-scope avars) result]
               )
      :vret (check-types (util/succ [:void]) (lookup-var vars "_return_" location) [vars [:vret]] location)
      :ret (m/domonad util/phase-m
             [[nvars expr] (annotate-expr glob-state vars (second code))
              [type _] (lookup-var nvars "_return_" location)
              res (check-types (m-result type) (m-result (get-type expr)) [nvars (with-type [:ret expr] (get-type expr))] location)
              ]
             res)
      :incr (m/domonad util/phase-m
              [[type num] (lookup-var vars (second code) location)
               res (check-types (util/succ [:int]) (m-result type) [vars (with-type [:incr [:ident num]] [:int])] location)]
              res)
      :decr (m/domonad util/phase-m
              [[type num] (lookup-var vars (second code) location)
               res (check-types (util/succ [:int]) (m-result type) [vars (with-type [:decr [:ident num]] [:int])] location)]
              res)
      :decl (m/domonad util/phase-m
              [
               type (m-result (second code))
               decls (m-result (rest (rest code)))
               res (reduce (process-decl glob-state type) (m-result [vars [:decl type]]) decls)
               ;(util/succ [(reduce #(second (add-var %1 %2 type)) vars (map second decls)) (with-type [:decl (map (map-decl glob-state vars location) (rest code))] type)])
               ]
              res
              )
      :ass (m/domonad util/phase-m
             [name (m-result (second code))
              [nvars expr] (annotate-expr glob-state vars (third code))
              [type num] (lookup-var vars name location)
              res (check-types (m-result type) (m-result (get-type expr)) [nvars (with-type [:ass [:ident num] expr] (get-type expr))] location)]
             res)
      :cond (m/domonad util/phase-m
              [
               [vars1 expr] (annotate-expr glob-state vars (second code))
               [vars2 nblock] (annotate-code glob-state vars1 (third code))
               res (check-types (m-result [:bool]) (m-result (get-type expr)) [vars2 [:cond expr nblock]] location)]
              res)
      :condelse (m/domonad util/phase-m
                  [
                   [vars1 expr] (annotate-expr glob-state vars (second code))
                   [vars2 nblock1] (annotate-code glob-state vars1 (third code))
                   [vars3 nblock2] (annotate-code glob-state vars2 (fourth code))
                   res (check-types (m-result [:bool]) (m-result (get-type expr)) [vars3 [:condelse expr nblock1 nblock2]] location)]
                  res)
      :while (m/domonad util/phase-m
               [
                [vars1 expr] (annotate-expr glob-state vars (second code))
                [vars2 nblock] (annotate-code glob-state vars1 (third code))
                res (check-types (m-result [:bool]) (m-result (get-type expr)) [vars2 [:while expr nblock]] location)]
               res
               )
      :sexp (m/domonad util/phase-m
              [[vars1 expr] (annotate-expr glob-state vars (second code))]
              [vars1 [:sexp expr]]
              )
      :else (util/succ [vars code]))))

