branch: externals/sql-indent
commit 1b48bcfa022e8a102a17b416aa858025e9624559
Author: Alex Harsanyi <[email protected]>
Commit: Alex Harsanyi <[email protected]>

    Correctly detect syntax for cursor statements (fix #19)
    
    Cursors are correctly detected as beginning of a statement.  Also an 
optional
    type for the cursor is recognized correctly.
    
    Also fixed block navigation for package names (so package end statements are
    correctly recognized)
    
    Added tests for the above cases.
---
 README.md              |  11 ++--
 sql-indent-test.el     |   4 ++
 sql-indent.el          |  40 ++++++++++----
 test-data/pr19-syn.eld | 138 +++++++++++++++++++++++++++++++++++++++++++++++++
 test-data/pr19.sql     |  64 +++++++++++++++++++++++
 5 files changed, 241 insertions(+), 16 deletions(-)

diff --git a/README.md b/README.md
index 6a3af6b..88c8b1a 100644
--- a/README.md
+++ b/README.md
@@ -288,11 +288,12 @@ defined for SQL code:
 
 * `(in-begin-block KIND LABEL)` -- line is inside a block started by a begin
   statement.  KIND (a symbol) is "toplevel-block" for a begin at toplevel,
-  "defun" for a begin that starts the body of a procedure or function, nil for
-  a begin that is none of the previous.  For a "defun", LABEL is the name of
-  the procedure or function, for the other block types LABEL contains the
-  block label, or the empty string if the block has no label.  ANCHOR is the
-  start of the block.
+  "defun" for a begin that starts the body of a procedure or function,
+  \"package\" for a begin that starts the body of a package, nil for a begin
+  that is none of the previous.  For a "defun" or "package", LABEL is the name
+  of the procedure, function or package, for the other block types LABEL
+  contains the block label, or the empty string if the block has no label.
+  ANCHOR is the start of the block.
 
 * `(block-start KIND)` -- line begins with a statement that starts a block.
   KIND (a symbol) can be one of "then", "else" or "loop".  ANCHOR is the
diff --git a/sql-indent-test.el b/sql-indent-test.el
index bec6abe..8f0028a 100644
--- a/sql-indent-test.el
+++ b/sql-indent-test.el
@@ -254,3 +254,7 @@ information read from DATA-FILE (as generated by
 
 (ert-deftest sqlind-ert-pr18 ()
   (sqlind-ert-check-file-syntax "test-data/pr18.sql" "test-data/pr18-syn.eld"))
+
+(ert-deftest sqlind-ert-pr19 ()
+  (sqlind-ert-check-file-syntax "test-data/pr19.sql" "test-data/pr19-syn.eld"))
+
diff --git a/sql-indent.el b/sql-indent.el
index 75e3c9c..4db48fc 100644
--- a/sql-indent.el
+++ b/sql-indent.el
@@ -270,7 +270,7 @@ But don't go before LIMIT."
     (catch 'done
       (while (not (eq (point) (or limit (point-min))))
         (when (re-search-backward
-               ";\\|\\b\\(begin\\|loop\\|if\\|then\\|else\\|elsif\\)\\b\\|)"
+               
";\\|\\b\\(declare\\|begin\\|cursor\\|loop\\|if\\|then\\|else\\|elsif\\)\\b\\|)"
                limit 'noerror)
           (unless (sqlind-in-comment-or-string (point))
             (let ((candidate-pos (match-end 0)))
@@ -279,6 +279,9 @@ But don't go before LIMIT."
                      ;; of the keywords inside one of them and think this is a
                      ;; statement start.
                      (progn (forward-char 1) (forward-sexp -1)))
+                    ((looking-at "\\bcursor\\b")
+                     ;; statement begins at the start of the keyword
+                     (throw 'done (point)))
                     ((looking-at "\\b\\(then\\|else\\)\\b")
                      ;; then and else start statements when they are inside
                      ;; blocks, not expressions.
@@ -525,6 +528,9 @@ See also `sqlind-beginning-of-block'"
                  ((and (listp previous-block-kind)
                        (eq (nth 0 previous-block-kind) 'defun-start))
                   (list 'in-begin-block 'defun (nth 1 previous-block-kind)))
+                  ((and (listp previous-block-kind)
+                        (memq (nth 0 previous-block-kind) '(package 
package-body)))
+                   (list 'in-begin-block 'package (nth 1 previous-block-kind)))
                  (t
                   (list 'in-begin-block nil begin-label)))))
 
@@ -549,7 +555,8 @@ See also `sqlind-beginning-of-block'"
             (cond ((memq previous-block-kind '(toplevel declare-statement))
                    (goto-char (cdr previous-block)))
                   ((and (listp previous-block-kind)
-                        (eq (nth 0 previous-block-kind) 'defun-start))
+                        (memq (nth 0 previous-block-kind)
+                               '(defun-start package package-body)))
                    (unless (sqlind-labels-match
                             label (nth 1 previous-block-kind))
                      (throw 'finished
@@ -1214,10 +1221,20 @@ procedure block."
                  ;; else, maybe we have a DML statement (select, insert,
                  ;; update and delete)
 
-                 ;; skip a cursor definition if it is before our point
-                 (when (looking-at "cursor[ \t\r\n\f]+[a-z0-9_]+[ 
\t\r\n\f]+is[ \t\r\n\f]+")
-                   (when (<= (match-end 0) pos)
-                     (goto-char (match-end 0))))
+                 ;; skip a cursor definition if it is before our point, in the
+                 ;; following format:
+                 ;;
+                 ;; CURSOR name IS
+                 ;; CURSOR name type IS
+                 (when (looking-at "cursor\\b")
+                   (let ((origin (point)))
+                     (forward-sexp 3)
+                     (sqlind-forward-syntactic-ws)
+                     (when (looking-at "is\\b")
+                       (goto-char (match-end 0))
+                       (sqlind-forward-syntactic-ws))
+                     (unless (<= (point) pos)
+                       (goto-char origin))))
 
                  ;; skip a forall statement if it is before our point
                  (when (looking-at "forall\\b")
@@ -1363,11 +1380,12 @@ The following syntax symbols are defined for SQL code:
 - (in-begin-block KIND LABEL) -- line is inside a block started
   by a begin statement.  KIND (a symbol) is \"toplevel-block\"
   for a begin at toplevel, \"defun\" for a begin that starts the
-  body of a procedure or function, nil for a begin that is none
-  of the previous.  For a \"defun\", LABEL is the name of the
-  procedure or function, for the other block types LABEL contains
-  the block label, or the empty string if the block has no label.
-  ANCHOR is the start of the block.
+  body of a procedure or function, \"package\" for a begin that
+  starts the body of a package, or nil for a begin that is none
+  of the previous.  For a \"defun\" or \"package\", LABEL is the
+  name of the procedure, function or package, for the other block
+  types LABEL contains the block label, or the empty string if
+  the block has no label.  ANCHOR is the start of the block.
 
 - (block-start KIND) -- line begins with a statement that starts
   a block.  KIND (a symbol) can be one of \"then\", \"else\" or
diff --git a/test-data/pr19-syn.eld b/test-data/pr19-syn.eld
new file mode 100644
index 0000000..3398c1f
--- /dev/null
+++ b/test-data/pr19-syn.eld
@@ -0,0 +1,138 @@
+(((toplevel . 1))
+ ((declare-statement . 1))
+ ((statement-continuation . 11))
+ ((select-clause . 30)
+  (statement-continuation . 11))
+ ((select-clause . 30)
+  (statement-continuation . 11))
+ (((in-select-clause "where")
+   . 68)
+  (statement-continuation . 11))
+ ((declare-statement . 1))
+ ((declare-statement . 1))
+ ((declare-statement . 1))
+ ((declare-statement . 1))
+ (((defun-start "get_my_value")
+   . 149))
+ (((defun-start "get_my_value")
+   . 149))
+ (((defun-start "get_my_value")
+   . 149))
+ ((statement-continuation . 241))
+ ((select-clause . 297)
+  (statement-continuation . 241))
+ ((select-clause . 297)
+  (statement-continuation . 241))
+ (((defun-start "get_my_value")
+   . 149))
+ (((defun-start "get_my_value")
+   . 149))
+ (((block-start begin)
+   . 149)
+  ((defun-start "get_my_value")
+   . 149))
+ (((in-begin-block defun "get_my_value")
+   . 403))
+ (((in-block loop "")
+   . 413))
+ (((block-end loop "")
+   . 413)
+  ((in-block loop "")
+   . 413))
+ (((block-end defun "get_my_value")
+   . 403)
+  ((in-begin-block defun "get_my_value")
+   . 403))
+ ((declare-statement . 1))
+ (((block-start begin)
+   . 1)
+  (declare-statement . 1))
+ (((in-begin-block toplevel-block "")
+   . 509))
+ (((in-block loop "")
+   . 517))
+ (((block-end loop "")
+   . 517)
+  ((in-block loop "")
+   . 517))
+ (((block-end toplevel-block "")
+   . 509)
+  ((in-begin-block toplevel-block "")
+   . 509))
+ ((toplevel . 1))
+ ((toplevel . 1))
+ ((toplevel . 1))
+ (((package-body "my_pacakge")
+   . 595))
+ (((package-body "my_pacakge")
+   . 595))
+ ((statement-continuation . 661))
+ ((select-clause . 678)
+  (statement-continuation . 661))
+ ((select-clause . 678)
+  (statement-continuation . 661))
+ (((in-select-clause "where")
+   . 714)
+  (statement-continuation . 661))
+ (((package-body "my_pacakge")
+   . 595))
+ (((package-body "my_pacakge")
+   . 595))
+ (((package-body "my_pacakge")
+   . 595))
+ (((package-body "my_pacakge")
+   . 595))
+ (((defun-start "get_my_value")
+   . 785))
+ (((defun-start "get_my_value")
+   . 785))
+ (((defun-start "get_my_value")
+   . 785))
+ ((statement-continuation . 873))
+ ((select-clause . 927)
+  (statement-continuation . 873))
+ ((select-clause . 927)
+  (statement-continuation . 873))
+ (((defun-start "get_my_value")
+   . 785))
+ (((defun-start "get_my_value")
+   . 785))
+ (((block-start begin)
+   . 785)
+  ((defun-start "get_my_value")
+   . 785))
+ (((in-begin-block defun "get_my_value")
+   . 1024))
+ (((in-block loop "")
+   . 1032))
+ (((block-end loop "")
+   . 1032)
+  ((in-block loop "")
+   . 1032))
+ (((block-end defun "get_my_value")
+   . 1024)
+  ((in-begin-block defun "get_my_value")
+   . 1024))
+ (((package-body "my_pacakge")
+   . 595))
+ (((package-body "my_pacakge")
+   . 595))
+ (((in-begin-block package "my_pacakge")
+   . 1120))
+ (((in-block loop "")
+   . 1128))
+ (((block-end loop "")
+   . 1128)
+  ((in-block loop "")
+   . 1128))
+ (((in-begin-block package "my_pacakge")
+   . 1120))
+ (((in-begin-block package "my_pacakge")
+   . 1120))
+ (((block-end package "my_pacakge")
+   . 1120)
+  ((in-begin-block package "my_pacakge")
+   . 1120))
+ ((toplevel . 1))
+ ((toplevel . 1)))
+ 
diff --git a/test-data/pr19.sql b/test-data/pr19.sql
new file mode 100644
index 0000000..3f21314
--- /dev/null
+++ b/test-data/pr19.sql
@@ -0,0 +1,64 @@
+declare
+  cursor cur1 is
+    select dummy
+      from my_table
+     where 1 = 1
+       and col1 = p_col1;
+  
+  p_col1 my_table.col1%type := 42;
+  
+  function get_my_value(p_param1 in my_table.col1%type)
+    return my_table.col2%type is
+
+    cursor cur2 (p_val_col1 in my_table.col1%type) is
+      select col2
+        from my_table
+       where col1 = p_val_col1;
+    
+    v_result my_table.col2%type;
+  begin
+    for rec in cur2(p_param1) loop
+      v_result := rec.col2;
+    end loop;
+  end get_my_value;
+  
+begin
+  for rec in cur1 loop
+    dbms_output.put_line(rec.dummy);
+  end loop;
+end;
+/
+
+create or replace package body my_pacakge authid current user is
+
+cursor cur1 is
+  select 1 dummy
+    from my_table
+   where 1 = 1
+     and col1 = p_col1;
+
+p_col1 my_table.col1%type := 42;
+
+function get_my_value(p_param1 in my_table.col1%type)
+  return my_table.col2%type is
+
+  cursor cur2 (p_val_col1 in my_table.col1%type) is
+    select col2
+      from   my_table
+     where  col1 = p_val_col1;
+
+  v_result my_table.col2%type;
+begin
+  for rec in cur2(p_param1) loop
+    v_result := rec.col2;
+  end loop;
+end get_my_value;
+
+begin
+  for rec in cur1 loop
+    dbms_output.put_line(rec.dummy);
+  end loop;
+  
+  dbms_output.put_line(get_my_value(p_col1));
+end my_pacakge;
+/

Reply via email to