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

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

[elpa] master 68d6973 3/5: Fixed parsing multiple forms inside if/then/e


From: Ian Dunn
Subject: [elpa] master 68d6973 3/5: Fixed parsing multiple forms inside if/then/else blocks
Date: Wed, 7 Feb 2018 20:43:26 -0500 (EST)

branch: master
commit 68d6973ce1509a00d26f86a3addff28b7c42222e
Author: Ian Dunn <address@hidden>
Commit: Ian Dunn <address@hidden>

    Fixed parsing multiple forms inside if/then/else blocks
    
    * org-edna.el (org-edna--normalize-forms): New defun.
      (org-edna--normalize-sexp-form): Use it for if-statements
      (org-edna--normalize-all-forms): Use it.
    
    * org-edna-tests.el: Added new parsing tests.
---
 org-edna-tests.el | 86 ++++++++++++++++++++++++++++++++++++++++++++++++-------
 org-edna.el       | 61 +++++++++++++++++++++++++--------------
 org-edna.info     | 13 ++++++---
 org-edna.org      |  5 ++++
 4 files changed, 130 insertions(+), 35 deletions(-)

diff --git a/org-edna-tests.el b/org-edna-tests.el
index 01842ec..0a9ddca 100644
--- a/org-edna-tests.el
+++ b/org-edna-tests.el
@@ -175,10 +175,10 @@
          (sexp (org-edna-string-form-to-sexp-form input-string 'action)))
     (should (equal
              sexp
-             '(((if ((match "checklist")
-                     (done?))
-                    ((self)
-                     (todo! TODO))
+             '(((if (((match "checklist")
+                      (done?)))
+                    (((self)
+                      (todo! TODO)))
                   nil)))))))
 
 (ert-deftest org-edna-form-to-sexp-if-else ()
@@ -186,12 +186,78 @@
          (sexp (org-edna-string-form-to-sexp-form input-string 'action)))
     (should (equal
              sexp
-             '(((if ((match "checklist")
-                      (done?))
-                    ((self)
-                     (todo! TODO))
-                  ((siblings)
-                   (todo! DONE)))))))))
+             '(((if (((match "checklist")
+                      (done?)))
+                    (((self)
+                      (todo! TODO)))
+                  (((siblings)
+                    (todo! DONE))))))))))
+
+(ert-deftest org-edna-form-to-sexp-if-multiple-thens ()
+  (let* ((input-string "if match(\"checklist\") done? then self next-sibling 
todo!(TODO) self set-property!(\"COUNTER\" \"0\") endif")
+         (sexp (org-edna-string-form-to-sexp-form input-string 'action)))
+    (should (equal
+             sexp
+             '(((if (((match "checklist")
+                      (done?)))
+                    (((self)
+                      (next-sibling)
+                      (todo! TODO))
+                     ((self)
+                      (set-property! "COUNTER" "0")))
+                  nil)))))))
+
+(ert-deftest org-edna-form-to-sexp-if-multiple-elses ()
+  (let* ((input-string "if match(\"checklist\") done? then self todo!(TODO) 
else siblings todo!(DONE) self todo!(TODO) endif")
+         (sexp (org-edna-string-form-to-sexp-form input-string 'action)))
+    (should (equal
+             sexp
+             '(((if (((match "checklist")
+                      (done?)))
+                    (((self)
+                      (todo! TODO)))
+                  (((siblings)
+                    (todo! DONE))
+                   ((self)
+                    (todo! TODO))))))))))
+
+(ert-deftest org-edna-form-to-sexp-failed-if ()
+  (pcase-let* ((input-string "if match(\"checklist\") done?")
+               (`(,error . ,data) (should-error 
(org-edna-string-form-to-sexp-form
+                                                input-string 'action)
+                                               :type 'invalid-read-syntax)))
+    (should (eq error 'invalid-read-syntax))
+    (should (listp data))
+    (should (eq (length data) 6))
+    (should (string-equal (plist-get data :msg) "Malformed if-construct; 
expected then terminator"))
+    ;; Error should point to the start of the if-statement
+    (should (eq (plist-get data :error-pos) 0))))
+
+(ert-deftest org-edna-form-to-sexp-failed-if-then ()
+  (pcase-let* ((input-string "if match(\"checklist\") done? then")
+               (`(,error . ,data) (should-error 
(org-edna-string-form-to-sexp-form
+                                                input-string 'action)
+                                               :type 'invalid-read-syntax)))
+    (should (eq error 'invalid-read-syntax))
+    (should (listp data))
+    (should (eq (length data) 6))
+    (should (string-equal (plist-get data :msg)
+                          "Malformed if-construct; expected else or endif 
terminator"))
+    ;; Error should point to the start of the if-statement
+    (should (eq (plist-get data :error-pos) 28))))
+
+(ert-deftest org-edna-form-to-sexp-failed-if-then-else ()
+  (pcase-let* ((input-string "if match(\"checklist\") done? then todo!(TODO) 
else todo!(TODO)")
+               (`(,error . ,data) (should-error 
(org-edna-string-form-to-sexp-form
+                                                 input-string 'action)
+                                                :type 'invalid-read-syntax)))
+    (should (eq error 'invalid-read-syntax))
+    (should (listp data))
+    (should (eq (length data) 6))
+    (should (string-equal (plist-get data :msg)
+                          "Malformed if-construct; expected endif terminator"))
+    ;; Error should point to the start of the if-statement
+    (should (eq (plist-get data :error-pos) 45))))
 
 (ert-deftest org-edna-expand-sexp-form ()
   ;; Override cl-gentemp so we have a repeatable test
diff --git a/org-edna.el b/org-edna.el
index a72377b..a4d9d3e 100644
--- a/org-edna.el
+++ b/org-edna.el
@@ -218,44 +218,50 @@ the remainder of FORM after the current scope was parsed."
               ;; ending.  If it doesn't match, throw an error.
               (let (cond-form then-form else-form have-else)
                 (pcase-let* ((`(,temp-form ,r-form)
-                              (org-edna--normalize-sexp-form
+                              (org-edna--normalize-forms
                                remaining-form
                                ;; Only allow conditions in cond forms
                                'condition
+                               '((then))
                                from-string)))
-                  ;; Use car-safe to catch r-form = nil
-                  (unless (equal (car-safe r-form) '(then))
+                  (unless r-form
                     (org-edna--syntax-error
                      "Malformed if-construct; expected then terminator"
-                     from-string (cdr (car-safe r-form))))
+                     from-string error-pos))
+                  ;; Skip the 'then' construct and move forward
                   (setq cond-form temp-form
+                        error-pos (cdar r-form)
                         remaining-form (cdr r-form)))
+
                 (pcase-let* ((`(,temp-form ,r-form)
-                              (org-edna--normalize-sexp-form remaining-form
-                                                             
action-or-condition
-                                                             from-string)))
-                  (unless (member (car-safe r-form) '((else) (endif)))
+                              (org-edna--normalize-forms remaining-form
+                                                         action-or-condition
+                                                         '((else) (endif))
+                                                         from-string)))
+                  (unless r-form
                     (org-edna--syntax-error
                      "Malformed if-construct; expected else or endif 
terminator"
-                     from-string (cdr (car-safe r-form))))
-                  (setq have-else (equal (car r-form) '(else))
+                     from-string error-pos))
+                  (setq have-else (equal (caar r-form) '(else))
                         then-form temp-form
+                        error-pos (cdar r-form)
                         remaining-form (cdr r-form)))
                 (when have-else
                   (pcase-let* ((`(,temp-form ,r-form)
-                                (org-edna--normalize-sexp-form remaining-form
-                                                               
action-or-condition
-                                                               from-string)))
-                    (unless (equal (car-safe r-form) '(endif))
+                                (org-edna--normalize-forms remaining-form
+                                                           action-or-condition
+                                                           '((endif))
+                                                           from-string)))
+                    (unless r-form
                       (org-edna--syntax-error "Malformed if-construct; 
expected endif terminator"
-                                              from-string (cdr (car-safe 
r-form))))
+                                              from-string error-pos))
                     (setq else-form temp-form
                           remaining-form (cdr r-form))))
                 (push `(if ,cond-form ,then-form ,else-form) final-form)))
           ((or 'then 'else 'endif)
            (setq need-break t)
            ;; Push the object back on remaining-form so the if knows where we 
are
-           (setq remaining-form (cons current-form remaining-form)))
+           (setq remaining-form (cons (cons current-form error-pos) 
remaining-form)))
           (_
            ;; Determine the type of the form
            ;; If we need to change state, return from this scope
@@ -291,22 +297,35 @@ the remainder of FORM after the current scope was parsed."
       (push '(!done?) final-form))
     (list (nreverse final-form) remaining-form)))
 
-(defun org-edna--normalize-all-forms (form-list action-or-condition &optional 
from-string)
-  "Normalize all forms in flat form list FORM-LIST.
+(defun org-edna--normalize-forms (form-list action-or-condition end-forms 
&optional from-string)
+  "Normalize forms in flat form list FORM-LIST until one of END-FORMS is found.
 
 ACTION-OR-CONDITION is either 'action or 'condition, indicating
 which of the two types is allowed in FORM.
 
 FROM-STRING is used internally, and is non-nil if FORM was
-originally a string."
+originally a string.
+
+END-FORMS is a list of forms.  When one of them is found, stop parsing."
   (pcase-let* ((`(,final-form ,rem-form) (org-edna--normalize-sexp-form 
form-list action-or-condition from-string)))
     (setq final-form (list final-form))
-    (while rem-form
+    ;; Use car-safe to catch r-form = nil
+    (while (and rem-form (not (member (car (car-safe rem-form)) end-forms)))
       (pcase-let* ((`(,new-form ,r-form)
                     (org-edna--normalize-sexp-form rem-form 
action-or-condition from-string)))
         (setq final-form (append final-form (list new-form))
               rem-form r-form)))
-    final-form))
+    (list final-form rem-form)))
+
+(defun org-edna--normalize-all-forms (form-list action-or-condition &optional 
from-string)
+  "Normalize all forms in flat form list FORM-LIST.
+
+ACTION-OR-CONDITION is either 'action or 'condition, indicating
+which of the two types is allowed in FORM.
+
+FROM-STRING is used internally, and is non-nil if FORM was
+originally a string."
+  (car-safe (org-edna--normalize-forms form-list action-or-condition nil 
from-string)))
 
 (defun org-edna-string-form-to-sexp-form (string-form action-or-condition)
   "Parse string form STRING-FORM into an Edna sexp form.
diff --git a/org-edna.info b/org-edna.info
index 25a9421..33b6708 100644
--- a/org-edna.info
+++ b/org-edna.info
@@ -1523,9 +1523,14 @@ File: org-edna.info,  Node: 10beta6,  Next: 10beta5,  
Up: Changelog
 1.0beta6
 ========
 
+Lots of parsing fixes.
+
    • Fixed error reporting
+
    • Fixed parsing of negations in conditions
 
+   • Fixed parsing of multiple forms inside if/then/else blocks
+
 
 File: org-edna.info,  Node: 10beta5,  Next: 10beta4,  Prev: 10beta6,  Up: 
Changelog
 
@@ -1667,10 +1672,10 @@ Node: Development43742
 Node: Documentation44895
 Node: Changelog45340
 Node: 10beta645548
-Node: 10beta545716
-Node: 10beta446103
-Node: 10beta346356
-Node: 10beta246795
+Node: 10beta545808
+Node: 10beta446195
+Node: 10beta346448
+Node: 10beta246887
 
 End Tag Table
 
diff --git a/org-edna.org b/org-edna.org
index 0676a31..e3422de 100644
--- a/org-edna.org
+++ b/org-edna.org
@@ -1292,8 +1292,13 @@ making any changes:
 :DESCRIPTION: List of changes by version
 :END:
 ** 1.0beta6
+Lots of parsing fixes.
+
 - Fixed error reporting
+
 - Fixed parsing of negations in conditions
+
+- Fixed parsing of multiple forms inside if/then/else blocks
 ** 1.0beta5
 Some new forms and a new build system.
 



reply via email to

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