1 ;;; sml-oldindent.el --- Navigation and indentation for SML without SMIE
3 ;; Copyright (C) 1999,2000,2004,2007,2012 Stefan Monnier <monnier@gnu.org>
5 ;; This program is free software; you can redistribute it and/or modify
6 ;; it under the terms of the GNU General Public License as published by
7 ;; the Free Software Foundation; either version 3 of the License, or
8 ;; (at your option) any later version.
10 ;; This program is distributed in the hope that it will be useful,
11 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ;; GNU General Public License for more details.
15 ;; You should have received a copy of the GNU General Public License
16 ;; along with this program; if not, write to the Free Software
17 ;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 (eval-when-compile (require 'cl))
28 (defun sml-preproc-alist (al)
29 "Expand an alist AL where keys can be lists of keys into a normal one."
35 (mapcar (lambda (y) (cons y v)) k)
39 (defconst sml-begin-syms
40 '("let" "abstype" "local" "struct" "sig")
41 "Symbols matching the `end' symbol.")
43 (defconst sml-begin-syms-re
44 (sml-syms-re sml-begin-syms)
45 "Symbols matching the `end' symbol.")
47 ;; (defconst sml-user-begin-symbols-re
48 ;; (sml-syms-re '("let" "abstype" "local" "struct" "sig" "in" "with"))
49 ;; "Symbols matching (loosely) the `end' symbol.")
51 (defconst sml-sexp-head-symbols-re
52 (sml-syms-re `("let" "abstype" "local" "struct" "sig" "in" "with"
53 "if" "then" "else" "case" "of" "fn" "fun" "val" "and"
54 "datatype" "type" "exception" "open" "infix" "infixr" "nonfix"
55 ,@sml-module-head-syms
57 "Symbols starting an sexp.")
59 ;; (defconst sml-not-arg-start-re
60 ;; (sml-syms-re '("in" "of" "end" "andalso"))
61 ;; "Symbols that can't be found at the head of an arg.")
63 ;; (defconst sml-not-arg-re
64 ;; (sml-syms-re '("in" "of" "end" "andalso"))
65 ;; "Symbols that should not be confused with an arg.")
67 (defconst sml-indent-rule
70 (,sml-module-head-syms "d=" 0)
73 ;;("else" . (sml-indent-level 0))
74 ;;(("in" "fun" "and" "of") . (sml-indent-level nil))
76 (,sml-=-starter-syms nil)
77 (("abstype" "case" "datatype" "if" "then" "else" "sharing" "infix" "infixr"
78 "let" "local" "nonfix" "open" "raise" "sig" "struct" "type" "val" "while"
79 "do" "with" "withtype")))))
81 (defconst sml-delegate
83 `((("of" "else" "then" "d=") . (not (sml-bolp)))
85 "Words which might delegate indentation to their parent.")
87 (defcustom sml-symbol-indent
95 "Special indentation alist for some symbols.
96 An entry like (\"in\" . 1) indicates that a line starting with the
97 symbol `in' should be indented one char further to the right.
98 This is only used in a few specific cases, so it does not work
99 for all symbols and in all lines starting with the given symbol."
101 :type '(repeat (cons string integer)))
103 (defconst sml-open-paren
105 `((,(list* "with" "in" sml-begin-syms) ,sml-begin-syms-re "\\<end\\>")))
106 "Symbols that should behave somewhat like opening parens.")
108 (defconst sml-close-paren
109 `(("in" "\\<l\\(ocal\\|et\\)\\>")
110 ("with" "\\<abstype\\>")
111 ("withtype" "\\<\\(abs\\|data\\)type\\>")
112 ("end" ,sml-begin-syms-re)
114 ("else" "\\<if\\>" (sml-bolp))
117 "Symbols that should behave somewhat like close parens.")
119 (defconst sml-agglomerate-re "\\<else[ \t]+if\\>"
120 "Regexp of compound symbols (pairs of symbols to be considered as one).")
122 (defvar sml-internal-syntax-table
123 (let ((st (make-syntax-table sml-mode-syntax-table)))
124 (modify-syntax-entry ?_ "w" st)
125 (modify-syntax-entry ?' "w" st)
126 (modify-syntax-entry ?. "w" st)
127 ;; treating `~' as a word constituent is not quite right, but
128 ;; close enough. Think about 12.3E~2 for example. Also `~' on its
129 ;; own *is* a nonfix symbol.
130 (modify-syntax-entry ?~ "w" st)
132 "Syntax table used for internal sml-mode operation.")
138 (defmacro sml-with-ist (&rest r)
139 (let ((ost-sym (make-symbol "oldtable")))
140 `(let ((,ost-sym (syntax-table))
141 (case-fold-search nil)
142 (parse-sexp-lookup-properties t)
143 (parse-sexp-ignore-comments t))
145 (progn (set-syntax-table sml-internal-syntax-table) . ,r)
146 (set-syntax-table ,ost-sym)))))
147 (def-edebug-spec sml-with-ist t)
149 (defmacro sml-move-if (&rest body)
150 (let ((pt-sym (make-symbol "point"))
151 (res-sym (make-symbol "result")))
152 `(let ((,pt-sym (point))
153 (,res-sym ,(cons 'progn body)))
154 (unless ,res-sym (goto-char ,pt-sym))
156 (def-edebug-spec sml-move-if t)
158 (defmacro sml-point-after (&rest body)
162 (def-edebug-spec sml-point-after t)
170 ((">" ">=" "<>" "<" "<=" "=") . 4)
173 (("/" "*" "quot" "rem" "div" "mod") . 7)))
174 "Alist of SML infix operators and their precedence.")
176 (defconst sml-syntax-prec
178 `((("in" "with") . 10)
180 (("=>" "d=" "=of") . (65 . 40))
182 (("case" "of" "fn") . 45)
183 (("if" "then" "else" "while" "do" "raise") . 50)
189 (,(cons "end" sml-begin-syms) . 10000)))
190 "Alist of pseudo-precedence of syntactic elements.")
192 (defun sml-op-prec (op dir)
193 "Return the precedence of OP or nil if it's not an infix.
194 DIR should be set to BACK if you want to precedence w.r.t the left side
195 and to FORW for the precedence w.r.t the right side.
196 This assumes that we are `looking-at' the OP."
198 (let ((sprec (cdr (assoc op sml-syntax-prec))))
200 ((consp sprec) (if (eq dir 'back) (car sprec) (cdr sprec)))
203 (let ((prec (cdr (assoc op sml-op-prec))))
204 (when prec (+ prec 100))))))))
208 (defun sml-forward-spaces () (forward-comment 100000))
209 (defun sml-backward-spaces () (forward-comment -100000))
213 ;; moving forward around matching symbols
216 (defun sml-looking-back-at (re)
218 (when (= 0 (skip-syntax-backward "w_")) (backward-char))
221 (defun sml-find-match-forward (this match)
222 "Only works for word matches."
224 (forward-sexp-function nil)
225 (either (concat this "\\|" match)))
226 (while (and (not (eobp)) (> level 0))
228 (while (not (or (eobp) (sml-looking-back-at either)))
229 (condition-case () (forward-sexp 1) (error (forward-char 1))))
232 ((sml-looking-back-at this) (1+ level))
233 ((sml-looking-back-at match) (1- level))
234 (t (error "Unbalanced")))))
237 (defun sml-find-match-backward (this match)
239 (forward-sexp-function nil)
240 (either (concat this "\\|" match)))
243 (while (not (or (bobp) (looking-at either)))
244 (condition-case () (backward-sexp 1) (error (backward-char 1))))
247 ((looking-at this) (1+ level))
248 ((looking-at match) (1- level))
249 (t (error "Unbalanced")))))
253 ;;; Read a symbol, including the special "op <sym>" case
256 (defmacro sml-move-read (&rest body)
257 (let ((pt-sym (make-symbol "point")))
258 `(let ((,pt-sym (point)))
260 (when (/= (point) ,pt-sym)
261 (buffer-substring-no-properties (point) ,pt-sym)))))
262 (def-edebug-spec sml-move-read t)
264 (defun sml-poly-equal-p ()
265 ;; Figure out which kind of "=" this is.
266 ;; The idea is to look backward for the first occurrence of a token that
267 ;; requires a definitional "=" and then see if there's such a definitional
268 ;; equal between that token and ourselves (in which case we're not
269 ;; a definitional = ourselves).
270 ;; The "search for =" is naive and will match "=>" and "<=", but it turns
271 ;; out to be OK in practice because such tokens very rarely (if ever) appear
272 ;; between the =-starter and the corresponding definitional equal.
273 ;; One known problem case is code like:
274 ;; "functor foo (structure s : S) where type t = s.t ="
275 ;; where the "type t = s.t" is mistaken for a type definition.
276 (< (sml-point-after (re-search-backward sml-=-starter-re nil 'move))
277 (sml-point-after (re-search-backward "=" nil 'move))))
279 (defun sml-nested-of-p ()
281 (re-search-backward sml-non-nested-of-starter-re nil 'move))
282 (sml-point-after (re-search-backward "\\<case\\>" nil 'move))))
284 (defun sml-forward-sym-1 ()
285 (or (/= 0 (skip-syntax-forward "'w_"))
286 (/= 0 (skip-syntax-forward ".'"))))
287 (defun sml-forward-sym ()
288 (let ((sym (sml-move-read (sml-forward-sym-1))))
292 (concat "op " (or (sml-move-read (sml-forward-sym-1)) "")))
296 (if (sml-poly-equal-p) "=" "d=")))
300 (if (sml-nested-of-p) "of" "=of")))
301 ;; ((equal sym "datatype")
303 ;; (sml-backward-sym-1)
304 ;; (sml-backward-spaces)
305 ;; (if (eq (preceding-char) ?=) "=datatype" sym)))
308 (defun sml-backward-sym-1 ()
309 (or (/= 0 (skip-syntax-backward ".'"))
310 (/= 0 (skip-syntax-backward "'w_"))))
311 (defun sml-backward-sym ()
312 (let ((sym (sml-move-read (sml-backward-sym-1))))
314 ;; FIXME: what should we do if `sym' = "op" ?
315 (let ((point (point)))
316 (sml-backward-spaces)
317 (if (equal "op" (sml-move-read (sml-backward-sym-1)))
321 ((string= sym "=") (if (sml-poly-equal-p) "=" "d="))
322 ((string= sym "of") (if (sml-nested-of-p) "of" "=of"))
323 ;; ((string= sym "datatype")
324 ;; (save-excursion (sml-backward-spaces)
325 ;; (if (eq (preceding-char) ?=) "=datatype" sym)))
329 (defun sml-backward-sexp (prec)
330 "Move one sexp backward if possible, or one char else.
331 Returns t if the move indeed moved through one sexp and nil if not.
332 PREC is the precedence currently looked for."
333 (let ((parse-sexp-lookup-properties t)
334 (parse-sexp-ignore-comments t))
335 (sml-backward-spaces)
336 (let* ((op (sml-backward-sym))
337 (op-prec (sml-op-prec op 'back))
341 (let ((point (point)))
342 (ignore-errors (let ((forward-sexp-function nil)) (backward-sexp 1)))
343 (if (/= point (point)) t (ignore-errors (backward-char 1)) nil)))
344 ;; stop as soon as precedence is smaller than `prec'
345 ((and prec op-prec (>= prec op-prec)) nil)
346 ;; special rules for nested constructs like if..then..else
347 ((and (or (not prec) (and prec op-prec))
348 (setq match (second (assoc op sml-close-paren))))
349 (sml-find-match-backward (concat "\\<" op "\\>") match))
350 ;; don't back over open-parens
351 ((assoc op sml-open-paren) nil)
352 ;; infix ops precedence
353 ((and prec op-prec) (< prec op-prec))
354 ;; [ prec = nil ] a new operator, let's skip the sexps until the next
355 (op-prec (while (sml-move-if (sml-backward-sexp op-prec))) t)
356 ;; special symbols indicating we're getting out of a nesting level
357 ((string-match sml-sexp-head-symbols-re op) nil)
358 ;; if the op was not alphanum, then we still have to do the backward-sexp
359 ;; this reproduces the usual backward-sexp, but it might be bogus
360 ;; in this case since !@$% is a perfectly fine symbol
361 (t t))))) ;(or (string-match "\\sw" op) (sml-backward-sexp prec))
363 (defun sml-forward-sexp (prec)
364 "Moves one sexp forward if possible, or one char else.
365 Returns T if the move indeed moved through one sexp and NIL if not."
366 (let ((parse-sexp-lookup-properties t)
367 (parse-sexp-ignore-comments t))
369 (let* ((op (sml-forward-sym))
370 (op-prec (sml-op-prec op 'forw))
374 (let ((point (point)))
375 (ignore-errors (let ((forward-sexp-function nil)) (forward-sexp 1)))
376 (if (/= point (point)) t (forward-char 1) nil)))
377 ;; stop as soon as precedence is smaller than `prec'
378 ((and prec op-prec (>= prec op-prec)) nil)
379 ;; special rules for nested constructs like if..then..else
380 ((and (or (not prec) (and prec op-prec))
381 (setq match (cdr (assoc op sml-open-paren))))
382 (sml-find-match-forward (first match) (second match)))
383 ;; don't forw over close-parens
384 ((assoc op sml-close-paren) nil)
385 ;; infix ops precedence
386 ((and prec op-prec) (< prec op-prec))
387 ;; [ prec = nil ] a new operator, let's skip the sexps until the next
388 (op-prec (while (sml-move-if (sml-forward-sexp op-prec))) t)
389 ;; special symbols indicating we're getting out of a nesting level
390 ((string-match sml-sexp-head-symbols-re op) nil)
391 ;; if the op was not alphanum, then we still have to do the backward-sexp
392 ;; this reproduces the usual backward-sexp, but it might be bogus
393 ;; in this case since !@$% is a perfectly fine symbol
394 (t t))))) ;(or (string-match "\\sw" op) (sml-backward-sexp prec))
396 (defun sml-in-word-p ()
397 (and (eq ?w (char-syntax (or (char-before) ? )))
398 (eq ?w (char-syntax (or (char-after) ? )))))
400 (defun sml-user-backward-sexp (&optional count)
401 "Like `backward-sexp' but tailored to the SML syntax."
403 (unless count (setq count 1))
405 (let ((point (point)))
406 (if (< count 0) (sml-user-forward-sexp (- count))
407 (when (sml-in-word-p) (forward-word 1))
409 (unless (sml-backward-sexp nil)
411 (error "Containing expression ends prematurely")))))))
413 (defun sml-user-forward-sexp (&optional count)
414 "Like `forward-sexp' but tailored to the SML syntax."
416 (unless count (setq count 1))
418 (let ((point (point)))
419 (if (< count 0) (sml-user-backward-sexp (- count))
420 (when (sml-in-word-p) (backward-word 1))
422 (unless (sml-forward-sexp nil)
424 (error "Containing expression ends prematurely")))))))
426 ;;(defun sml-forward-thing ()
427 ;; (if (= ?w (char-syntax (char-after))) (forward-word 1) (forward-char 1)))
429 (defun sml-backward-arg () (sml-backward-sexp 1000))
430 (defun sml-forward-arg () (sml-forward-sexp 1000))
434 (defvar sml-rightalign-and)
435 (defvar sml-indent-args)
436 (defvar sml-indent-level)
438 (defun sml-indent-line ()
439 "Indent current line of ML code."
441 (let ((savep (> (current-column) (current-indentation)))
442 (indent (max (or (ignore-errors (sml-calculate-indentation)) 0) 0)))
444 (save-excursion (indent-line-to indent))
445 (indent-line-to indent))))
447 (defun sml-find-comment-indent ()
451 (if (re-search-backward "(\\*\\|\\*)" nil t)
453 ;; FIXME: That's just a stop-gap.
454 ((eq (get-text-property (point) 'face) 'font-lock-string-face))
455 ((looking-at "*)") (incf depth))
456 ((looking-at comment-start-skip) (decf depth)))
459 (1+ (current-column))
462 (defun sml-calculate-indentation ()
464 (beginning-of-line) (skip-chars-forward "\t ")
466 ;; Indentation for comments alone on a line, matches the
467 ;; proper indentation of the next line.
468 (when (looking-at "(\\*") (sml-forward-spaces))
470 (sym (save-excursion (sml-forward-sym))))
472 ;; Allow the user to override the indentation.
473 (when (looking-at (concat ".*" (regexp-quote comment-start)
474 "[ \t]*fixindent[ \t]*"
475 (regexp-quote comment-end)))
476 (current-indentation))
478 ;; Continued comment.
479 (and (looking-at "\\*") (sml-find-comment-indent))
481 ;; Continued string ? (Added 890113 lbn)
482 (and (looking-at "\\\\")
483 (or (save-excursion (forward-line -1)
484 (if (looking-at "[\t ]*\\\\")
485 (current-indentation)))
487 (if (re-search-backward "[^\\\\]\"" nil t)
488 (1+ (current-column))
491 ;; Closing parens. Could be handled below with `sml-indent-relative'?
492 (and (looking-at "\\s)")
494 (skip-syntax-forward ")")
496 (if (sml-dangling-sym)
497 (sml-indent-default 'noindent)
500 (and (setq data (assoc sym sml-close-paren))
501 (sml-indent-relative sym data))
503 (and (member sym sml-starters-syms)
504 (sml-indent-starter sym))
506 (and (string= sym "|") (sml-indent-pipe))
509 (sml-indent-default))))))
511 (defsubst sml-bolp ()
512 (save-excursion (skip-chars-backward " \t|") (bolp)))
514 (defun sml-first-starter-p ()
515 "Non-nil if starter at point is immediately preceded by let/local/in/..."
517 (let ((sym (unless (save-excursion (sml-backward-arg))
518 (sml-backward-spaces)
519 (sml-backward-sym))))
520 (if (member sym '(";" "d=")) (setq sym nil))
523 (defun sml-indent-starter (orig-sym)
524 "Return the indentation to use for a symbol in `sml-starters-syms'.
525 Point should be just before the symbol ORIG-SYM and is not preserved."
526 (let ((sym (unless (save-excursion (sml-backward-arg))
527 (sml-backward-spaces)
528 (sml-backward-sym))))
529 (if (member sym '(";" "d=")) (setq sym nil))
530 (if sym (sml-get-sym-indent sym)
531 ;; FIXME: this can take a *long* time !!
532 (setq sym (sml-old-find-matching-starter sml-starters-syms))
533 (if (or (sml-first-starter-p)
534 ;; Don't align with `and' because it might be specially indented.
535 (and (or (equal orig-sym "and") (not (equal sym "and")))
538 (if (and sml-rightalign-and (equal orig-sym "and"))
539 (- (length sym) 3) 0))
540 (sml-indent-starter orig-sym)))))
542 (defun sml-indent-relative (sym data)
544 (sml-forward-sym) (sml-backward-sexp nil)
545 (unless (second data) (sml-backward-spaces) (sml-backward-sym))
546 (+ (or (cdr (assoc sym sml-symbol-indent)) 0)
547 (sml-delegated-indent))))
549 (defun sml-indent-pipe ()
550 (let ((sym (sml-old-find-matching-starter sml-pipeheads
551 (sml-op-prec "|" 'back))))
553 (if (string= sym "|")
554 (if (sml-bolp) (current-column) (sml-indent-pipe))
555 (let ((pipe-indent (or (cdr (assoc "|" sml-symbol-indent)) -2)))
556 (when (or (member sym '("datatype" "abstype"))
557 (and (equal sym "and")
560 (not (sml-funname-of-and)))))
561 (re-search-forward "="))
564 (+ pipe-indent (current-column)))))))
566 (defun sml-indent-arg ()
567 (and (save-excursion (ignore-errors (sml-forward-arg)))
568 ;;(not (looking-at sml-not-arg-re))
569 ;; looks like a function or an argument
570 (sml-move-if (sml-backward-arg))
572 (if (save-excursion (not (sml-backward-arg)))
574 (+ (current-column) sml-indent-args)
576 (while (and (/= (current-column) (current-indentation))
577 (sml-move-if (sml-backward-arg))))
578 (unless (save-excursion (sml-backward-arg))
579 ;; all earlier args are on the same line
580 (sml-forward-arg) (sml-forward-spaces))
583 (defun sml-get-indent (data sym)
586 ((not (listp data)) data)
587 ((setq d (member sym data)) (cadr d))
588 ((and (consp data) (not (stringp (car data)))) (car data))
589 (t sml-indent-level))))
591 (defun sml-dangling-sym ()
592 "Non-nil if the symbol after point is dangling.
593 The symbol can be an SML symbol or an open-paren. \"Dangling\" means that
594 it is not on its own line but is the last element on that line."
596 (and (not (sml-bolp))
597 (< (sml-point-after (end-of-line))
598 (sml-point-after (or (sml-forward-sym) (skip-syntax-forward "("))
599 (sml-forward-spaces))))))
601 (defun sml-delegated-indent ()
602 (if (sml-dangling-sym)
603 (sml-indent-default 'noindent)
604 (sml-move-if (backward-word 1)
605 (looking-at sml-agglomerate-re))
608 (defun sml-get-sym-indent (sym &optional style)
609 "Find the indentation for the SYM we're `looking-at'.
610 If indentation is delegated, point will move to the start of the parent.
611 Optional argument STYLE is currently ignored."
612 (assert (equal sym (save-excursion (sml-forward-sym))))
614 (let ((delegate (and (not (equal sym "end")) (assoc sym sml-close-paren)))
616 (when (and delegate (not (eval (third delegate))))
617 ;;(sml-find-match-backward sym delegate)
618 (sml-forward-sym) (sml-backward-sexp nil)
620 (if (second delegate)
621 (save-excursion (sml-forward-sym))
622 (sml-backward-spaces) (sml-backward-sym))))
624 (let ((idata (assoc head-sym sml-indent-rule)))
626 ;;(if (or style (not delegate))
627 ;; normal indentation
628 (let ((indent (sml-get-indent (cdr idata) sym)))
629 (when indent (+ (sml-delegated-indent) indent)))
630 ;; delgate indentation to the parent
631 ;;(sml-forward-sym) (sml-backward-sexp nil)
632 ;;(let* ((parent-sym (save-excursion (sml-forward-sym)))
633 ;; (parent-indent (cdr (assoc parent-sym sml-indent-starters))))
634 ;; check the special rules
635 ;;(+ (sml-delegated-indent)
636 ;; (or (sml-get-indent (cdr indent-data) 1 'strict)
637 ;; (sml-get-indent (cdr parent-indent) 1 'strict)
638 ;; (sml-get-indent (cdr indent-data) 0)
639 ;; (sml-get-indent (cdr parent-indent) 0))))))))
642 (defun sml-indent-default (&optional noindent)
643 (let* ((sym-after (save-excursion (sml-forward-sym)))
644 (_ (sml-backward-spaces))
645 (sym-before (sml-backward-sym))
646 (sym-indent (and sym-before (sml-get-sym-indent sym-before)))
647 (indent-after (or (cdr (assoc sym-after sml-symbol-indent)) 0)))
648 (when (equal sym-before "end")
649 ;; I don't understand what's really happening here, but when
650 ;; it's `end' clearly, we need to do something special.
652 (setq sym-before nil sym-indent nil))
655 ;; the previous sym is an indentation introducer: follow the rule
659 (+ sym-indent indent-after)))
660 ;; If we're just after a hanging open paren.
661 ((and (eq (char-syntax (preceding-char)) ?\()
662 (save-excursion (backward-char) (sml-dangling-sym)))
664 (sml-indent-default))
667 (let* ((prec-after (sml-op-prec sym-after 'back))
668 (prec (or (sml-op-prec sym-before 'back) prec-after 100)))
669 ;; go back until you hit a symbol that has a lower prec than the
670 ;; "current one", or until you backed over a sym that has the same prec
671 ;; but is at the beginning of a line.
672 (while (and (not (sml-bolp))
673 (while (sml-move-if (sml-backward-sexp (1- prec))))
675 (while (sml-move-if (sml-backward-sexp prec))))
677 ;; the `noindent' case does back over an introductory symbol
678 ;; such as `fun', ...
681 (sml-backward-spaces)
682 (member (sml-backward-sym) sml-starters-syms))
684 ;; Use `indent-after' for cases such as when , or ; should be
685 ;; outdented so that their following terms are aligned.
687 (if (equal sym-after ";")
689 (sml-backward-spaces)
690 (member (sml-backward-sym) sml-starters-syms)))
691 (and sym-after (not (looking-at sym-after))))
693 (current-column))))))))
696 ;; maybe `|' should be set to word-syntax in our temp syntax table ?
697 (defun sml-current-indentation ()
700 (skip-chars-forward " \t|")
704 (defun sml-old-find-matching-starter (syms &optional prec)
708 (progn (sml-backward-sexp prec)
709 (setq sym (save-excursion (sml-forward-sym)))
710 (not (or (member sym syms) (bobp)))))
711 (if (member sym syms) sym))))
713 (defun sml-old-skip-siblings ()
714 (while (and (not (bobp)) (sml-backward-arg))
715 (sml-old-find-matching-starter sml-starters-syms))
716 (when (looking-at "in\\>\\|local\\>")
717 ;; Skip over `local...in' and continue.
719 (sml-backward-sexp nil)
720 (sml-old-skip-siblings)))
722 (provide 'sml-oldindent)
724 ;;; sml-oldindent.el ends here