[postmodern-devel] Binary and unary operators

Ivan Boldyrev lispnik at gmail.com
Mon Jan 7 14:50:38 UTC 2008


On 10077 day of my life Marijn Haverbeke wrote:
> ... a patch?

Comment string may require full rewriting.

diff -rN -u old-postmodern/postmodern/package.lisp new-postmodern/postmodern/package.lisp
--- old-postmodern/postmodern/package.lisp      2008-01-07 20:38:27.000000000 +0600
+++ new-postmodern/postmodern/package.lisp      2008-01-07 20:38:27.000000000 +0600
@@ -25,6 +25,7 @@
    #:smallint #:bigint #:numeric #:real #:double-precision
    #:bytea #:text #:varchar
    #:*escape-sql-names-p* #:sql-escape-string
+   #:def-infix-ops
 
    ;; Condition type from cl-postgres
    #:database-error #:database-error-message #:database-error-code
diff -rN -u old-postmodern/s-sql/s-sql.lisp new-postmodern/s-sql/s-sql.lisp
--- old-postmodern/s-sql/s-sql.lisp     2008-01-07 20:38:27.000000000 +0600
+++ new-postmodern/s-sql/s-sql.lisp     2008-01-07 20:38:27.000000000 +0600
@@ -16,6 +16,7 @@
            #:to-sql-name
            #:sql-ize
            #:*escape-sql-names-p*
+           #:def-infix-ops
            #:sql
            #:sql-compile
            #:enable-s-sql-syntax))
@@ -373,21 +374,58 @@
       (destructuring-bind ,arglist ,args-name
         , at body))))
 
-(defun expand-infix-op (operator allow-unary args)
-  (if (cdr args)
-      `("(" ,@(sql-expand-list args (strcat " " operator " ")) ")")
-      (if allow-unary
-          (sql-expand (first args))
-          (error "SQL operator ~A takes at least two arguments." operator))))
-
-(defmacro def-infix-ops (allow-unary &rest ops)
+(defun expand-infix-op (operator class args)
+  (declare (type (member t :both nil) class))
+  (cond
+    ((cdr args)
+     `("(" ,@(sql-expand-list args (strcat " " operator " ")) ")"))
+    ((eq class t)
+     (sql-expand (first args)))
+    ((eq class :both)
+     `(,operator "(" ,@(sql-expand (first args)) ")"))
+    (t
+       (error "SQL operator ~A takes at least two arguments." operator))))
+
+(defmacro def-infix-ops (class &rest ops)
+  (declare (type (member t :both nil) class))
+  "Define infix operators.
+CLASS may be either T, :BOTH or NIL.
+
+  1. T.  S-SQL operators may be both binary and unary, but unary form
+     is equivalent to the only argument itself (e.g.
+     (:AND condition) => \"condition\").
+
+  2. :BOTH.  S-SQL operators may be both binary and unary, but unlike
+     T, operator is kept before the argument in unary form.  Example
+     is PosgreSQL's ?| operator:
+     (def-infix-ops :both :?\\|)
+     (:?\\| a)    => \"?|(a)\"
+     (:?\\| a b)  => \"a ?| b\".
+
+  3. NIL.  Operator is binary only.
+
+OPS is a list of operator designators.  There are two kinds of
+operator designators:
+
+  1. A keyword.  Downcased symbol value of the keword is used as SQL
+     name of operator.
+
+  2. Two-element list: (KEYWORD STRING).  String is used as SQL name
+     of operator, and KEYWORD is S-SQL name of operator.
+     Example: (:concat \"||\")."
   `(progn
     ,@(mapcar (lambda (op)
-                `(defmethod expand-sql-op ((op (eql ,op)) args)
-                  (expand-infix-op ,(string-downcase (symbol-name op)) ,allow-unary args)))
+                (when (keywordp op)
+                  (setf op (list op (string-downcase (symbol-name op)))))
+                (let ((kwd (first op))
+                      (txt (second op)))
+                  `(defmethod expand-sql-op ((op (eql ,kwd)) args)
+                     (expand-infix-op ,txt ,class args))))
               ops)))
-(def-infix-ops t :+ :* :& :|\|| :and :or :union)
-(def-infix-ops nil := :/ :!= :< :> :<= :>= :^ :intersect :except :~* :!~ :!~* :like :ilike)
+
+(def-infix-ops t :+ :* :& :|\|| :and :or :union :\|\| (:concat "||"))
+(def-infix-ops nil := :/ :!= :< :> :<= :>= :^ :intersect :except :~* :!~ :!~*
+                   :like :ilike :&& :% :\# :<< :>>)
 
 (def-sql-op :- (first &rest rest)
   (if rest


-- 
Ivan Boldyrev

                                      Life!  Don't talk to me about life.



More information about the postmodern-devel mailing list