
;;(defun checkpoint (str) (message "*** checkpoint %s" str))
(defun checkpoint (str) )

(setq sc 'sc)

(setq debug-on-error t)
;;(load-file "../lisp/cl-macs.el")

;;(load-file "~/dlisp/assert.el")
(require 'cl)

;; (insert (c--print-string "a\0"))
(defun c--print-string (s)
  (assert (stringp s))
  (let ((i      0)
        (len    (length s))
        (a      0)
        (result "\""))
    (while (< i len)
      (setq a (aref s i))
      (setq result (concat result
                           (cond
                            ((= a ?\n) "\\n")
                            ((= a ?\") "\\\"")
                            ((= a 0)   "\\0")
                            (t
                             (format "%c" a)))))
      (incf i))
    (concat result "\"")))

;; (setq ch "a")
;; (insert (c--print-char (setq ch "\n")))
;; (insert (c--print-char (setq ch "\0")))
(defun c--print-char (ch)
  (concat "\'"
          (cond
           ((= (aref ch 0) ?\n) "\\n")
           ((= (aref ch 0) ?\") "\\\"")
           ((= (aref ch 0) 0) "\\0")
           (t
            ch))
          "\'"))

;; (c--print-list '(abc def))
;; (c--print-list [10] [20])
;; (c--print-list '([10] [20]))
;; (setq list nil)
;; (setq list '(1 2 3))
(defun c--print-list (list)
  (assert (or (not list) (consp list)))
  (let ((ptr    list)
        (result ""))
    ;;(debug)
    (while ptr
      (setq result (format "%s %s" result (car ptr)))
      (setq ptr (cdr ptr)))
    result))


;;(c--process 'ptr<Array_A<Int_A>>::ctor)
;; (c--process '(cprogn (s 1 + 2 sc)) 'cprogn)
;; (setq str ">>")
;; (setq str "ptr<Array_A<Int_A>>::ctor")
;; (c--process 'ptr<Array_A<Int_A>>::ctor)
;; (c--process '>>)
;; (prin1-to-string 'abc)
;; (princ 'abc)
;; (format "%s" 'abc)
;; (c--process 'ptr<List_A<Menu_Button_A>>)
(defun c--process (term &rest car-terms)
  (interactive)
  ;;(if (eq 'if_part term)
  ;;    (debug))
  (let ((str (prin1-to-string term)))
    ;;(debug)
    (cond
     ((eq term 'sc) ";")
     ((eq term 'nl) "\n")
     ((string= ">>" str)
      ">>")
     ;; -----------------------------------------------------
     ((consp term)
      (if (memq (car term) car-terms)
          nil
        (assert nil nil "error (car term)=%s" (car term)))
      (cadr (eval term)))
     ;; -----------------------------------------------------
     ((stringp term)
      (if (/= (length term) 1)
          (c--print-string term)
        (c--print-char term)))

     ;; -----------------------------------------------------
     ((string-match ">>" str)
      (while (string-match "\\(^.*[^ ]\\)>>\\(.*$\\)" str)
        (setq str (concat (substring str (match-beginning 1) (match-end 1)) "> >" (substring str (match-beginning 2) (match-end 2)))))
      ;;(debug)
      str)

     (t
      ;;(debug)
      (format "%s" term)))))

;; (c--delete-line)
(defun c--delete-line ()
  (while (looking-at "[ \t]")
    (delete-char 1))
  (delete-char 1))

(quote
 (cwhile (b 1 == 1)
          (f foo)
          (cassert (b 1 == 0))
          (s adafd (b 123) sc)
          (f bar))
          )


;; (cprogn (s 123 sc) (s 456 sc) (s abc sc) (s (f smeg (b 123 + 456) (b 123 * 789)) sc))
;; (cprogn (s abc sc) (s 123 sc) sc)
;; (cprogn (cswitch (b 1 == 0) (s case 123:) (f foo)))
;; (foo (s 123 sc))
(defmacro foo (&rest rest)
  (if (consp rest)
     (cons 'cprogn rest)))

;;(cprogn (s 123 sc) (s 456 sc))
;;(foo (s 123 sc) (s 456 sc))

(defmacro cprogn (&rest list)
  (let ((ptr    list)
        (result "{\n")
        (count  0)
        (schmu  nil))
    (while ptr
      ;;(debug)
      ;;(message "ptr=%s" (prin1-to-string ptr))
      (assert (or (eq (car ptr) 'mangina)
                  (eq (car ptr) 'sc)
                  (eq (caar ptr) 's)
                  (eq (caar ptr) 'b)
                  (eq (caar ptr) 'cif)
                  (eq (caar ptr) 'cprogn)
                  (eq (caar ptr) 'cfor)
                  (eq (caar ptr) 'cif)
                  (eq (caar ptr) 'cdo)
                  (eq (caar ptr) 'cwhile)
                  (eq (caar ptr) 'cswitch)
                  (eq (caar ptr) 'cassert)
                  (eq (caar ptr) 'cforeach)
                  (eq (caar ptr) 'cpause)
                  (eq (caar ptr) 'cbegin)
                  (eq (caar ptr) 'cend)
                  ;;(eq (caar ptr) 'c-raw-splat)
                  (eq (caar ptr) 'f)
                  ))
      ;;(debug)
      (setq x (eval (car ptr)))
      (setq y (eval (list 's (car ptr) 'sc)))
      ;;(if (eq (caar ptr) 'cswitch) (debug))
      ;;(eval (car ptr))
      (setq result (concat result (if (/= count 0) "\n" "")
                           ;;(debug)
                           (cond
                            ((eq (car ptr) 'sc)
                             ";")
                            ((eq (caar ptr) 'f)
                             (cadr y))
                            ((eq (caar ptr) 'cfor)
                             (cadr (eval (car ptr))))
                            ((eq (caar ptr) 'cwhile)
                             (cadr (eval (car ptr))))
                            ((eq (caar ptr) 'cif)
                             (cadr (eval (car ptr))))
                            ((eq (caar ptr) 'cprogn)
                             (cadr (eval (car ptr))))
                            ((eq (caar ptr) 'cswitch)
                             (cadr (eval (car ptr))))
                            ((eq (caar ptr) 'cassert)
                             (cadr (eval (car ptr))))
                            ((eq (caar ptr) 'cforeach)
                             ;;(debug)
                             (cadr (eval (car ptr))))
                            ;;(t (cadr x) ))))
                            (t
                             (cadr (eval (car ptr)))))))
      (incf count)
      (setq ptr (cdr ptr)))
    `(list 'cprogn ,(concat result "\n}"))))

;; (b abc + (b 2 * 3))
;; (b *star)
(defmacro b (&rest args)
  (let ((ptr    args)
        (result "(")
        (count  0))
    (while ptr
      ;;(setq term (car ptr))
      (setq result (concat result (if (/= count 0) " " "") (format "%s" (c--process (car ptr)
                                                                                    'apple
                                                                                    'b
                                                                                    'f
                                                                                    'cassert
                                                                                    'cforeach
                                                                                    'cswitch
                                                                                    'cprogn
                                                                                    'cif
                                                                                    'cif?
                                                                                    'cfor
                                                                                    'cwhile
                                                                                    'cdo))))
      (incf count)
      (setq ptr (cdr ptr)))
    `(list 'b ,(concat result ")"))))

;; (s 123 + 456)
(defmacro s (&rest args)
  (let ((ptr    args)
        (result "")
        (count  0))
    (while ptr
      ;;(debug)
      (setq result (concat result (if (/= count 0) " " "") (format "%s" (c--process (car ptr)
                                                                                    'banana
                                                                                    'b
                                                                                    'f
                                                                                    's
                                                                                    'if
                                                                                    'cassert
                                                                                    'cforeach
                                                                                    'cswitch
                                                                                    'cprogn
                                                                                    'cif
                                                                                    'cfor
                                                                                    'cwhile
                                                                                    'cdo
                                                                                    'cbegin
                                                                                    'cpause
                                                                                    'cend
                                                                                    ;;'c-raw-splat
                                                                                    ))))
      (incf count)
      (setq ptr (cdr ptr)))
    ;;(message "result=%s" (prin1-to-string result))
    `(list 's ,result)))

;; (c-typedef (c-ret void) (b foo) (c-args))
(defmacro c-typedef (&rest list)
  (let ((ptr    list)
        (result "typedef ")
        (count  0))
    (while ptr
      ;;(debug)
      (setq result (format "%s%s%s" result (if (/= count 0) " " "") (c--process (car ptr) 'carrot 'b 'c-ret 'c-args)))
      (incf count)
      (setq ptr (cdr ptr)))
    (save-excursion
      (if in-class
          (set-buffer (find-file class-hh))
        (set-buffer (find-file global-hh)))
      (goto-char (point-max))
      (insert (concat result ";\n"))
      nil)))

;; (setq list '(int a)) => extern int a / int a = 123 sc
;; (c-variable const int a = 123 sc)
;; (c-variable const int a = 123 sc)
(defmacro c-variable (&rest list)
  (assert (not in-class))
  (let (ptr done)
    (if (eq (car list) 'const)
        (save-excursion
          (set-buffer (find-file global-hh))
          (goto-char (point-max))
          (setq ptr list)
          (while ptr
            (insert (c--process (car ptr) 'doughnut 'const) " ")
            (setq ptr (cdr ptr)))
          (insert ";\n")
          )
      (save-excursion
        (set-buffer (find-file global-hh))
        (goto-char (point-max))
        (insert "extern ")
        (setq ptr list)
        (setq done nil)
        (while (and ptr (not done))
          (if (eq (car ptr) '=)
              (setq done t)
            (insert (c--process (car ptr) 'eggplant 'b 'const) " "))
          (setq ptr (cdr ptr)))
        ;;(if done (insert ";"))
        (insert ";\n")
        (set-buffer (find-file global-cc))
        (goto-char (point-max))
        (setq ptr list)
        (while ptr
          (insert (c--process (car ptr) 'fish 'b) " ")
          (setq ptr (cdr ptr)))
        (insert ";\n")
        )
      )
    ))

;; (cprogn (s 123) (s 456) (s abc) (f smeg (b 123 + 456) (b 123 * 789)))
;; (f smeg (b 123 + 456) (b 123 * 789))
;; (f new Apple 123 456)
;; (setq function (b *abc))
;; (f (b *foo) args)
;; (b *foo)
(defmacro f (function &rest args)
  ;;(debug)
  (assert (or (symbolp function) (eq (car function) 'b)))
  (if (and (consp function) (eq (car function) 'b))
      (setq function (cdr function))) ;; skip b form
  ;;(debug)
  (let ((ptr args) (result "") (count 0))
    (if (eq function 'new)
        (progn
          (setq result (format "%s %s(" function (car args)))
          (setq ptr (cdr ptr)))
      (setq result (format "%s(" function)))
    (while ptr
      (setq result (concat result (if (/= count 0) "," "") (format "%s" (c--process (car ptr) 'gamma 's 'b 'f))))
      (incf count)
      (setq ptr (cdr ptr)))
    `(list 'f ,(concat result ")"))))


;; (cif (c-= 1 0) (s foo sc) (cprogn (s 123 sc)))
;; (cif (b 1 == 0) foo bar)
;; (cif (b !(b 1 == 0)) (f foo) (f bar))
;; (cif (b 1 == 0) (s foo sc) (s bar sc))
;; (cif (b 1 == 0) (f foo) (f bar))
;; (cif (cnot (b 1 == 0)) (f foo))
;; (cif (f keypressed) (s sex << 8 sc))
;; (cif (f keypressed) (s sex >> 8 sc))
(defmacro cif (test if-part &optional else-part)
  ;;(debug)
  `(list 'cif ,(format "if (%s)\n%s %s %s\n"
                        (c--process test 'hole 'f 'b 'cnot)
                        (if (eq 'f (car if-part))
                            (c--process (list 's if-part 'sc) 'hole 's)
                          (c--process if-part 'hole 'cforeach 'cif 'b 's 'cprogn 'f))
                        (if else-part "else" "")
                        (if else-part
                            (if (eq 'f (car else-part))
                                (c--process (list 's else-part 'sc) 'igloo 's 'f)
                              (c--process else-part 'b 's 'cforeach 'cif 'cprogn 'igloo 'f))
                          ";"))))

;; (cif? (b 1 == 0) (f foo))
;; (cif? (b 1 == 0) (b if_part 123 456) (b else_part))
;; (cif? (b 1 == 0) (b if_part 123 456) )
(defmacro cif? (test if-part &optional else-part)
  ;;(debug)
  (let (ptr fold_l fold_r count)
    (setq ptr (cddr if-part))
    (setq fold_l (car ptr))
    (setq count 0)
    (while ptr
      (if (/= count 0)
          (setq fold_l (format "%s,%s" fold_l (car ptr))))
      (incf count)
      (setq ptr (cdr ptr)))
    (setq ptr (cddr else-part))
    (setq fold_r (car ptr))
    (setq count 0)
    (while ptr
      (if (/= count 0)
          (setq fold_r (format "%s,%s" fold_r (car ptr))))
      (incf count)
      (setq ptr (cdr ptr)))
    `(list 'cif? ,(format "(%s)? %s : %s"
                           (c--process test 'b 'john)
                           (format "%s(%s)" (c--process (cadr if-part) 'john 'b 's 'cprogn 'f) (or fold_l ""))
                           (if else-part
                               (format "%s(%s)" (c--process (cadr else-part) 'john 'b 's 'cprogn 'f) (or fold_r ""))
                             "0")))))

;; (cfor (s int i = 0 sc) (s i < 10 sc) (s i++) (s 12 + 34 sc) (s bar sc))
;; (cfor (s int i = 0 sc) (s i < 10 sc) (s i++) (cprogn (s 12 + 34 sc)))
;; (cfor (s int i = 0 sc) (s i < 10 sc) (s i++) (f foo))
;; (cfor nil nil nil (s 123 sc))
;;
(defmacro cfor (part1 part2 part3 &rest body)
  ;;(debug)
  (assert (or (not part1) (eq 'sc (car (last part1)))))
  (assert (or (not part2) (eq 'sc (car (last part2)))))
  (let ((ptr    body)
        (result "{"))
    (while ptr
      (setq result (concat result "\n" (c--process (car ptr)
                                                   'kappa
                                                   'cprogn
                                                   'cwhile
                                                   'cdo
                                                   'cfor
                                                   'cif
                                                   'cswitch
                                                   'cforeach
                                                   'f
                                                   'b
                                                   's)))
      ;;(debug)
      (if (eq (caar ptr) 'f)
          (setq result (concat result ";")))
      (setq ptr (cdr ptr)))
    `(list 'cfor ,(concat "for ("
                           (or (cadr (eval part1)) ";")
                           " "
                           (or (cadr (eval part2)) ";")
                           " "
                           (cadr (eval part3))
                           ")\n"
                           result "\n}"))))

;; (cswitch (b 1 == 0) (s case 1:) (s return 123 sc) (s case 2:) (f foo) (cassert (b 1 == 1)))
(defmacro cswitch (test &rest body)
  ;;(debug)
  (assert (consp body))
  (let ((ptr    body)
        (result ""))
    (while ptr
      ;;(if (eq (car ptr) 'cprogn) (debug))
      (setq result (concat result (c--process (car ptr) 'lambda 'cforeach 'cassert 'cif 'cprogn 'f 's) (if (eq (caar ptr) 'f) ";\n" "\n")))
      (setq ptr (cdr ptr)))
    `(list 'cswitch ,(concat "switch " (c--process test 'lambda 'b) "\n{\n" result "}"))))

;; (cwhile (b i < 10) (cprogn (s 1 + 2 sc)))
;; (cwhile (b i < 10) (f foo))
;; (cwhile (b i < 10) (s foo sc))
;; (cwhile (b foo (cprogn (s 123 sc))) (f foo))
;; (cwhile (b 1 != 0) (s 123 sc) (s 456 sc))
;; (cwhile (b 1 != 0) (s 123 sc))
;; (cwhile (b 1 != 0) (f abc))
;; (cwhile (b 1 != 0) (cprogn (cprogn (cprogn (f foo[10][20])))))
(defmacro cwhile (expr &rest body)
  (let ((ptr    body)
        (result "{"))
  (while ptr
    (setq result (concat result "\n" (c--process (car ptr)
                                                 'munchos
                                                 'cprogn
                                                 'cwhile
                                                 'cdo
                                                 'cfor
                                                 'f
                                                 'b
                                                 's)
                         (if (eq (caar ptr) 'f) ";" "")))
    (setq ptr (cdr ptr)))
  `(list 'cwhile ,(concat "while " (c--process expr 'b 'munchos) "\n" result "\n}"))))

;;(if (consp body)
;;    (c--process (list 'cprogn body) 'cprogn 's 'f)
;;  (if (eq (car body) 'f)
;;      (c--process (list 's body 'sc) 's 'f)
;;    (c--process body 'cprogn 's 'f))))))

;; (cdo (b i < 10) (f foo))
;; (cdo (b i < 10) (s foo sc) (s smeg sc))
;; (cdo (s foo + bar sc) (b i < 10))
(defmacro cdo (&rest rest)
  (let ((ptr    rest)
        (last   (last rest))
        (result ""))
  (while (not (eq ptr (last rest)))
    (setq result (concat result "\n" (c--process (car ptr)
                                                 'nigger
                                                 'cprogn
                                                 'cwhile
                                                 'cdo
                                                 'cfor
                                                 'f
                                                 'b
                                                 's)
                         (if (eq (caar ptr) 'f) ";" "")))
    (setq ptr (cdr ptr)))
  `(list 'cdo ,(concat "do {" result "\n} while " (c--process (car last) 'nigger 'b) ";"))))

;;(if (eq (car body) 'f)
;;    (c--process (list 's body 'sc) 's)
;;  (c--process body 's 'cswitch 'cprogn 'cwhile 'cfor 'cdo 'cif))
;;

;; (insert (cadr (cassert (c-= 1 0))))
;; (insert (cadr (cassert foo)
;; (cnot 123)
;; (cnot apple)
(defmacro cnot (test)
  `(list 'cnot (concat "!(" ,(c--process test 'oxtail 'b) ")"))
  )

 ;; my library of macros

;; (cprogn (s 123 + 456 sc))
;; (c--process (cassert foo) 'cnot)
;; (cassert (b 1 == 0))
;;; VERSION 1:
(defmacro cassert (test)
  ;;(debug)
  (setq etest (c--process test 'b 'cnot 'peter))
  (eval `(list 'cif '(cnot ,test)
               '(cprogn
                 (f printf "*** Assertion failed: %s at (%s:%d)\n" ,etest __FILE__ __LINE__)
                 (f exit -1))
               nil)))

;; (cassert (b 1 != 0)) (eval (b 1 != 0))
;;; VERSION 2:
(defmacro cassert (test)
  ;;(debug)
  `(cif (cnot ,test) (cprogn (f printf "*** Assertion failed: %s at (%s:%d)\n" ,(cadr (eval test)) __FILE__ __LINE__) (f exit -1))))

;; (reverse '(1 2 3 4))
;; (cassert 1 != 2)
;;; VERSION 3:
(defmacro cassert (&rest rest)
  (let ((result   nil)
        (e-result "")
        (ptr      rest));; (apply 'reverse rest) (length rest) (reverse rest)
    ;;(debug)
    (while ptr
      (setq result (cons (car ptr) result))
      (setq e-result (concat e-result (format "%s" (car ptr))))
      (setq ptr (cdr ptr)))
    ;;(debug)
    `(cif (cnot ,(cons 'b (reverse result))) (cprogn
                                                (f printf "Assertion failed: %s at (%s:%d)\n" ,e-result __FILE__ __LINE__)
                                                (f exit -1)))))


;;; VERSION 4:

(defmacro cassert (&rest rest)
  (let ((result   nil)
        (e-result "")
        (ptr      rest));; (apply 'reverse rest) (length rest) (reverse rest)
    ;;(debug)
    (while ptr
      (setq result (cons (car ptr) result))
      (setq e-result (concat e-result (format "%s" (car ptr))))
      (setq ptr (cdr ptr)))
    ;;(debug)
    `(cif (cnot ,(cons 'b (reverse result))) (cprogn
                                                (f PRINTF_AND_EXIT(b "Assertion failed: %s at (%s:%d)\n" COMMA
                                                                     ,e-result COMMA
                                                                     __FILE__  COMMA
                                                                     __LINE__))
                                                (f exit -1)))))


;; (cassert (b 1 != 0))
;;(defmacro cassert-2 (&rest test)
;;  (apply 'cassert test))
;; (cassert-2 1 == 1)

;; (c-ptr String_Sample_A p)
(defmacro c-ptr (ptr arg)
  (setq str (concat "const ptr<" (prin1-to-string ptr) ">& " (prin1-to-string arg)))
  (setq str (if (string= ">>" str)
                ">>"
              (while (string-match "\\(^.*\\)>>\\(.*$\\)" str)
                (setq str (concat (substring str (match-beginning 1) (match-end 1)) "> >" (substring str (match-beginning 2) (match-end 2)))))
              str))
  `(list 'c-ptr str))

;; (cforeach Y m mylist (cprogn (f m->get_data) (s 123 sc)))
;; (cforeach Y m mylist (s 123 sc) (s 456 sc))
;; (cforeach Y m mylist (s 123 sc))
;; (cforeach Y m mylist (f foo))
;; (setq X 'Int_A)
(defmacro cforeach (X iterator list &rest body)
  ;;(debug)
  (let ((ptr    body)
        (result ""))
    (setq result "\n{")
    (while ptr
      (setq result (concat result "\n" (c--process (car ptr)
                                                   'fuck
                                                   'cprogn
                                                   'cwhile
                                                   'cdo
                                                   'cif
                                                   'cfor
                                                   'cforeach
                                                   'f
                                                   'b
                                                   's)
                           (if (eq (caar ptr) 'f) ";" "")))
      (setq ptr (cdr ptr)))
    (setq result (concat result "\n}"))
    ;;  (if (eq (car body) 'f)
    ;;      (setq body (list 's body 'sc)))
    ;;  (if (eq (car body) 's)
    ;;      (setq body (list 'cprogn body)))
    ;;(debug)
    ;;(assert (or (eq (car body) 'cprogn) (eq (caar body) 'cprogn)))
    `(list 'cprogn
           (concat "for ("
                   (cadr (s ,(read (format "ptr<List_Iterator_A<%s>>" X))
                            ,iterator = (s (b ,list) (f ->get_first) sc)))
                   (cadr (s (b ,iterator) (f ->has_more) sc))
                   (cadr (s (b ,iterator) (f ->advance))) ")"
                   ,result))))
                   ;;,(cadr (eval body))))))

;; (c-begin)
(defmacro cbegin ()
  (setq c-pause-count 0)
  '(cprogn
    (cif (b !ptr)
          (s ptr = &&a_0 sc))
    (s goto *ptr sc)
    (s a_0: sc)))

;; (c-pause)
(defmacro cpause ()
  (incf c-pause-count)
  `(cprogn
    (s ptr = ,(read (format "&&a_%d" c-pause-count)) sc)
    (s return sc)
    (s ,(read (format "a_%d:" c-pause-count)))
    (s (b void)123 sc)))

;; (c-end)
(defmacro cend ()
  '(cprogn
    (s ptr = &&a_0 sc)
    (s return sc)))

;; (setq body '(f assert 1 != 0))
;; (c-method (c-ret const char**) hello (c-arg int x) : (f A 123) (f foo 123))
;; (c-method (c-ret void) hello (c-arg) (cprogn (s cout << 123 << "\n")))
;; (setq name 'name)
;; (setq method--return-type    (format "%s" (nth 1 thing)))
;; (setq method--name-and--args (format "%s" (nth 2 thing)))
;; (setq method--top-rest       (format "%s" (nth 3 thing)))
;; (setq method--body           (format "%s" (nth 4 thing)))
;; (cprogn (f assert (b 1 != 0)) (f assert (b 1 == 1)))
;; (c-submode-get int a1 (f assert (b 1 != 0)))
;; (c-submode-get int a1 (s (f assert (b 1 != 0)) sc))
;; (c-submode-get int a1 (cprogn (f assert (b 1 != 0)) (f foo)))
;; (c-submode-get int a1 )
(defmacro c-submode-get (type name &optional body)
  ;;(debug)
  (if (not body)
      `(list 'c-method ,(format "%s" type) ,(format "get_%s()" name) ""
             (concat "{\n" (cadr ,(list 's 'return name sc)) "\n}"))
    (cond
     ((eq (car body) 'f)
      `(list 'c-method ,(format "%s" type) ,(format "get_%s()" name) ""
             (concat "{\n" (cadr ,(list 'cprogn (list 's body 'sc) (list 's 'return name sc))) "\n}")))
     ((eq (car body) 's)
      `(list 'c-method ,(format "%s" type) ,(format "get_%s()" name) ""
             (concat "{\n" (cadr ,(list 'cprogn body (list 's 'return name sc))) "\n}")))
     ((eq (car body) 'cprogn)
      `(list 'c-method ,(format "%s" type) ,(format "get_%s()" name) ""
             (concat "{\n" (cadr ,(list 'cprogn body (list 's 'return name sc))) "\n}")))
     ((eq (car body) 'cif)
      `(list 'c-method ,(format "%s" type) ,(format "get_%s()" name) ""
             (concat "{\n" (cadr ,(list 'cprogn (list 's body 'sc) (list 's 'return name sc))) "\n}")))
     ((eq (car body) 'cassert)
      `(list 'c-method ,(format "%s" type) ,(format "get_%s()" name) ""
             (concat "{\n" (cadr ,(list 'cprogn (list 's body 'sc) (list 's 'return name sc))) "\n}")))
    )))

;;(c-submode-set int x (cassert 1 != 0))
;;(c-submode-set int x (s (f assert (b 1 != 0)) sc))
;;(c-submode-set int x (cprogn (s assert (b 1 != 0) sc)))
(defmacro c-submode-set (type name &optional body)
  ;;(debug)
  (if (not body)
    `(list 'c-method "void" ,(format "set_%s(%s %s)" name type name) ""
           (concat "{\n" (cadr ,(list 's 'this-> name '= name 'sc)) "\n}"))
    (cond
     ((eq (car body) 'f)
      `(list 'c-method "void" ,(format "set_%s(%s %s)" name type name) ""
             (concat "{\n" (cadr ,(list 'cprogn (list 's body 'sc) (list 's 'this-> name '= name 'sc))) "\n}")))
     ((eq (car body) 's)
      `(list 'c-method "void" ,(format "set_%s(%s %s)" name type name) ""
             (concat "{\n" (cadr ,(list 'cprogn body (list 's 'this-> name '= name 'sc))) "\n}")))
     ((eq (car body) 'cprogn)
      `(list 'c-method "void" ,(format "set_%s(%s %s)" name type name) ""
             (concat "{\n" (cadr ,(list 'cprogn body (list 's 'this-> name '= name 'sc))) "\n}")))
     ((eq (car body) 'cif)
      `(list 'c-method "void" ,(format "set_%s(%s %s)" name type name) ""
             (concat "{\n" (cadr ,(list 'cprogn body (list 's 'this-> name '= name 'sc))) "\n}")))
     ((eq (car body) 'cassert)
      `(list 'c-method "void" ,(format "set_%s(%s %s)" name type name) ""
             (concat "{\n" (cadr ,(list 'cprogn body (list 's 'this-> name '= name 'sc))) "\n}")))
     )))

;;(c-submode-inc int x (f assert (b 1 != 0)))
;;(c-submode-inc int x (s (f assert (b 1 != 0)) sc))
;;(c-submode-inc int x (cprogn (s assert (b 1 != 0) sc)))
(defmacro c-submode-inc (inc-type name &optional body)
  ;;(debug)
  (if (not body)
      `(list 'c-method "void" ,(format "inc_%s(%s amount)" name inc-type) ""
             (concat "{\n" (cadr ,(list 's 'this-> name '+= 'amount 'sc)) "\n}"))
    (cond
     ((eq (car body) 'f)
      `(list 'c-method "void" ,(format "inc_%s(%s amount)" name inc-type) ""
             (concat "{\n" (cadr ,(list 'cprogn (list 's body 'sc) (list 's 'this-> name '+= 'amount 'sc))) "\n}")))
     ((eq (car body) 's)
      `(list 'c-method "void" ,(format "inc_%s(%s amount)" name inc-type) ""
             (concat "{\n" (cadr ,(list 'cprogn body (list 's 'this-> name '= name 'sc))) "\n}")))
     ((eq (car body) 'cprogn)
      `(list 'c-method "void" ,(format "inc_%s(%s amount)" name inc-type) ""
             (concat "{\n" (cadr ,(list 'cprogn body (list 's 'this-> name '= name 'sc))) "\n}")))
     ((eq (car body) 'cassert)
      `(list 'c-method "void" ,(format "inc_%s(%s amount)" name inc-type) ""
             (concat "{\n" (cadr ,(list 'cprogn body (list 's 'this-> name '= name 'sc))) "\n}")))
     )))

;;(c-submode-dec int x (f assert (b 1 != 0)))
;;(c-submode-dec int x (s (f assert (b 1 != 0)) sc))
;;(c-submode-dec int x (cprogn (s assert (b 1 != 0) sc)))
(defmacro c-submode-dec (inc-type name &optional body)
  ;;(debug)
  (if (not body)
      `(list 'c-method "void" ,(format "dec_%s(%s amount)" name inc-type) nil
             (concat "{\n" (cadr ,(list 's 'this-> name '-= 'amount 'sc)) "\n}"))
    (cond
     ((eq (car body) 'f)
      `(list 'c-method "void" ,(format "dec_%s(%s amount)" name inc-type) nil
             (ooncat "{\n" (cadr ,(list 'cprogn (list 's body 'sc) (list 's 'this-> name '-= 'amount 'sc))) "\n}")))
     ((eq (car body) 's)
      `(list 'c-method "void" ,(format "dec_%s(%s amount)" name inc-type) nil
             (ooncat "{\n" (cadr ,(list 'cprogn body (list 's 'this-> name '-= 'amount 'sc))) "\n}")))
     ((eq (car body) 'cprogn)
      `(list 'c-method "void" ,(format "dec_%s(%s amount)" name inc-type) nil
             (concat "{\n" (cadr ,(list 'cprogn body (list 's 'this-> name '-= 'amount 'sc))) "\n}")))
     ((eq (car body) 'cif)
      `(list 'c-method "void" ,(format "dec_%s(%s amount)" name inc-type) nil
             (concat "{\n" (cadr ,(list 'cprogn body (list 's 'this-> name '-= 'amount 'sc))) "\n}")))
     )))

;; (c-submode-var int x)
;;(defmacro c-submode-var (type name)
;;  `(list 'c-property (concat ,(prin1-to-string type) " " ,(prin1-to-string name))))


;; (defun cforever (&rest list)
;; (list 'cfor "for (;;)\n{"
;; (c-arg int foo)
;; (c-arg const char** bar = "lemon")
;; (c-arg 'foo bar) fails
;; (c-arg 123 456)
(defmacro c-arg (&rest list)
  (let ((ptr list)
        (result "")
        (count 0))
    ;;(debug)
    (while ptr
      (setq result (concat result (if (/= count 0) " " "") (c--process (car ptr) 'c-ptr 'b)))
      (incf count)
      (setq ptr (cdr ptr)))
    `(list 'c-arg ,result)))

;;(defalias 'c-ret 'c-arg)

(defmacro c-ret (&rest list)
  (let ((ptr list)
        (result "")
        (count 0))
    ;;(debug)
    (while ptr
      (setq result (concat result (if (/= count 0) " " "") (c--process (car ptr))))
      (incf count)
      (setq ptr (cdr ptr)))
    `(list 'c-ret ,result)))

;; (c-args (c-arg const int a) (c-arg char** b))
;; (c-args (c-arg const int a[123][456]) (c-arg char** b))
;; (c-args (c-arg void (b *step_callback) (b )))
(defmacro c-args (&rest arg-list)
  (let ((ptr arg-list)
        (result "(")
        (count 0))
    (while ptr
      (assert (eq (caar ptr) 'c-arg))
      ;;(debug)
      (setq result (concat result (if (/= count 0) ", " "")))
      (let ((ptr2 (cdar ptr))
            (count2 0))
        (while ptr2
          (setq result (concat result (if (/= count2 0) " " "") (c--process (car ptr2) 'quango 'c-arg 'b 'c-ptr)))
          (incf count2)
          (setq ptr2 (cdr ptr2))))
      ;;(debug)
      (incf count)
      (setq ptr (cdr ptr)))
    ;;(debug)
    (setq result (concat result ")"))
    `(list 'c-args ,result)))

;; (c-method (c-ret const char**) hello (c-args (c-arg int x)) : (f A 123) (cprogn (s 123)))
;; (c-method (c-ret const char**) hello (c-args (c-arg int x)) : (f A 123) (f foo 123))
;; (c-method (c-ret const char**) hello (c-arg int x) : (f A 123) (f foo 123))
(defmacro c-method (return-type name args &rest rest)
  (assert (symbolp name))
  (assert (or (eq (car args) 'c-args) (eq (car args) 'c-arg)))
  (assert (eq (car return-type) 'c-ret))
  (let* ((e-args   (eval args))
         (e-ret    (c--process return-type 'c-ret 'rusty))
         (last     (last rest))
         (e-body   (if (eq 'null (car last)) nil (eval (car last))))
         (ptr      rest)
         (top-rest ""))
    ;;(if (eq e-body nil) (debug))
    (assert (or (eq (car e-body) 'cprogn) (eq (car e-body) 's) (eq (car e-body) 'f) (eq (car e-body) 'sc) (eq e-body nil)))
    (if (eq (car last) 'null)
        (progn
         (setq top-rest "= null")
         ;;(debug)
          )
      (while (not (eq ptr last))
        (setq top-rest (concat top-rest (c--process (car ptr) 'f)))
        (setq ptr (cdr ptr))))
    `(list 'c-method ,e-ret ,(format "%s%s" name (if (eq (car args) 'c-arg)
                                                     (concat "(" (cadr e-args) ")")
                                                   (cadr e-args))) ,top-rest ,(cond
                                                                               ((eq e-body nil)
                                                                                ";")
                                                                               ((eq (car e-body) 'cprogn)
                                                                                (cadr e-body))
                                                                               ((eq (car e-body) 'cswitch)
                                                                                (cadr e-body))
                                                                               ((eq (car e-body) 's)
                                                                                (concat "{\n" (cadr e-body) "\n}"))
                                                                               ((eq (car e-body) 'f)
                                                                                (concat "{\n" (cadr e-body) ";\n}"))
                                                                               ))))

;; (c-static-method (c-ret void) static_method (c-args) (cprogn (s (b 123))))
;; (c-static-method (c-ret void) static_method (c-arg) (cprogn (s (b 123))))
(defmacro c-static-method (return-type name args &rest rest)
  (assert (symbolp name))
  (assert (or (eq (car args) 'c-args) (eq (car args) 'c-arg)))
  (assert (eq (car return-type) 'c-ret))
  (let* ((e-args   (eval args))
         (e-ret    (c--process return-type 'c-ret))
         (last     (last rest))
         (e-body   (eval (car last)))
         (ptr      rest)
         (top-rest ""))
    (assert (or (eq (car e-body) 'cprogn) (eq (car e-body) 's) (eq (car e-body) 'f)))
    (while (not (eq ptr last))
      (setq top-rest (concat top-rest (c--process (car ptr) 'f)))
      (setq ptr (cdr ptr)))
    `(list 'c-static-method ,e-ret ,(format "%s%s" name (if (eq (car args) 'c-arg)
                                                            (concat "(" (cadr e-args) ")")
                                                          (cadr e-args))) ,top-rest ,(cond
                                                                                 ((eq (car e-body) 'cprogn)
                                                                                  (cadr e-body))
                                                                                 ((eq (car e-body) 'cswitch)
                                                                                  (cadr e-body))
                                                                                 ((eq (car e-body) 's)
                                                                                  (concat "{\n" (cadr e-body) "\n}"))
                                                                                 ((eq (car e-body) 'f)
                                                                                  (concat "{\n" (cadr e-body) ";\n}"))
                                                                                 ))))

;; (fuck int abc)
;; (c-submode-var int abc)
;; (c-property int abc)
;; (c-property int prop [10] [20])
;; (c-property int (b *callback)(b))
;; (c-property ptr<List_A<Menu_Button_A>> abc)
(defmacro c-property (&rest rest)
  (let ((ptr    rest)
        (result ""))
    (while ptr
      (setq result (concat result " " (c--process (car ptr) 'b)))
      (setq ptr (cdr ptr)))
    `(list 'c-property ,result)))

;; (c-static-property char** static_property[10][20])
;; (c-static-property (char** static_property)(b))
(defmacro c-static-property (&rest rest)
  (let ((ptr    rest)
        (result ""))
    (while ptr
      ;;(debug)
      (setq result (concat result " " (if (and (consp (car ptr)) (or (eq (caar ptr) 'b) (eq (car ptr) 'b)))
                                          (c--process (car ptr) 'b)
                                        (prin1-to-string (car ptr)))))
      (setq ptr (cdr ptr)))
    ;;(assert (string-match "[*][a-z][A-Za-z0-9_]*" result))
    `(list 'c-static-property ,result)))

(defun c-private ()
  (list 'c-private "\nprivate:\n"))

(defun c-public ()
  (list 'c-public "\npublic:\n"))

(defun c-protected ()
  (list 'c-protected "\nprotected:\n"))

;; (c-extends )
;; (c-extends Foo)
;; (c-extends Foo Bar)
(defmacro c-extends (&rest parent-class-list)
  (let ((ptr parent-class-list)
        (result ": public ")
        (count 0))
    (while ptr
      (setq result (format "%s%s%s" result (if (/= count 0) "," "") (car ptr)))
      (incf count)
      (setq ptr (cdr ptr)))

    `(list 'c-extends ,(if (string= result ": public ") "" result))))

;; (setq class-name "Apple")
(setq in-class nil)

(defmacro c-class (class-name extends &rest method-list)
  (message "*** started c-class class=%s" class-name)
  (let ((in-class t) class-hh class-ch e-extends extends-list)
    (assert (symbolp class-name))
    (setq class-name-string (format "%s" class-name))
    (setq class-hh (concat directory "/" class-name-string ".hh"))
    (setq class-ch (concat directory "/" class-name-string ".ch"))
    (setq e-extends (eval extends))
    (if (consp e-extends) (assert (eq (car e-extends) 'c-extends)))
    (setq extends-list (cdr extends))
    ;;(setq direct-parent-class (cons (cons class-name (copy-list (cdr extends))) direct-parent-class))
    ;;(progn ;;save-excursion
    ;;(find-file class-hh)
    ;;(goto-char (point-max))
    ;;(debug)
    ;;(debug)
    (let (ptr)
      (save-excursion
        (when (not (string= class-hh global-hh))
          (find-file class-hh)
          (goto-char (point-min))
          (insert "#include \"" (file-name-nondirectory global-hh) "\"\n\n")
          (goto-char (point-max))
          (setq ptr extends-list)
          (while ptr
            ;;(debug)
            (if (not (eq 'Auto_G_C (car ptr))) ;; NOTE: hack
                (progn
                  ;;(delete-char 1)
                  ;;(debug)
                  (goto-char (point-max))
                  (backward-delete-char 1)
                  (insert "#include \"" (prin1-to-string (car ptr)) ".hh\"\n\n")
                  ;;(if (string= (expand-file-name "~/3-libd/2011/Arithmetickles/Abstract_Term_A.hh") class-hh) (debug))
                  ;;(insert "FROGGER\n")
                  ;;(goto-char (point-min))
                  ;;(insert "********************************************************\n")
                  ;;(debug)
                  )
              )
            (setq ptr (cdr ptr))
            )
          (insert (format "class %s%s\n{\n" class-name-string (if (cadr e-extends) (cadr e-extends) "")))
          ;;(debug)
          ;;(insert "SEXY")
          ))
      (save-excursion
        ;;(message "*** farticus")
        (find-file global-hh)
        (goto-char (point-min))
        (insert (format "class %s;\n" class-name-string)))
      (save-excursion
        (find-file global-cc)
        (goto-char (point-min))
        (insert "#include \"" (file-name-nondirectory class-hh) "\"\n")
        (re-search-forward "#include \".*\\.ch\"" nil t)
        (forward-line 1)
        (beginning-of-line)
        (insert "#include \"" (file-name-nondirectory class-ch) "\"\n")
        )
      (save-excursion
        (if (string= class-hh global-hh)
            (progn
              (find-file class-hh)
              (goto-char (point-max))
              (insert (format "class %s\n{" class-name-string))))
        (let ((ptr       method-list)
              (is-static nil)
              thing
              method--return-type
              method--name-and--args
              method--top-rest method--body
              pure-virtual)
          (while ptr
            ;;(debug)
            (setq thing (eval (car ptr)))
            ;;(debug)
            (cond
             ((or (eq (nth 0 thing) 'c-static-method) (eq (nth 0 thing) 'c-method))
              (setq is-static (eq (nth 0 thing) 'c-static-method))
              (setq method--return-type    (format "%s" (nth 1 thing)))
              (setq method--name-and--args (format "%s" (nth 2 thing)))
              (setq method--top-rest       (format "%s" (nth 3 thing)))
              (setq method--body           (format "%s" (nth 4 thing)))
              (setq pure-virtual (string= method--top-rest "= null"))
              ;;(if pure-virtual (debug))
              (save-excursion
                (find-file class-hh)
                (goto-char (point-max))
                (insert (if is-static "static " "")
                        method--return-type
                        " "
                        method--name-and--args (if pure-virtual "= null" "")
                        ";\n"))
              (if (not pure-virtual)
                  (save-excursion
                    (find-file class-ch)
                    (goto-char (point-max))
                    ;; CULL virtual
                    (when (string-match "\\(virtual\\)" method--return-type)
                      ;;(debug)
                      (setq method--return-type
                            (concat (substring method--return-type 0 (match-beginning 1))
                                    (substring method--return-type (match-end 1)))))
                    (insert "\n"
                            method--return-type
                            " "
                            class-name-string
                            "::"
                            method--name-and--args method--top-rest
                            "\n"
                            method--body
                            "\n"))))
             ((or (eq (nth 0 thing) 'c-private) (eq (nth 0 thing) 'c-public) (eq (nth 0 thing) 'c-protected))
              (save-excursion
                (find-file class-hh)
                (goto-char (point-max))
                (insert (nth 1 thing))
                ))
             ((or (eq (nth 0 thing) 'c-property) (eq (nth 0 thing) 'c-static-property))
              (setq is-static (eq (nth 0 thing) 'c-static-property))
              (save-excursion
                ;;(debug)
                (find-file class-hh)
                (goto-char (point-max))
                ;;(debug)
                (setq result (nth 1 thing))
                (while (string-match "\\(.*\\)>>\\(.*\\)" result)
                  ;;(debug)
                  (setq result (concat
                                (substring result (match-beginning 1) (match-end 1))
                                "> >"
                                (substring result (match-beginning 2) (match-end 2))))
                  )
                (insert (if is-static "static " "") result ";\n"))
              (if is-static
                  (let (result)
                    (save-excursion
                      (find-file class-ch)
                      (goto-char (point-max))
                      ;;(setq result " int (*callback) ()")
                      (setq result (nth 1 thing))
                      ;;(debug)
                      (if (string-match "\\( [a-zA-Z_<>]+\\)[ \t]+\\([a-z_]+\\)" result)
                          (progn
                            (setq result (concat (substring result 0 (match-end 1))
                                                 " " class-name-string "::"
                                                 (substring result (match-beginning 2))))
                            (while (string-match "\\(.*\\)>>\\(.*\\)" result)
                              ;;(debug)
                              (setq result (concat
                                            (substring result (match-beginning 1) (match-end 1))
                                            "> >"
                                            (substring result (match-beginning 2) (match-end 2))))
                              )
                            ;;(insert "\n" result ";\n")
                            )
                        (assert (string-match "[*]+[ \t]\\([a-z][A-Za-z0-9_]*\\)" result))
                        (setq result (concat (substring result 0 (match-beginning 1))
                                             class-name-string "::"
                                             (substring result (match-beginning 1)))))
                      (insert "\n" result ";\n"))
                    ))))
            (setq ptr (cdr ptr)))
        ))
      ;;(if (eq 'Abstract_Term_A (cadr extends)) (debug))
      (save-excursion
        (find-file class-hh)
        ;;(goto-char (point-min))
        ;;(when (re-search-forward "\n\n\\(public\\|private\\|protected\\)")
        ;; (skip-chars-backward "a-z")
        ;; (backward-delete-char 1))
        (goto-char (point-max))
        (insert "};\n\n")
        ;;(insert "FUCK")
        (indent-region (point-min) (point-max))
        )
      ;;(if (string= class-name-string "Term_A") (debug))
      (save-excursion
        (find-file class-ch)
        (indent-region (point-min) (point-max))
        )
      (save-some-buffers 'NO-QUESTIONS)
      (kill-buffer (find-file class-hh))
      (kill-buffer (find-file class-ch))
      (message "*** ended c-class class=%s" class-name)
      nil
      )
    )
  )

;;(c-friend (c-ret Writer&) operator<< (c-args (c-arg Writer& w) (c-arg String_Sample_A& s)) (cprogn (s w << (f string_quoted s.name) << " " sc)))
(defmacro c-friend (return-type name args body)
  (assert (consp return-type))
  (assert (eq (car return-type) 'c-ret))
  (assert (consp args))
  (assert (or (eq (car args) 'c-args) (eq (car args) 'c-arg)))
  ;;(assert (eq (car args) 'c-args))
  (let ((name (format "%s" name))
        (e-return-type (eval return-type))
        (e-args        (eval args))
        (e-body        (eval body)))
    ;;(if (string= name "pred")
    ;;    (debug))
    (save-excursion
      (find-file class-hh)
      (goto-char (point-max))
      (insert (concat "friend " (cadr e-return-type) " " name (if (eq (car args) 'c-arg)
                                                                  (concat "(" (cadr e-args) ")")
                                                                (cadr e-args)) ";\n"))
      ;;(indent-region (point-min) (point-max))
      )
    (save-excursion
      (find-file class-ch)
      (goto-char (point-max))
      (insert "\n")
      (insert (concat (cadr e-return-type) " " name (if (eq (car args) 'c-arg)
                                                        (concat "(" (cadr e-args) ")")
                                                      (cadr e-args)) "\n" (cond
                                                                           ((eq (car e-body) 'cprogn)
                                                                            (cadr e-body))
                                                                           ((eq (car e-body) 'cswitch)
                                                                            (cadr e-body))
                                                                           ((eq (car e-body) 's)
                                                                            (concat "{\n" (cadr e-body) "\n}"))
                                                                           ((eq (car e-body) 'f)
                                                                            (concat "{\n" (cadr e-body) ";\n}"))
                                                                           (t
                                                                            (assert nil))) "\n"))
      ;;(indent-region (point-min) (point-max))
      )
    ;;(debug)
    ;;`(list 'c-friend ,(concat (eval ret) name (eval args) (eval body))))
    )
  nil
  )

;; (c-function (c-ret void) function_name (c-args (c-arg int i)) (cprogn (s 4 * 5 sc)))
;; (setq name 'main)
(defmacro c-function (return-type name args body)
  (assert (symbolp name))
  (setq name (format "%s" name))
  (assert (consp return-type))
  (assert (eq (car return-type) 'c-ret))
  (assert (consp args))
  (assert (or (eq (car args) 'c-args) (eq (car args) 'c-arg)))
  (checkpoint "f1")
  (let ((e-return-type (eval return-type))
        (e-args (eval args))
        (e-body (eval body)))
    (save-excursion
      (checkpoint "f2")
      (find-file global-hh)
      (goto-char (point-max))
      (insert (concat (cadr e-return-type) " " name (if (eq (car args) 'c-arg)
                                                        (concat "(" (cadr e-args) ")")
                                                      (cadr e-args)) ";\n"))
      (checkpoint "f3")
      ;;(indent-region (point-min) (point-max))
      )
    (save-excursion
      (checkpoint "f4")
      (find-file global-cc)
      (goto-char (point-max))
      (insert "\n")
      (insert (concat (cadr e-return-type) " " name (if (eq (car args) 'c-arg)
                                                        (concat "(" (cadr e-args) ")")
                                                      (cadr e-args)) "\n" (cond
                                                                           ((eq (car e-body) 'cprogn)
                                                                            (cadr e-body))
                                                                           ((eq (car e-body) 'cswitch)
                                                                            (concat "{\n" (cadr e-body) "\n}"))
                                                                           ((eq (car e-body) 's)
                                                                            (concat "{\n" (cadr e-body) "\n}"))
                                                                           ((eq (car e-body) 'f)
                                                                            (concat "{\n" (cadr e-body) ";\n}"))
                                                                           ) "\n"))
      ;;(indent-region (point-min) (point-max))
      ;;(if (string= name "func") (debug))
      (checkpoint "f5")
      )
    )
  nil
  )

;; (setq file "iostream")
;; (c-include (setq file '<iostream>)
(setq c-include-count 0)

(defmacro c-include (file)
  (setq c-include-list (cons file c-include-list))
  nil)

(quote

 (cprogn
  (cif (b 1 ==  0) (s std::cout << "foo\n" sc))
  (cif (b 1 == 0) (s std::cout << "foo\n" sc))
  (b fuck << std::cout << "\"abc\ndef" (cif? (b 1 == 0) (b if_part) (b else_part)))
  (s abc + (b 2 + 3))
  (s 1 + (b 2 + 3))
  (s abc + (b 2 + 3))
  (b 1 * (b 2 + 3 + "abc\n") - (f myfunc abc def))
  (s (cif (b 1 != 0) (f foo) (f bar)) sc)
  (s foo + abc)
;;  (c-args (c-arg int x))
  )

 )

;;
;; s 123 + 456 sc useful for the 1st part of for loops and introducing local variables
;; s (123 + 456) sc useful for most stuff
;;
;; (c-class a)
;; in a file called a.hh a.ch ... a.hh includes global.hh . Contains:
;;
;; class A
;; class B
;; class C
;; and function prototypes
;;
;; global.cc includes a.ch, b.ch, c.ch and contains functions
;;
;; Fred.hh Fred.ch
;;

;; (c-compile-project (setq directory "~/3-libd/2010/Arithmetickles"))
(defun c-compile-project ()
  (interactive)
  ;;(interactive "DEnter directory: ")
  (checkpoint 1.1)
  ;;(setq directory (safe-expand-file-name directory))
  ;;(setq directory (expand-file-name "~/3-libd/mylpp"))
  (setq directory (expand-file-name "~/3-libd/2011/Arithmetickles"))
  ;;(setq directory (safe-expand-file-name "~/3-libd/mylpp"))
  (let ((ptr (buffer-list)))
    (while ptr
      (set-buffer (car ptr))
      (when (eq major-mode 'c++-mode)
        (save-buffer)
        (kill-buffer nil))
      (setq ptr (cdr ptr))))
  (if (not (directory-files directory nil "\\.lpp$"))
      (error "No *.lpp files found"))
  (mapcar 'delete-file (directory-files directory t "\\.\\(cc\\|ch\\|hh\\)$"))
  (checkpoint 1.2)
  (let ((c-include-list nil)
        (list           (directory-files directory t "\\.lpp$"))
        (global-hh nil)
        (global-cc nil))
    (assert (file-directory-p directory))
    (checkpoint 1.3)
    (progn
      ;;
      ;; COOL: The main file is now at the end of the list
      ;;
      (if (string-match "/$" directory) (setq directory (substring directory 0 (1- (length directory)))))
      (setq title-less-extension (file-name-nondirectory directory))
      (setq global-cc (concat directory "/" title-less-extension ".cc"))
      (setq global-hh (concat directory "/" title-less-extension ".hh"))
      (setq project-title (concat directory "/" title-less-extension ".lpp"))
      (when (> (length list) 1)
        (setq list (remove project-title list))
        (setcdr (last list) (cons project-title nil))
        )
      )
    (checkpoint 1.4)
    ;;(debug)
    ;;(debug)
    (let ((ptr                 list)
          ;;(direct-parent-class nil)
          (f                   nil))
      (while ptr
        (save-excursion
          (set-buffer (setq f (find-file (car ptr))))
          (message "**** BEGIN evaling buffer %s" (buffer-name))
          (checkpoint 1.41)
          (eval-buffer)
          (checkpoint 1.42)
          (message "**** END evaling buffer %s" (buffer-name))
          (kill-buffer f)
          ;;(debug)
          )
        (setq ptr (cdr ptr)))
      ;;(debug)
      (checkpoint 1.5)
      (save-excursion
        (set-buffer (find-file global-hh))
        (goto-char (point-min))
        (setq ptr (reverse c-include-list))
        (while ptr
          (if (symbolp (car ptr))
              (insert (format "#include %s\n" (car ptr)))
            (insert (format "#include \"%s\"\n" (car ptr))))
          (setq ptr (cdr ptr)))
        (save-buffer)
        ;;(debug)
        ))
    ;;(debug)
    (checkpoint 1.7)
    (setq list (directory-files directory t "\\.hh$"))
    (setq ptr list)
    ;;(debug)
    (save-excursion
      (set-buffer (find-file global-hh))
      (goto-char (point-min))
      (c-raw-splat "#define COMMA , /* smelly */ \n")
      )
    (while ptr
      (setq str (progn
                  (assert (string-match "\\([a-zA-Z0-9_-]*\\)\\.hh$" (car ptr)))
                  (setq str (substring (car ptr) (match-beginning 1) (match-end 1)))
                  ;; (setq str "Apple-Banana")
                  (while (string-match "\\(.*\\)-\\(.*\\)" str)
                    (setq str (concat (substring str (match-beginning 1) (match-end 1))
                                      "_"
                                      (substring str (match-beginning 2) (match-end 2)))))
                  (setq str (concat "ALREADY_INCLUDED_" (upcase str) "_HH"))))
      (find-file (car ptr))
      (goto-char (point-min))
      (insert "#ifndef " str "\n")
      (insert "#define " str "\n\n")
      (goto-char (point-max))
      (insert "\n#endif /* " str " */\n")
      (setq ptr (cdr ptr)))
    (checkpoint 1.8)
    (save-excursion
      (set-buffer (find-file global-hh))
      ;;(goto-char (point-min))
      ;;(c-raw-splat "#define comma , /* foo */ \n")
      (indent-region (point-min) (point-max))
      (save-some-buffers 'NO-QUESTIONS)
      (kill-buffer (find-file global-hh)))
    (checkpoint 1.9)
      (save-excursion
        (set-buffer (find-file global-cc))
        (indent-region (point-min) (point-max))
        (save-some-buffers 'NO-QUESTIONS)
        (kill-buffer (find-file global-cc)))
      (let ((ptr (buffer-list)))
        (while ptr
          (set-buffer (car ptr))
          (when (eq major-mode 'c++-mode)
            (save-buffer)
            (kill-buffer nil))
          (setq ptr (cdr ptr))))
      ;;(if (eq major-mode 'c++-mode) (kill-buffer nil))
      (dired directory)
      (revert-buffer)
      (checkpoint 1.10)
      )
  )

(defmacro c-raw-class-hh (&rest list)
  (assert in-class)
  ;;(debug)
  (save-excursion
    (let ((result "")
          (ptr    list))
      (set-buffer (find-file class-hh))
      (goto-char (point-max))
      (while ptr
        (setq result (concat result " " (if (eq (car ptr) 'sc)
                                            ";"
                                          (prin1-to-string (car ptr)))))
        (setq ptr (cdr ptr)))
      (insert result "\n")
      )
    )
  nil)

(defmacro c-raw-global-cc (&rest list)
  (assert (not in-class))
  (let (ptr)
    (save-excursion
      ;;(message "**** c-raw-global-cc buf=%s" (buffer-name))
      (set-buffer (find-file global-cc))
      (goto-char (point-max))
      (setq ptr list)
      (while ptr
        (insert (c--process (car ptr) 'b) " ")
        (setq ptr (cdr ptr)))
      (insert ";\n")))
  nil)

;; (c-raw-global-hh \#define comma ,)
(defmacro c-raw-global-hh (&rest list)
  (assert (not in-class))
  (let (ptr)
    (save-excursion
      ;;(message "**** c-raw-global-cc buf=%s" (buffer-name))
      (set-buffer (find-file global-hh))
      (goto-char (point-min))
      (setq ptr list)
      (while ptr
        (insert (c--process (car ptr) 'b 'c-raw-global-hh) " ")
        (setq ptr (cdr ptr)))
      (insert ";\n")))
  nil)

(defmacro c-raw-splat (str)
  (save-excursion
    (set-buffer (find-file global-hh))
    (goto-char (point-min))
    (insert str)))

(defmacro c-enum (enum list)
  (checkpoint 1)
  (assert (not in-class))
  (let (ptr)
    (save-excursion
      (setq list (eval list))
      (setq ptr list)
      (find-file global-hh)
      (goto-char (point-min))
      (insert (format "enum %s\n{\n" enum))
      (while ptr
        (assert (eq (caar ptr) 'c-item))
        (let ((ptr2 (cdar ptr)))
          (while ptr2
            (insert " " (prin1-to-string (car ptr2)))
            (setq ptr2 (cdr ptr2))))
        (insert ",\n")
        (setq ptr (cdr ptr)))
      (insert "};\n")
      (indent-region (point-min) (point-max))
      (checkpoint 2))))

;; (setq rest '(int abc))
;; (c-property-inited int abc)
;; (setq name "abc")
(quote (defmacro c-property-inited (&rest rest)
  (let ((ptr    rest)
        (result "")
        (name   (nth 1 rest)))
    (while ptr
      (setq result (concat result " " (c--process (car ptr))))
      (setq ptr (cdr ptr)))
    (concat (list 'c-property result) ";" (list 'c-property "safe_bool" (read (format "inited_%s" name))) ";"))))

(global-set-key [(kp-enter)] 'lpp)

(defun lpp ()
  (interactive)
  (setq b (find-file "~/dlisp/lpp.lpp"))
  (switch-to-buffer b))

(provide 'lpp)


