packages feed

structured-haskell-mode-1.0.3: elisp/shm-constraint.el

;;; shm-constraint.el --- Constraint editing functions.

;; Copyright (c) 2014 Chris Done. All rights reserved.

;; This file is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.

;; This file is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with this program.  If not, see <http://www.gnu.org/licenses/>.

;;; Code:

(require 'shm-ast)

(defun shm/modify-type-constraint ()
  "Modify a type signatures constraint"
  (interactive)
  (let* ((pair (shm-current-node-pair))
         (current-node (cdr pair)))
    (if (shm-type-signature-with-constraint-p pair)
        (shm-add-additional-type-constraint current-node)
      (add-initial-type-constraint current-node))))

(defun shm-add-additional-type-constraint (node)
  (if (shm-constraint-has-parens-p node)
      (progn
        (shm-goto-end-of-constraint node)
        (backward-char 1)
        (insert ", "))
    (goto-char (shm-node-start node))
    (insert "(")
    (shm-goto-end-of-constraint node)
    (insert ", )")
    (backward-char 1)))

(defun add-initial-type-constraint (node)
  (goto-char (shm-node-start node))
  (insert " => ") (backward-char 4))

(defun shm-top-level-type-decl-p (node-pair)
  (let ((current-node (cdr node-pair)))
    (if (and (not (shm-has-parent-with-matching-type-p node-pair))
             (string= "Type SrcSpanInfo" (shm-node-type current-node))) t)))

(defun shm-type-signature-with-constraint-p (pair)
  (let ((current-node (cdr pair)))
    (and (shm-top-level-type-decl-p pair)
         (shm-node-syntax-contains-regex "=>" current-node))))

(defun shm-constraint-has-parens-p (node)
   (let* ((syntax (shm-concrete-syntax-for-node node))
          (constraint-syntax (car (split-string syntax "=>"))))
     (string-match-p ")" constraint-syntax)))

(defun shm-goto-end-of-constraint (node)
  "Set point to the first white-space character between the end of the type constraint and the '=>'"
  (goto-char (+ (shm-node-start node)
                (shm-node-syntax-contains-regex "=>" node)))
  (re-search-backward "^\\|[^[:space:]]") (goto-char (+ (point) 1)))

(defun shm-node-syntax-contains-regex (regex node)
  "check the syntax of a node for an occurrence of pattern"
  (let ((node-concrete-syntax (shm-concrete-syntax-for-node node)))
    (string-match-p regex node-concrete-syntax)))

(defun shm-concrete-syntax-for-node (node)
  "Get the concrete syntax of the node"
  (buffer-substring-no-properties
   (shm-node-start (shm-current-node))
   (shm-node-end (shm-current-node))))

(defun shm-has-parent-with-matching-type-p (node-pair)
  (let* ((current (cdr node-pair))
         (parent-pair (shm-node-parent node-pair (shm-node-type current)))
         (parent (cdr parent-pair)))
    (if parent
        (if (string= (shm-node-type current)
                     (shm-node-type parent)) t))))

(provide 'shm-constraint)