(feat): implement parenthesis and boolean binary boolean operators.

This commit is contained in:
savnkk_manjaro 2021-07-12 20:49:15 -07:00
parent 94f9e6f303
commit c1807340de

View file

@ -298,6 +298,11 @@ See Info node `(org-ql)Queries'."
:type 'boolean :type 'boolean
:risky t) :risky t)
(defcustom org-ql-default-predicate-boolean 'and
"Default boolean to combine search terms."
:type 'boolean
:group 'org-ql)
;;;; Macros ;;;; Macros
;;;###autoload ;;;###autoload
@ -868,8 +873,13 @@ value of `org-ql-predicates')."
;; obscure bug in `peg': when one keyword is a substring of another, ;; obscure bug in `peg': when one keyword is a substring of another,
;; and the shorter one is listed first, the shorter one fails to match. ;; and the shorter one is listed first, the shorter one fails to match.
(-sort (-on #'> #'length)))) (-sort (-on #'> #'length))))
(pexs `((query (+ term (pexs `((query sum (opt eol))
(opt (+ (syntax-class whitespace) (any))))) (sum value (* (or (and _ "and" _ value `(a b -- (list 'and a b)))
(and _ "or" _ value `(a b -- (list 'or a b)))
(and _ value `(a b -- (list org-ql-default-predicate-boolean a b))))))
(value
(or term
(and "(" (opt _) sum (opt _) ")" (opt _))))
(term (or (and negation (list positive-term) (term (or (and negation (list positive-term)
;; This is a bit confusing, but it seems to work. There's probably a better way. ;; This is a bit confusing, but it seems to work. There's probably a better way.
`(pred -- (list 'not (car pred)))) `(pred -- (list 'not (car pred))))
@ -883,18 +893,22 @@ value of `org-ql-predicates')."
(predicate (or ,@predicate-names)) (predicate (or ,@predicate-names))
(args (list (+ (and (or keyword-arg quoted-arg unquoted-arg) (opt separator))))) (args (list (+ (and (or keyword-arg quoted-arg unquoted-arg) (opt separator)))))
(keyword-arg (and keyword "=" `(kw -- (intern (concat ":" kw))))) (keyword-arg (and keyword "=" `(kw -- (intern (concat ":" kw)))))
(keyword (substring (+ (not (or separator "=" "\"" (syntax-class whitespace))) (any)))) (keyword (substring (+ (not (or brackets separator "=" "\"" (syntax-class whitespace))) (any))))
(quoted-arg "\"" (substring (+ (not (or separator "\"")) (any))) "\"") (quoted-arg "\"" (substring (+ (not (or separator "\"")) (any))) "\"")
(unquoted-arg (substring (+ (not (or separator "\"" (syntax-class whitespace))) (any)))) (unquoted-arg (substring (+ (not (or brackets separator "\"" (syntax-class whitespace))) (any))))
(negation "!") (negation "!")
(separator "," ))) (separator "," )
(operator (or "and" "or"))
(brackets (or "(" ")"))
(_ (* [" \t"]))
(eol (or "\n" "\r\n" "\r"))))
(closure (lambda (input &optional boolean) (closure (lambda (input &optional boolean)
"Return query parsed from plain query string INPUT. "Return query parsed from plain query string INPUT.
Multiple predicate-names are combined with BOOLEAN (default: `and')." Multiple predicate-names are combined with BOOLEAN (default: `and')."
;; HACK: Silence unused lexical variable warnings. ;; HACK: Silence unused lexical variable warnings.
(ignore predicates predicate-names names aliases) (ignore predicates predicate-names names aliases)
(unless (s-blank-str? input) (unless (s-blank-str? input)
(let* ((boolean (or boolean 'and)) (let* ((org-ql-default-predicate-boolean (or boolean org-ql-default-predicate-boolean))
(parsed-sexp (parsed-sexp
(with-temp-buffer (with-temp-buffer
(insert input) (insert input)
@ -908,8 +922,7 @@ value of `org-ql-predicates')."
(eval `(with-peg-rules ,pexs (eval `(with-peg-rules ,pexs
(peg-run (peg ,(caar pexs)) #'peg-signal-failure)))))) (peg-run (peg ,(caar pexs)) #'peg-signal-failure))))))
(pcase parsed-sexp (pcase parsed-sexp
(`(,one-predicate) one-predicate) (`(,_) (car parsed-sexp))
(`(,_ . ,_) (cons boolean (reverse parsed-sexp)))
(_ nil))))))) (_ nil)))))))
(fset 'org-ql--query-string-to-sexp closure))) (fset 'org-ql--query-string-to-sexp closure)))