emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] externals/wisi 8bdcee1 11/35: publish ada-mode 5.1.6, wisi 1.0.6,


From: Stefan Monnier
Subject: [elpa] externals/wisi 8bdcee1 11/35: publish ada-mode 5.1.6, wisi 1.0.6, new package ada-ref-man
Date: Sat, 28 Nov 2020 14:47:51 -0500 (EST)

branch: externals/wisi
commit 8bdcee1fa6adaef1ccdc411b444b4236923bd94f
Author: Stephen Leake <stephen_leake@stephe-leake.org>
Commit: Stephen Leake <stephen_leake@stephe-leake.org>

    publish ada-mode 5.1.6, wisi 1.0.6, new package ada-ref-man
    
    * admin/archive-contents.el (archive--metadata): include 'dir' in files, 
for doc-only packages
      (archive--metadata): fix typo in error message
    
    * packages/ada-mode/ada-ref-man.el: New file.
    * packages/ada-mode/*: version 5.1.6
    
    * packages/ada-ref-man/: New directory.
    
    * packages/wisi/*: version 1.0.6
    * packages/wisi/README: New file.
---
 README          |  14 +++
 wisi-compile.el |   7 +-
 wisi-parse.el   | 126 +++++++++++++------
 wisi.el         | 383 +++++++++++++++++++++++++++++++++++++-------------------
 4 files changed, 362 insertions(+), 168 deletions(-)

diff --git a/README b/README
new file mode 100755
index 0000000..cbf97c9
--- /dev/null
+++ b/README
@@ -0,0 +1,14 @@
+Emacs wisi package 1.0.6
+
+The wisi package provides utilities for using generalized LALR parsers
+to do indentation and navigation. See ada-mode for an example of its
+use.
+
+It is provided as a Gnu ELPA package; to install the package, add to
+~./emacs:
+
+(package-initialize)
+
+then invoke M-x list-packages, install wisi.
+
+(end of file)
diff --git a/wisi-compile.el b/wisi-compile.el
index 39ed689..a17b7f6 100755
--- a/wisi-compile.el
+++ b/wisi-compile.el
@@ -49,8 +49,11 @@
 
 (eval-when-compile
   ;; can't just 'require'; `wisent-with-context' doesn't work.
-  ;; also can't load .elc; must load .el
-  (load (locate-library "semantic/wisent/comp.el")))
+  ;; also can't load .elc; must load .el or .el.gz
+  (let ((file (locate-library "semantic/wisent/comp.el")))
+    (if file
+       (load file)
+      (error "source library semantic/wisent/comp.el not installed; install 
emacs lisp sources"))))
 
 (eval-and-compile
   (require 'semantic/wisent/comp))
diff --git a/wisi-parse.el b/wisi-parse.el
index bd7ce7e..e3b3da6 100755
--- a/wisi-parse.el
+++ b/wisi-parse.el
@@ -29,6 +29,28 @@
 (require 'cl-lib)
 (require 'semantic/wisent)
 
+;; WORKAROUND: for some reason, this condition doesn't work in batch mode!
+;; (when (and (= emacs-major-version 24)
+;;        (= emacs-minor-version 2))
+  (require 'wisi-compat-24.2)
+;;)
+
+(defvar wisi-parse-max-parallel 15
+  "Maximum number of parallel parsers for acceptable performance.
+If a file needs more than this, it's probably an indication that
+the grammar is excessively redundant.")
+
+(defvar wisi-parse-max-parallel-current (cons 0 0)
+  "Cons (count . point); Maximum number of parallel parsers used in most 
recent parse,
+point at which that max was spawned.")
+
+(defvar wisi-debug 0
+  "wisi debug mode:
+0 : normal - ignore parse errors, for indenting new code
+1 : report parse errors (for running tests)
+2 : show parse states, position point at parse errors, debug-on-error works in 
parser
+3 : also show top 10 items of parser stack.")
+
 (cl-defstruct (wisi-parser-state
            (:copier nil))
   label ;; integer identifying parser for debug
@@ -70,31 +92,19 @@
      'error-message
      "wisi parse error")
 
-(defvar wisi-parse-max-parallel 15
-  "Maximum number of parallel parsers for acceptable performance.
-If a file needs more than this, it's probably an indication that
-the grammar is excessively redundant.")
-
-(defvar wisi-parse-max-parallel-current (cons 0 0)
-  "Cons (count . point); Maximum number of parallel parsers used in most 
recent parse,
-point at which that max was spawned.")
-
-(defvar wisi-debug 0
-  "wisi debug mode:
-0 : normal - ignore parse errors, for indenting new code
-1 : report parse errors (for running tests)
-2 : show parse states, position point at parse errors, debug-on-error works in 
parser
-3 : also show top 10 items of parser stack.")
+(defvar-local wisi-cache-max 0
+  "Maximimum position in buffer where wisi-cache text properties are valid.")
 
 (defun wisi-parse (automaton lexer)
-  "Parse input using the automaton specified in AUTOMATON.
+  "Parse current buffer from bob using the automaton specified in AUTOMATON.
 
 - AUTOMATON is the parse table generated by `wisi-compile-grammar'.
 
 - LEXER is a function with no argument called by the parser to
-  obtain the next token in input, as a list (symbol text start
-  . end), where `symbol' is the terminal symbol, `text' is the
-  token string, `start . end' is the range in the buffer."
+  obtain the next token from the current buffer after point, as a
+  list (symbol text start . end), where `symbol' is the terminal
+  symbol, `text' is the token string, `start . end' is the range
+  in the buffer."
   (let* ((actions (aref automaton 0))
         (gotos   (aref automaton 1))
         (parser-states ;; vector of parallel parser states
@@ -108,12 +118,15 @@ point at which that max was spawned.")
         (active-parser-count 1)
         active-parser-count-prev
         (active 'shift)
-        (token (funcall lexer))
-        some-pending)
+        (token nil)
+        some-pending
+        )
 
-    (setq wisi-parse-max-parallel-current (cons 0 0))
+    (goto-char (point-min))
+    (aset (wisi-parser-state-stack (aref parser-states 0)) 0 0)
 
-    (aset (wisi-parser-state-stack (aref parser-states 0)) 0 0) ;; Initial 
state
+    (setq token (funcall lexer))
+    (setq wisi-parse-max-parallel-current (cons 0 0))
 
     (while (not (eq active 'accept))
       (setq active-parser-count-prev active-parser-count)
@@ -126,8 +139,12 @@ point at which that max was spawned.")
              ;; spawn a new parser
              (when (= active-parser-count wisi-parse-max-parallel)
                (signal 'wisi-parse-error
-                       (wisi-error-msg (concat "too many parallel parsers 
required;"
-                                               " simplify grammar, or increase 
`wisi-parse-max-parallel'"))))
+                       (let ((state (aref (wisi-parser-state-stack 
parser-state)
+                                          (wisi-parser-state-sp 
parser-state))))
+                         (wisi-error-msg (concat "too many parallel parsers 
required in grammar state %d;"
+                                                 " simplify grammar, or 
increase `wisi-parse-max-parallel'"
+                                                 state)))))
+
              (let ((j (wisi-free-parser parser-states)))
                (cond
                 ((= j -1)
@@ -223,11 +240,23 @@ point at which that max was spawned.")
       (when (eq active 'shift)
        (when (> active-parser-count 1)
          (setq active-parser-count (wisi-parse-elim-identical parser-states 
active-parser-count)))
+
        (setq token (funcall lexer)))
     )
     (when (> active-parser-count 1)
       (error "ambiguous parse result"))))
 
+(defun wisi-parsers-active-index (parser-states)
+  ;; only called when active-parser-count = 1
+  (let ((result nil)
+       (i 0))
+    (while (and (not result)
+               (< i (length parser-states)))
+      (when (wisi-parser-state-active (aref parser-states i))
+       (setq result i))
+      (setq i (1+ i)))
+    result))
+
 (defun wisi-parsers-active (parser-states active-count)
   "Return the type of parser cycle to execute.
 PARSER-STATES[*].active is the last action a parser took. If it
@@ -235,6 +264,8 @@ was 'shift, that parser used the input token, and should 
not be
 executed again until another input token is available, after all
 parsers have shifted the current token or terminated.
 
+Returns one of:
+
 'accept : all PARSER-STATES have active set to nil or 'accept -
 done parsing
 
@@ -264,7 +295,9 @@ token, execute 'reduce parsers."
       'accept)
      ((= (+ shift-count accept-count) active-count)
       'shift)
-     (t (error "unexpected result in wisi-parsers-active"))
+     (t
+      ;; all parsers in error state; should not get here
+      (error "all parsers in error state; programmer error"))
      )))
 
 (defun wisi-free-parser (parser-states)
@@ -332,19 +365,37 @@ nil, 'shift, or 'accept."
        )))
   active-parser-count)
 
+(defun wisi-parse-max-pos (tokens)
+  "Return max position in tokens, or point if tokens nil."
+  (let ((result (if tokens 0 (point))))
+    (mapc
+     (lambda (token)
+       (when (cl-cdddr token)
+        (setq result (max (cl-cdddr token) result))))
+     tokens)
+    result)
+  )
+
+(defun wisi-parse-exec-action (func tokens)
+  "Execute action if all tokens past wisi-cache-max."
+  ;; We don't execute actions if all tokens are before wisi-cache-max,
+  ;; because later actions can update existing caches, and if the
+  ;; parse fails that won't happen. It also saves time.
+  (if (>= (wisi-parse-max-pos tokens) wisi-cache-max)
+
+      (funcall func tokens)
+
+    (when (> wisi-debug 1)
+      (message "... action skipped"))
+    ))
+
 (defun wisi-execute-pending (pending)
   (while pending
     (when (> wisi-debug 1) (message "%s" (car pending)))
 
-    (cond
-     ((and (>= emacs-major-version 24)
-          (>= emacs-minor-version 3))
-      (apply (pop pending)))
-
-     (t
-      (let ((func-args (pop pending)))
-       (apply (car func-args) (cdr func-args))))
-     )))
+    (let ((func-args (pop pending)))
+      (wisi-parse-exec-action (car func-args) (cadr func-args)))
+    ))
 
 (defun wisi-parse-1 (token parser-state pendingp actions gotos)
   "Perform one shift or reduce on PARSER-STATE.
@@ -468,7 +519,10 @@ the first and last tokens of the nonterminal."
                          (list (list (nth 1 action) tokens))))
          (setf (wisi-parser-state-pending parser-state)
                (list (list (nth 1 action) tokens))))
-      (funcall (nth 1 action) tokens))
+
+      ;; Not pending.
+      (wisi-parse-exec-action (nth 1 action) tokens)
+      )
     ))
 
 (provide 'wisi-parse)
diff --git a/wisi.el b/wisi.el
index d4cd8e6..509e6ba 100755
--- a/wisi.el
+++ b/wisi.el
@@ -3,7 +3,11 @@
 ;; Copyright (C) 2012 - 2014  Free Software Foundation, Inc.
 ;;
 ;; Author: Stephen Leake <stephen_leake@member.fsf.org>
-;; Version: 1.0.5
+;; Maintainer: Stephen Leake <stephen_leake@member.fsf.org>
+;; Keywords: parser
+;;  indentation
+;;  navigation
+;; Version: 1.0.6
 ;; package-requires: ((cl-lib "0.4") (emacs "24.2"))
 ;; URL: http://stephe-leake.org/emacs/ada-mode/emacs-ada-mode.html
 ;;
@@ -25,7 +29,7 @@
 
 ;;; Commentary:
 
-;;;; History: first experimental version Oct 2012
+;;;; History: see NEWS-wisi.text
 ;;
 ;;;; indentation algorithm overview
 ;;
@@ -131,6 +135,15 @@
 ;; that in functions that return tokens in the form wisi-parse
 ;; expects.
 ;;
+;;;; lexer
+;;
+;; The lexer is `wisi-forward-token'. It relies on syntax properties,
+;; so syntax-propertize must be called on the text to be lexed before
+;; wisi-forward-token is called. In general, it is hard to determine
+;; an appropriate end-point for syntax-propertize, other than
+;; point-max. So we call (syntax-propertize point-max) in wisi-setup,
+;; and also call syntax-propertize in wisi-after-change.
+;;
 ;;;; code style
 ;;
 ;; 'wisi' was originally short for "wisent indentation engine", but
@@ -218,19 +231,28 @@ If at end of buffer, returns `wisent-eoi-term'."
       (setq token-id (symbol-value (intern-soft token-text 
wisi-keyword-table))))
 
      ((eq syntax 7)
-      ;; string quote, either single or double. we assume point is before the 
start quote, not the end quote
+      ;; string quote, either single or double. we assume point is
+      ;; before the start quote, not the end quote
       (let ((delim (char-after (point)))
            (forward-sexp-function nil))
-       (forward-sexp)
-       ;; point is now after the end quote; check for an escaped quote
-       (while (or
-               (and wisi-string-quote-escape-doubled
-                    (eq (char-after (point)) delim))
-               (and (eq delim (car wisi-string-quote-escape))
-                    (eq (char-before (1- (point))) (cdr 
wisi-string-quote-escape))))
-         (forward-sexp))
-       (setq token-text (buffer-substring-no-properties start (point)))
-       (setq token-id (if (= delim ?\") wisi-string-double-term 
wisi-string-single-term))))
+       (condition-case err
+           (progn
+             (forward-sexp)
+
+             ;; point is now after the end quote; check for an escaped quote
+             (while (or
+                     (and wisi-string-quote-escape-doubled
+                          (eq (char-after (point)) delim))
+                     (and (eq delim (car wisi-string-quote-escape))
+                          (eq (char-before (1- (point))) (cdr 
wisi-string-quote-escape))))
+               (forward-sexp))
+             (setq token-text (buffer-substring-no-properties start (point)))
+             (setq token-id (if (= delim ?\") wisi-string-double-term 
wisi-string-single-term)))
+         (scan-error
+          ;; Something screwed up; we should not get here if
+          ;; syntax-propertize works properly.
+          (error "wisi-forward-token: forward-sexp failed %s" err)
+          ))))
 
      (t ;; assuming word syntax
       (skip-syntax-forward "w_'")
@@ -241,7 +263,8 @@ If at end of buffer, returns `wisent-eoi-term'."
      );; cond
 
     (unless token-id
-      (error (wisi-error-msg "unrecognized token '%s'" 
(buffer-substring-no-properties start (point)))))
+      (signal 'wisi-parse-error
+             (wisi-error-msg "unrecognized token '%s'" 
(buffer-substring-no-properties start (point)))))
 
     (if text-only
        token-text
@@ -317,12 +340,10 @@ wisi-forward-token, but does not look up symbol."
 
   prev ;; marker at previous motion token in statement; nil if none
   next ;; marker at next motion token in statement; nil if none
-  end ;; marker at token at end of current statement
+  end  ;; marker at token at end of current statement
+  face ;; for font-lock. only set when regexp font-lock can't handle it
   )
 
-(defvar-local wisi-cache-max 0
-  "Maximimum position in buffer where wisi token cache is valid.")
-
 (defvar-local wisi-parse-table nil)
 
 (defvar-local wisi-parse-failed nil
@@ -331,21 +352,29 @@ wisi-forward-token, but does not look up symbol."
 (defvar-local wisi-parse-try nil
   "Non-nil when parse is needed - cleared when parse succeeds.")
 
-(defvar-local wisi-change-need-invalidate nil)
+(defvar-local wisi-change-need-invalidate nil
+  "When non-nil, buffer position to invalidate from.
+Used in before/after change functions.")
 
-(defvar wisi-end-caches nil
+(defvar-local wisi-end-caches nil
   "List of buffer positions of caches in current statement that need 
wisi-cache-end set.")
 
-(defun wisi-invalidate-cache()
-  "Invalidate the wisi token cache for the current buffer.
-Also invalidate the Emacs syntax cache."
+(defun wisi-invalidate-cache(&optional after)
+  "Invalidate parsing caches for the current buffer from AFTER to end of 
buffer.
+Caches are the Emacs syntax cache, the wisi token cache, and the wisi parser 
cache."
   (interactive)
-  (setq wisi-cache-max 0)
+  (if (not after)
+      (setq after (point-min))
+    (setq after
+       (save-excursion
+         (goto-char after)
+         (line-beginning-position))))
+  (when (> wisi-debug 0) (message "wisi-invalidate %s:%d" (current-buffer) 
after))
+  (setq wisi-cache-max after)
   (setq wisi-parse-try t)
-  (setq wisi-end-caches nil)
-  (syntax-ppss-flush-cache (point-min))
+  (syntax-ppss-flush-cache after)
   (with-silent-modifications
-    (remove-text-properties (point-min) (point-max) '(wisi-cache))))
+    (remove-text-properties after (point-max) '(wisi-cache nil))))
 
 (defun wisi-before-change (begin end)
   "For `before-change-functions'."
@@ -363,49 +392,64 @@ Also invalidate the Emacs syntax cache."
       (add-hook 'after-change-functions 'wisi-after-change nil t))
     )
 
-  (save-excursion
-    ;; don't invalidate parse for whitespace, string, or comment changes
-    (let (;; (info "(elisp)Parser State")
-         (state (syntax-ppss begin)))
-      ;; syntax-ppss has moved point to "begin".
-      (cond
-       ((or
-        (nth 3 state); in string
-        (nth 4 state)); in comment
-       ;; FIXME: check that entire range is in comment or string
-       (setq wisi-change-need-invalidate nil))
-
-       ((progn
-         (skip-syntax-forward " " end);; does not skip newline
-         (eq (point) end))
-       (setq wisi-change-need-invalidate nil))
-
-       (t (setq wisi-change-need-invalidate t))
-       ))))
+  (setq wisi-change-need-invalidate nil)
+
+  (when (and (> end begin)
+            (>= wisi-cache-max begin))
+
+    (when wisi-parse-failed
+      ;; The parse was failing, probably due to bad syntax; this change
+      ;; may have fixed it, so try reparse.
+      (setq wisi-parse-try t))
+
+    (save-excursion
+      ;; don't invalidate parse for whitespace, string, or comment changes
+      (let (;; (info "(elisp)Parser State")
+           (state (syntax-ppss begin)))
+       ;; syntax-ppss has moved point to "begin".
+       (cond
+        ((or
+          (nth 3 state); in string
+          (nth 4 state)); in comment
+         ;; FIXME: check that entire range is in comment or string
+         )
+
+        ((progn
+           (skip-syntax-forward " " end);; does not skip newline
+           (eq (point) end)))
+
+        (t
+         (setq wisi-change-need-invalidate
+               (progn
+                 (wisi-goto-statement-start)
+                 (point))))
+        ))))
+  )
 
 (defun wisi-after-change (begin end length)
   "For `after-change-functions'."
-  ;; begin . end is range of text being inserted (may be empty)
+  ;; begin . end is range of text being inserted (empty if equal)
 
   ;; (syntax-ppss-flush-cache begin) is in before-change-functions
 
-  (cond
-   (wisi-parse-failed
-    ;; The parse was failing, probably due to bad syntax; this change
-    ;; may have fixed it, so try reparse.
-    (setq wisi-parse-try t)
+  (syntax-propertize end) ;; see comments above on "lexer" re syntax-propertize
 
-    ;; remove 'wisi-cache on inserted text, which could have caches
-    ;; from before the failed parse, and are in any case invalid.
-    (with-silent-modifications
-      (remove-text-properties begin end '(wisi-cache)))
-    )
+  ;; The parse was failing, probably due to bad syntax; this change
+  ;; may have fixed it, so try reparse.
+  (setq wisi-parse-try t)
 
+  ;; remove 'wisi-cache on inserted text, which could have caches
+  ;; from before the failed parse (or another buffer), and are in
+  ;; any case invalid.
+  (with-silent-modifications
+    (remove-text-properties begin end '(wisi-cache)))
+
+  (cond
    ((>= wisi-cache-max begin)
     ;; The parse had succeeded past the start of the inserted
     ;; text.
     (save-excursion
-      (let ((need-invalidate t)
+      (let (need-invalidate
            ;; (info "(elisp)Parser State")
            (state (syntax-ppss begin)))
        ;; syntax-ppss has moved point to "begin".
@@ -413,7 +457,10 @@ Also invalidate the Emacs syntax cache."
         (wisi-change-need-invalidate
          ;; wisi-before change determined the removed text alters the
          ;; parse
-         nil)
+         (setq need-invalidate wisi-change-need-invalidate))
+
+        ((= end begin)
+         (setq need-invalidate nil))
 
         ((or
           (nth 3 state); in string
@@ -430,17 +477,16 @@ Also invalidate the Emacs syntax cache."
            (eq (point) end))
          (setq need-invalidate nil))
 
-        (t nil)
+        (t
+         (setq need-invalidate begin))
         )
 
        (if need-invalidate
            ;; The inserted or deleted text could alter the parse;
            ;; wisi-invalidate-cache removes all 'wisi-cache.
-           (wisi-invalidate-cache)
+           (wisi-invalidate-cache need-invalidate)
 
-         ;; else move cache-max by the net change length. We don't
-         ;; need to delete 'wisi-cache in the inserted text, because
-         ;; if there were any it would not pass the above.
+         ;; else move cache-max by the net change length.
          (setq wisi-cache-max
                (+ wisi-cache-max (- end begin length))))
        )
@@ -448,7 +494,7 @@ Also invalidate the Emacs syntax cache."
 
    (t
     ;; parse never attempted, or only done to before BEGIN. Just
-    ;; remove 'wisi-cache
+    ;; remove caches
     (with-silent-modifications
       (remove-text-properties begin end '(wisi-cache)))
     )
@@ -473,15 +519,24 @@ If accessing cache at a marker for a token as set by 
`wisi-cache-tokens', POS mu
 (defun wisi-show-parse-error ()
   "Show last wisi-parse error."
   (interactive)
-  (if wisi-parse-failed
-      (progn
-       (message wisi-parse-error-msg)
-       (wisi-goto-error))
-    (message "parse succeeded")))
+  (cond
+   (wisi-parse-failed
+    (message wisi-parse-error-msg)
+    (wisi-goto-error))
+
+   (wisi-parse-try
+    (message "need parse"))
+
+   (t
+    (message "parse succeeded"))
+   ))
+
+(defvar wisi-post-parse-succeed-hook nil
+  "Hook run after parse succeeds.")
 
 (defun wisi-validate-cache (pos)
   "Ensure cached data is valid at least up to POS in current buffer."
-  (let ((msg (format "wisi: parsing %s:%d ..." (buffer-name) 
(line-number-at-pos))))
+  (let ((msg (when (> wisi-debug 0) (format "wisi: parsing %s:%d ..." 
(buffer-name) (line-number-at-pos pos)))))
     (when (and wisi-parse-try
               (< wisi-cache-max pos))
       (when (> wisi-debug 0)
@@ -489,20 +544,26 @@ If accessing cache at a marker for a token as set by 
`wisi-cache-tokens', POS mu
 
       (setq wisi-parse-try nil)
       (setq wisi-parse-error-msg nil)
+      (setq wisi-end-caches nil)
+
       (save-excursion
-       (goto-char wisi-cache-max)
        (if (> wisi-debug 1)
            ;; let debugger stop in wisi-parse
            (progn
              (wisi-parse wisi-parse-table 'wisi-forward-token)
              (setq wisi-cache-max (point))
-             (setq wisi-parse-failed nil))
-         ;; else capture errors from bad syntax, so higher level functions can 
try to continue
+             (setq wisi-parse-failed nil)
+             (run-hooks 'wisi-post-parse-succeed-hook))
+
+         ;; else capture errors from bad syntax, so higher level
+         ;; functions can try to continue and/or we don't bother the
+         ;; user.
          (condition-case err
              (progn
                (wisi-parse wisi-parse-table 'wisi-forward-token)
                (setq wisi-cache-max (point))
-               (setq wisi-parse-failed nil))
+               (setq wisi-parse-failed nil)
+               (run-hooks 'wisi-post-parse-succeed-hook))
            (wisi-parse-error
             (setq wisi-parse-failed t)
             (setq wisi-parse-error-msg (cdr err)))
@@ -524,6 +585,11 @@ If accessing cache at a marker for a token as set by 
`wisi-cache-tokens', POS mu
     (and containing
         (wisi-get-cache (1- containing)))))
 
+(defun wisi-cache-region (cache)
+  "Return region designated by cache.
+Point must be at cache."
+  (cons (point) (+ (point) (wisi-cache-last cache))))
+
 (defun wisi-cache-text (cache)
   "Return property-less buffer substring designated by cache.
 Point must be at cache."
@@ -592,7 +658,8 @@ that token. Use in a grammar action as:
                    ;;
                    ;; statement : label_opt simple_statement
                    ;;
-                   ;; override nonterm, class and containing
+                   ;; override nonterm, class, containing
+                   ;; set end only if not set yet (due to failed parse)
                    (progn
                      (cl-case (wisi-cache-class cache)
                        (block-start
@@ -611,7 +678,13 @@ that token. Use in a grammar action as:
                         (setf (wisi-cache-class cache) (or override-start 
class)))
                        )
                      (setf (wisi-cache-nonterm cache) $nterm)
-                     (setf (wisi-cache-containing cache) first-keyword-mark))
+                     (setf (wisi-cache-containing cache) first-keyword-mark)
+                     (unless (wisi-cache-end cache)
+                       (if wisi-end-caches
+                           (push (car region) wisi-end-caches)
+                         (setq wisi-end-caches (list (car region)))
+                         ))
+                     )
 
                  ;; else create new cache
                  (with-silent-modifications
@@ -706,9 +779,9 @@ Each TOKEN-NUMBERS is one of:
 
 number: the token number; mark that token
 
-list (number token_id):
-list (number (token_id token_id)):
-   mark all tokens with token_id in the nonterminal given by the number."
+list (number class token_id):
+list (number class token_id class token_id ...):
+   mark all tokens in number nonterminal matching (class token_id) with nil 
prev/next."
   (save-excursion
     (let (prev-keyword-mark
          prev-cache
@@ -716,11 +789,10 @@ list (number (token_id token_id)):
          mark)
       (while token-numbers
        (let ((token-number (pop token-numbers))
-             target-token
+             class-tokens target-class target-token
              region)
          (cond
           ((numberp token-number)
-           (setq target-token nil)
            (setq region (cddr (nth (1- token-number) wisi-tokens)))
            (when region
              (setq cache (wisi-get-cache (car region)))
@@ -737,29 +809,30 @@ list (number (token_id token_id)):
              ))
 
           ((listp token-number)
-           ;; token-number may contain 0, 1, or more token_id; token_id may be 
a list
+           ;; token-number may contain 0, 1, or more 'class token_id' pairs
            ;; the corresponding region may be empty
            ;; there must have been a prev keyword
-           (setq target-token (cadr token-number))
-           (when (not (listp target-token))
-             (setq target-token (list target-token)))
+           (setq class-tokens (cdr token-number))
            (setq token-number (car token-number))
            (setq region (cddr (nth (1- token-number) wisi-tokens)))
            (when region ;; not an empty token
-             (goto-char (car region))
-             (while (wisi-forward-find-token target-token (cdr region) t)
-               (setq cache (wisi-get-cache (point)))
-               (setq mark (copy-marker (1+ (point))))
-
-               (when (null (wisi-cache-prev cache))
-                 (setf (wisi-cache-prev cache) prev-keyword-mark)
-                 (setf (wisi-cache-next prev-cache) mark)
-                 (setq prev-keyword-mark mark)
-                 (setq prev-cache cache))
-
-               (wisi-forward-token);; don't find same token again
+             (while class-tokens
+               (setq target-class (pop class-tokens))
+               (setq target-token (list (pop class-tokens)))
+               (goto-char (car region))
+               (while (setq cache (wisi-forward-find-token target-token (cdr 
region) t))
+                 (when (eq target-class (wisi-cache-class cache))
+                   (when (null (wisi-cache-prev cache))
+                     (setf (wisi-cache-prev cache) prev-keyword-mark))
+                   (when (null (wisi-cache-next cache))
+                     (setq mark (copy-marker (1+ (point))))
+                     (setf (wisi-cache-next prev-cache) mark)
+                     (setq prev-keyword-mark mark)
+                     (setq prev-cache cache)))
+
+                 (wisi-forward-token);; don't find same token again
                ))
-             )
+             ))
 
           (t
            (error "unexpected token-number %s" token-number))
@@ -768,6 +841,41 @@ list (number (token_id token_id)):
          ))
       )))
 
+(defun wisi-extend-action (number)
+  "Extend text of cache at token NUMBER to cover all of token NUMBER.
+Also override token with new token."
+  (let* ((token-region (nth (1- number) wisi-tokens));; wisi-tokens is 
let-bound in wisi-parse-reduce
+        (token (car token-region))
+        (region (cddr token-region))
+       cache)
+
+    (when region
+      (setq cache (wisi-get-cache (car region)))
+      (setf (wisi-cache-last cache) (- (cdr region) (car region)))
+      (setf (wisi-cache-token cache) token)
+      )
+    ))
+
+(defun wisi-face-action (&rest pairs)
+  "Cache face information in text properties of tokens.
+Intended as a grammar non-terminal action.
+
+PAIRS is of the form [TOKEN-NUMBER fase] ..."
+  (while pairs
+    (let* ((number (1- (pop pairs)))
+          (region (cddr (nth number wisi-tokens)));; wisi-tokens is let-bound 
in wisi-parse-reduce
+          (face (pop pairs))
+          cache)
+
+      (when region
+       (setq cache (wisi-get-cache (car region)))
+       (unless cache
+         (error "wisi-face-action on non-cache"))
+       (setf (wisi-cache-face cache) face)
+       (when (boundp 'jit-lock-mode)
+         (jit-lock-refontify (car region) (cdr region))))
+      )))
+
 ;;;; motion
 (defun wisi-backward-cache ()
   "Move point backward to the beginning of the first token preceding point 
that has a cache.
@@ -882,7 +990,7 @@ If LIMIT (a buffer position) is reached, throw an error."
   "If not at a cached token, move forward to next
 cache. Otherwise move to cache-next, or next cache if nil.
 Return cache found."
-  (wisi-validate-cache (point-max))
+  (wisi-validate-cache (point-max)) ;; ensure there is a next cache to move to
   (let ((cache (wisi-get-cache (point))))
     (if cache
        (let ((next (wisi-cache-next cache)))
@@ -898,7 +1006,7 @@ Return cache found."
 (defun wisi-backward-statement-keyword ()
   "If not at a cached token, move backward to prev
 cache. Otherwise move to cache-prev, or prev cache if nil."
-  (wisi-validate-cache (point-max))
+  (wisi-validate-cache (point))
   (let ((cache (wisi-get-cache (point))))
     (if cache
        (let ((prev (wisi-cache-prev cache)))
@@ -909,7 +1017,8 @@ cache. Otherwise move to cache-prev, or prev cache if nil."
   ))
 
 (defun wisi-goto-containing (cache &optional error)
-  "Move point to containing token for CACHE, return cache at that point."
+  "Move point to containing token for CACHE, return cache at that point.
+If ERROR, throw error when CACHE has no container; else return nil."
   (cond
    ((markerp (wisi-cache-containing cache))
     (goto-char (1- (wisi-cache-containing cache)))
@@ -943,10 +1052,20 @@ Return start cache."
 (defun wisi-goto-end-1 (cache)
   (goto-char (1- (wisi-cache-end cache))))
 
-(defun wisi-goto-end ()
+(defun wisi-goto-statement-start ()
+  "Move point to token at start of statement point is in or after.
+Return start cache."
+  (interactive)
+  (wisi-validate-cache (point))
+  (let ((cache (wisi-get-cache (point))))
+    (unless cache
+      (setq cache (wisi-backward-cache)))
+    (wisi-goto-start cache)))
+
+(defun wisi-goto-statement-end ()
   "Move point to token at end of statement point is in or before."
   (interactive)
-  (wisi-validate-cache (point-max))
+  (wisi-validate-cache (point))
   (let ((cache (or (wisi-get-cache (point))
                   (wisi-forward-cache))))
     (when (wisi-cache-end cache)
@@ -1001,9 +1120,7 @@ of CACHE with class statement-start or block-start."
 
 (defun wisi-indent-statement ()
   "Indent region given by `wisi-goto-start' on cache at or before point, then 
wisi-cache-end."
-  ;; force reparse, in case parser got confused
-  (let ((wisi-parse-try t))
-    (wisi-validate-cache (point)))
+  (wisi-validate-cache (point))
 
   (save-excursion
     (let ((cache (or (wisi-get-cache (point))
@@ -1040,27 +1157,34 @@ correct. Must leave point at indentation of current 
line.")
   "Indent current line using the wisi indentation engine."
   (interactive)
 
-  (let* ((savep (point))
-        (indent
-         (or (save-excursion
-               (wisi-validate-cache (point))
-               (back-to-indentation)
-               (when (>= (point) savep) (setq savep nil))
-               (if wisi-parse-failed
-                   (progn
-                     ;; parse failed. Assume user is editing; indent to 
previous line, fix it after parse succeeds
-                     (setq wisi-indent-failed t)
-                     (forward-line -1);; safe at bob
-                     (back-to-indentation)
-                     (current-column))
-
-                 ;; else parse succeeded
-                 (when wisi-indent-failed
-                   (setq wisi-indent-failed nil)
-                   (run-hooks 'wisi-post-parse-fail-hook))
-                 (with-demoted-errors
-                   (or (run-hook-with-args-until-success 
'wisi-indent-calculate-functions) 0))
-                 )))))
+  (let ((savep (point))
+       indent)
+    (save-excursion
+      (back-to-indentation)
+      (when (>= (point) savep) (setq savep nil))
+
+      (when (> (point) wisi-cache-max)
+       (wisi-validate-cache (point))
+       (when (and (not wisi-parse-failed)
+                  wisi-indent-failed)
+         (setq wisi-indent-failed nil)
+         (run-hooks 'wisi-post-parse-fail-hook)))
+
+      (if (> (point) wisi-cache-max)
+         (progn
+           ;; no indent info at point. Assume user is
+           ;; editing; indent to previous line, fix it
+           ;; after parse succeeds
+           (setq wisi-indent-failed t)
+           (forward-line -1);; safe at bob
+           (back-to-indentation)
+           (setq indent (current-column)))
+
+       (setq indent
+             (with-demoted-errors
+               (or (run-hook-with-args-until-success 
'wisi-indent-calculate-functions) 0))
+             )))
+
     (if savep
        ;; point was inside line text; leave it there
        (save-excursion (indent-line-to indent))
@@ -1135,8 +1259,7 @@ correct. Must leave point at indentation of current 
line.")
   (add-hook 'before-change-functions 'wisi-before-change nil t)
   (add-hook 'after-change-functions 'wisi-after-change nil t)
 
-  ;; WORKAROUND: sometimes the first time font-lock is run,
-  ;; syntax-propertize is not run properly, so we run it here
+  ;; see comments on "lexer" above re syntax-propertize
   (syntax-propertize (point-max))
 
   (wisi-invalidate-cache)



reply via email to

[Prev in Thread] Current Thread [Next in Thread]