Advertisement
Guest User

common.lisp

a guest
Jul 22nd, 2011
274
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lisp 9.79 KB | None | 0 0
  1. ;;; common.lisp - aggregator of different tools
  2. ;;; used in scripts
  3. ;;; author: Necto
  4. ;;; uses pregexp.lisp - library for work with regular expressions
  5.  
  6. (defun lib/ (str)
  7.   (if (find-symbol "+/CL+")
  8.     (concatenate 'string +/cl+ str)
  9.     str))
  10.  
  11. (load (lib/ "pregexp.lisp") :verbose nil)
  12.  
  13. (if (find-symbol "+CMD-ARGS+")
  14.     (defun symbol-mentioned-in-params (symb)
  15.       (find symb +cmd-args+)))
  16.  
  17. ;; Predicate checks if some keywords are given
  18. (defun verbose-enabled-p ()
  19.   (and (find-symbol "+CMD-ARGS+")
  20.        (or (find 'talkative +cmd-args+)
  21.            (find 'verbose +cmd-args+))))
  22.  
  23. ;; A output stream which you can enable by taking option "talkative"
  24. ;; to a script using it
  25. (defconstant extra-out (if (verbose-enabled-p)
  26.                          t
  27.                          (make-string-output-stream)))
  28.  
  29. (defconstant +max-syms-in-line+ 10000)
  30.  
  31. ;; Also if user doesn't want to view all it's loads, disable it:
  32. (setf *load-verbose* (verbose-enabled-p))
  33.  
  34.  
  35. ;; process every line in given stream
  36. (defmacro for-every-line-in-file (file line &rest body)
  37.   `(loop for ,line = (read-line ,file nil nil)
  38.             then    (read-line ,file nil nil)
  39.          while ,line do ,@body))
  40.  
  41. ;; append to given dir list some directories
  42. (defun sub-dir (dir &rest dirs)
  43.   (append (if (pathnamep dir)
  44.               (pathname-directory dir)
  45.               dir)
  46.           dirs))
  47.  
  48. ;; make pathname for directory inside given path
  49. (defmacro sub-dir-path (dir &rest dirs)
  50.   `(make-pathname :directory (sub-dir ,dir ,@dirs)))
  51.  
  52. ;; open any file with name=name and type=type in given directory, and
  53. ;; execute if-exists form, if file exists, and
  54. ;; if-missing form, otherwise
  55. (defmacro with-open-any-file (file dir name type direction if-exists if-missing)
  56.   (let ((path-name (gensym))
  57.         (dir-list `(if (pathnamep ,dir) (pathname-directory ,dir) ,dir)))
  58.     `(let ((,path-name (directory (make-pathname :directory ,dir-list
  59.                                                  :name ,name :type ,type))))
  60.        (if ,path-name
  61.            (with-open-file (,file (first ,path-name);get single file
  62.                                   :direction ,direction
  63.                                   :if-does-not-exist nil)
  64.              (if ,file
  65.                  ,if-exists
  66.                  ,if-missing))
  67.        ,if-missing))))
  68.  
  69. ;; process each file, satisfying to the given path pattern
  70. (defmacro process-every-file (file path-pattern direction &rest body)
  71.   (let ((path-name (gensym)))
  72.     `(dolist (,path-name (directory ,path-pattern))
  73.        (with-open-file (,file ,path-name :direction ,direction)
  74.          ,@body))))
  75.  
  76. ;; find first file, according to given path pattern
  77. (defun a-path (path-pattern)
  78.   (car (directory path-pattern)))
  79.  
  80. ;; parse string "+354.2" to float value 345.2
  81. (defun parse-float (str)
  82.   (let ((dotted-pair (pregexp-match " *([-+]?[0-9]*)[.]([0-9]+)" str))
  83.         (int (pregexp-match " *[+-0-9]+" str)))
  84.     (float
  85.       (if dotted-pair
  86.         (+ (parse-integer (second dotted-pair))
  87.            (let ((after-dot (parse-integer (third dotted-pair))))
  88.              (do ((mantiss after-dot (/ mantiss 10)))
  89.                ((< mantiss 1) mantiss))))
  90.         (parse-integer int)))))
  91.  
  92. ;; substitute symbols for each given pair
  93. (defmacro subst-many (new+old tree)
  94.   (labels ((subst-rec (new+old tree)
  95.                       (cond ((null new+old) tree)
  96.                             (t `(subst ,(caar new+old) ,(cadar new+old)
  97.                                        ,(subst-rec (cdr new+old) tree))))))
  98.     (subst-rec new+old tree)))
  99.  
  100. ;; bind each value to given symbols, calling, if exists,
  101. ;; corresponding function before binding, and join it,
  102. ;; if a number cpecified, for example:
  103. ;; ("fdg" 34 23 t) : (a (b '1+ 1) (c :rest)) ->
  104. ;; (let ((a "fdg") (b (list (1+ 34)) (c (list 23 t)))
  105. ;;   body)
  106. (defmacro list-bind (list-form symbols &rest body)
  107.   (let ((list-name (gensym))
  108.         (n 0))
  109.     (labels ((get-val1 (processor)
  110.                 (prog1
  111.                     (if processor
  112.                         `(,processor (nth ,n ,list-name))
  113.                         `(nth ,n ,list-name))
  114.                     (incf n)))
  115.              (get-valK (processor K)
  116.                 `(list ,@(loop repeat k
  117.                                collect (get-val1 processor))))
  118.              (get-val-rest (processor)
  119.                 `(subseq ,list-name ,n))
  120.              (push-sym (sym)
  121.                 (if (symbolp sym)
  122.                     (list sym (get-val1 nil))
  123.                     (if (and (listp sym) sym) ;list contains at least one element
  124.                       (let ((val (if (numberp (second sym))
  125.                                      (get-valK (third sym) (second sym))
  126.                                      (if (eq (second sym) :rest)
  127.                                          (get-val-rest (third sym))
  128.                                          (get-val1 (second sym))))))
  129.                         (if (first sym) ;if first token is nil, then omit certain amount of elements
  130.                           (list (first sym) val)))
  131.                       (incf n))))) ;omit element
  132.     `(let ((,list-name ,list-form))
  133.         (if ,list-name
  134.             (let ,(loop for sym in symbols
  135.                         collect (push-sym sym))
  136.                  ,@body))))))
  137.  
  138. ;; parse integer, if it is really integer string representation
  139. (defun safe-parse-integer (arg)
  140.   (if (pregexp-match "^ *[-+]?[0-9]+" arg)
  141.     (parse-integer arg)))
  142.  
  143. ;; parse float, if it is really floating point string representation
  144. (defun safe-parse-float (arg)
  145.   (if (pregexp-match "^ *[-+]?[0-9]+[.]?[0-9]*" arg)
  146.     (parse-float arg)))
  147.  
  148. ;; abbreviate some useful functions to short symbols
  149. (defun expand-abbreviations (symbs)
  150.   (subst-many (('parse-integer :i)
  151.                ('parse-float :f)
  152.                ('safe-parse-integer :si)
  153.                ('safe-parse-float :sf)
  154.                ('identity t))
  155.               symbs))
  156.  
  157. ;; parse string, and bind certain groups to corresponding symbols
  158. (defmacro parse-let (regexp line symbs &rest body)
  159.  `(if (> (length ,line) +max-syms-in-line+)
  160.     (format extra-out "~%warning! line \"~a...\"(~a) exceeds maximum lenght(~a) for match~%"
  161.             (subseq ,line 0 15)
  162.             (length ,line)
  163.             +max-syms-in-line+)
  164.    ,(if (listp symbs)
  165.      `(list-bind (cdr (pregexp-match ,regexp ,line))
  166.                 ,(expand-abbreviations symbs)
  167.           ,@body)                                             ;bind all groups to separate symbol
  168.      `(let ((,symbs (car (pregexp-match ,regexp ,line))))     ;bind only whole match
  169.         (when ,symbs ,@body)))))
  170.  
  171. ;; process every line, satisfying given pattern, with parsing it to given symbols
  172. (defmacro for-every-appropriate-line (file pattern symbols &rest body)
  173.   (let ((line-name (gensym)))
  174.   `(for-every-line-in-file ,file ,line-name
  175.     (parse-let ,pattern ,line-name ,symbols ,@body))))
  176.  
  177. ;; sum all hash values or keys
  178. (defun for-hash (table &key (summarize :values sum-suplied-p))
  179.   (let ((sum 0))
  180.     (flet ((add-val (key val)
  181.                     (setf sum (+ val sum)))
  182.            (add-key (key val)
  183.                     (setf sum (+ key sum))))
  184.       (maphash (if (or (eq summarize :values)
  185.                        (eq summarize :val)
  186.                        (eq summarize :value))
  187.                    #'add-val #'add-key)
  188.                table)
  189.       (if sum-suplied-p sum))))
  190.  
  191. ;; bind the sym to the val, and evaluate body if it is not null
  192. (defmacro let-if-non-null (sym val &rest body)
  193.   `(let ((,sym ,val))
  194.      (if ,sym
  195.        (progn ,@body))))
  196.  
  197. ;; expand list with quantifiers like ( ... (5 a) ... )
  198. ;; to a plain list: ( ... a a a a a ... )
  199. (defun expand-quantifiers (list)
  200.   (let (result)
  201.     (dolist (entry list (reverse result))
  202.       (if (and (listp entry)
  203.                (numberp (first entry)))
  204.         (dotimes (i (first entry)) (setf result (append (cdr entry) result)))
  205.         (push entry result)))))
  206.  
  207. ;; read a standart representation of a object from file, named fname
  208. (defun init-obj (fname &key (reader #'read))
  209.   (with-open-file (file fname :direction :input :if-does-not-exist nil)
  210.     (if file
  211.       (funcall reader file))))
  212.  
  213. ;; check file file-name, if it exists, read value from it, or eval fun,
  214. ;; and store it's value otherwise
  215. (defun eval-or-read (file-name fun &key (reader #'read) (writer #'print))
  216.   (with-open-file (store file-name :direction :output :if-exists nil)
  217.     (if store
  218.       (let ((val (funcall fun)))
  219.         (funcall writer val store)
  220.         val)
  221.       (progn
  222.         (format extra-out "~%using stored value at ~a" file-name)
  223.         (init-obj file-name :reader reader)))))
  224.  
  225. ;; get a single value from a string by given pattern
  226. (defmacro extract (pattern str &optional (type nil type-supplied-p))
  227.   (let ((val-name (gensym)))
  228.     `(parse-let ,pattern ,str (,(if type-supplied-p
  229.                                   (list val-name type)
  230.                                   val-name))
  231.        ,val-name)))
  232.  
  233. ;; extract all matches of given pattern from str
  234. (defun all-matches (pattern str)
  235.   (loop for positions = (first (pregexp-match-positions pattern str))
  236.                    then (first (pregexp-match-positions pattern str (cdr positions)))
  237.         while positions
  238.         collect (subseq str (car positions) (cdr positions))))
  239.  
  240. ;; A macro useful for such constructions (let (var) (do stuff with var) var)
  241. ;; you can take a list (var-name initial-form final-transformation) instead
  242. ;; of just var
  243. (defmacro returning (variable &rest body)
  244.   `(let (,(if (atom variable)
  245.              variable
  246.              (list (first variable) (if (cdr variable)
  247.                                       (second variable)))))
  248.      ,@body
  249.      ,(if (atom variable)
  250.         variable
  251.         (if (< (length variable) 3)
  252.           (first variable)
  253.           `(funcall ,(third variable) ,(first variable))))))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement