简体   繁体   中英

Why do these nested macros fail to create bindings in packages that import these macros?

I tried to construct a function template that I can use in other packages with package-specific parameters. The gist of what I tried to achieve this is as follows:

;;; FSM

(in-package #:fsm)

(defmacro %cas (flag old new)
  #+sbcl `(sb-ext:compare-and-swap ,flag ,old ,new)
  #+ecl `(mp:compare-and-swap ,flag ,old ,new)
  )

(defmacro control! (fsm task flag)
  `(let ((*task-category* (tag ,task)))
     (unless (%cas ,flag nil t)
       (lambda () (submit-task (channel (cqueue-prio-out ,fsm)) (fn ,task))))))


;;; REPL

(in-package #:repl)

(defparameter *controller-active* nil)

(control! fsm control-task *controller-active*)

;;; USB-SP

(in-package #:usb-sp)

(defparameter *controller-active* nil)

(control! fsm control-task *controller-active*)

Apparently, this does not work:

Unhandled SIMPLE-ERROR in thread #<SB-THREAD:THREAD "main thread" RUNNING {1001640703}>:
Invalid place to CAS: CNC-HOST/FSM::FLAG -> CNC-HOST/FSM::FLAG

How is this construct properly done?

After receiving feedback on the freenode lisp channel, it became clear to me that the macro construct works as intended:

(defpackage #:fsm    (:use #:cl)       (:export #:control!! #:%cas))
(defpackage #:repl   (:use #:cl #:fsm) (:export #:test-in-repl))
(defpackage #:usb-sp (:use #:cl #:fsm) (:export #:test-in-usb-sp))

;;; FSM

(in-package #:fsm)

(defmacro %cas (flag old new)
  #+sbcl `(sb-ext:compare-and-swap ,flag ,old ,new)
  #+ecl `(mp:compare-and-swap ,flag ,old ,new))

(defmacro control!! (flag pkg)
  `(lambda () (if (%cas ,flag nil t)
                  (format nil "~A : skip task" ,pkg)
                  (format nil "~A : task run" ,pkg))))


;;; REPL

(in-package #:repl)

(defparameter *controller-active* nil)
(defun test-in-repl (pkg) (funcall (control!! *controller-active* pkg)))
(assert (string= "repl : task run" (test-in-repl "repl")))
(assert *controller-active*)

;;; USB-SP

(in-package #:usb-sp)

(defparameter *controller-active* nil)
(defun test-in-usb-sp (pkg) (funcall (control!! usb-sp::*controller-active* pkg)))
(assert (string= "usb-sp : task run" (test-in-usb-sp "usb-sp")))
(assert *controller-active*)

(in-package #:cl-user)

(assert (string= "repl : skip task"   (repl:test-in-repl     "repl")))
(assert (string= "usb-sp : skip task" (usb-sp:test-in-usb-sp "usb-sp")))

The compiler message made me think that I had an error in the macros - instead I overlooked that in my use case control!! should have returned the function call result instead of the lambda .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM