           (message "Use %s to go back."
                    (substitute-command-keys "\\[merlin-pop-stack]")))
       (save-excursion (save-selected-window (funcall do-open))))))
+
+(defun merlin-parse-position (data)
+  "Position commands return a pair of a physical position (line, col) and a
+logical position (a path in the document)."
+  (cons
+    (merlin-make-point (cdr (assoc 'pos data)))
+    (cdr (assoc 'path data))))
+
+(defun merlin-path-common-prefix (p1 p2)
+  (cond ((equal p1 p2)
+         p1)
+        ((and (listp p1) (listp p2))
+         (let* ((head (list nil))
+                (tail head))
+           (while (and p1 p2 (equal (car p1) (car p2)))
+             (setcdr tail (list (car p1)))
+             (setq tail (cdr tail))
+             (setq p1 (cdr p1))
+             (setq p2 (cdr p2)))
+           (when (and p1 p2)
+             (let ((cell (merlin-path-common-prefix (car p1) (car p2))))
+               (when cell (setcdr tail (list cell)))))
+           (cdr head)))
+        (nil)))
+
+(defun merlin-path-is-recursive (path)
+  (let ((isrec nil))
+    (while (and (not isrec) path (listp path))
+      (setq isrec (merlin-path-is-recursive (car path)))
+      (setq path (cdr path)))
+    (or isrec (and (stringp path)
+                   (or (string-equal path "rec")
+                       (string-equal path "class")
+                       (string-equal path "object"))))))
 
 (defun merlin-make-point (data)
   "Transform DATA (a remote merlin position) into a point."

             (merlin-sync-lock-zone-display))))

(defun merlin-sync-to-point (&optional point)
  "Makes sure the buffer is synchronized on merlin-side and centered around (point)."
  (unless point (setq point (point)))
  (merlin-tell-to-point point)
  (merlin-seek-exact point)
  (merlin-sync-lock-zone-display))

;;;;;;;;;;;;;;;;;;

(defun merlin-pop-stack ()
  "Go back to the last position where the user did a locate."
  (interactive)
  (let ((result (pop merlin-position-stack)))
    (cond ((not result) (message "empty stack"))
          ((equal merlin-locate-in-new-window 'never)
           (switch-to-buffer (car result)))
          ((or (equal merlin-locate-in-new-window 'always)
               (not (equal (buffer-name) (car result))))
           (select-window (display-buffer (car result)))))
    (when result (goto-char (cdr result)))))

;;;;;;;;;;;;;;;;;;;;;;;
;; SEMANTIC MOVEMENT ;;
