i am having problem exporting a macro, it works when in it is declared in the same package, but not when it is imported. I use Emacs, SLIME, Clozure on Windows.
Package file
(defpackage :tokenizer
(:use :common-lisp)
(:export :tokenize-with-symbols
:current-token
:advanze-token
:peek-token
:with-token-and-peek
:with-token))
(defpackage :csharp-parser
(:use :common-lisp :tokenizer)
(:import-from :tokenizer :with-token-and-peek :with-token))
Tokenizer file
(in-package :tokenizer)
(defmacro with-token-and-peek (&body body)
`(let ((token (current-token tokenizer))
(peek (peek-token tokenizer)))
,#body))
Parser file
(in-package :csharp-parser)
(defun expression (tokenizer node-stack)
(with-token-and-peek
(cond ((is-number? token) (make-value-node "number" token))
((is-bool? token) (make-value-node "bool" token))
((is-identifier? token peek) (make-identifier-node tokenizer node-stack))
(t (make-ast-node :identifier "bla")))))
Gives the errors on compile:
csharpParser.lisp:265:3:
warning: Undeclared free variable TOKENIZER::TOKENIZER (2 references)
style-warning: Unused lexical variable TOKENIZER::PEEK
style-warning: Unused lexical variable TOKENIZER::TOKEN
csharpParser.lisp:266:14:
warning: Undeclared free variable TOKEN
etc etc etc
If i try a macroexpansion in package :csharp-parser
(macroexpand-1 '(with-token-and-peek tok))
(LET ((TOKENIZER::TOKEN (CURRENT-TOKEN TOKENIZER::TOKENIZER))
(TOKENIZER::PEEK (PEEK-TOKEN TOKENIZER::TOKENIZER)))
TOK)
T
Now like i said if i move the macros to the parser file, it compiles and works perfectly. But when i try to refactor it to the tokenizer file and export it via the package system it gives these errors, because it seems to internalize the symbol to the calling package. I have tried multiple ways via the colons, but can't get it to work.
If anybody could help me with this i would be very thankful.
The symbols TOKEN and PEEK in the macro are interned in the TOKENIZER package, while the code inside the COND uses symbols interned in the CSHARP-PARSER package. There are two ways around this.
Have the expansion use a symbol interned in the package where the code is. This can be done by manually interning a symbol in the current package while expanding the macro. For example:
(defpackage #:foo
(:use #:cl)
(:export #:aif))
(in-package #:foo)
(defmacro aif (test then &optional else)
(let ((it (intern (symbol-name 'it))))
`(let ((,it ,test))
(if ,it ,then ,else))))
(in-package :cl-user)
(use-package :foo)
(aif (+ 3 3) it) ;=> 6
Using (intern (symbol-name 'it)) instead of just (intern "IT") is a way of avoiding problems in case the lisp doesn't convert symbols to uppercase.
Have the code use the symbol interned in the tokenizer package. This can be done by exporting the symbol.
(defpackage #:foo
(:use #:cl)
(:export #:aif
#:it))
(in-package #:foo)
(defmacro aif (test then &optional else)
`(let ((it ,test))
(if it ,then ,else)))
(in-package :cl-user)
(use-package :foo)
(aif (+ 3 3) it) ;=> 6
The drawback is that the user of the macro must import the symbol, so they can't use the package qualified name for the macro.
(defpackage #:foo
(:use #:cl)
(:export #:aif
#:it))
(in-package #:foo)
(defmacro aif (test then &optional else)
`(let ((it ,test))
(if it ,then ,else)))
(in-package :cl-user)
(foo:aif (+ 3 3) it) ; Fails
This happened because the macro with-interned-symbols expanded to code which includes symbols interned in TOKENIZER, while the cond expression has only symbols interned in CSHARP-PARSER. Any symbols (other than keywords or gensyms) that a macro expansion includes should be interned.
The following macro will intern a list of symbols to variables of the same name:
(defmacro with-interned-symbols (symbol-list &body body)
"Interns a set of symbols in the current package to variables of the same (symbol-name)."
(let ((symbol-list (mapcar (lambda (s)
(list s `(intern (symbol-name ',s))))
symbol-list)))
`(let ,symbol-list ,#body)))
The macro with-token-and-peek can be redefined this way using the above to avoid this mismatch:
(with-interned-symbols (token peek)
(defmacro with-token-and-peek (&body body)
`(let ((,token (current-token tokenizer))
(,peek (peek-token tokenizer)))
,#body)))
Note that while anaphoric macros might be the most obvious special case here, this can happen in any macro that introduces new symbols to the expansion, with the exception of keywords as they are always in the keyword package.
Related
I have a very weird requirement that lexically binding a special variable of another package.
In file A.lisp
(defpackage A
(:use #:CL)
(:export #:a-test))
(in-package A)
(declaim (special *a-sp-v*))
(defun a-test (&key (v *a-sp-v*))
(print v))
in file B.lisp
(defpackage B
(:use #:CL #:A))
(in-package B)
(defun b-test ()
(let ((*a-sp-v* 1)) ; cannot let a-test know
(a-test)))
I keep receiving the error The variable A::*A-SP-V* is unbound. in my REPL.
Are there some methods I can bind *a-sp-v* in the package B? Let a-test function running with special *a-sp-v* no matter what package it is in?
Your code is fine (I would use defvar instead of declaim special though).
You can bind any symbol, it does not matter which package it resides in.
You just need to make sure you bind the symbol you need to bind and not something else.
E.g., since you are not exporting a::*a-sp-v* from a, your b-test binds b::*a-sp-v* rather than a::*a-sp-v*.
If you replace *a-sp-v* with a::*a-sp-v* in b-test, it should work.
Alternatively, you can add #:*a-sp-v* to the :export section in (defpackage A ...)
Given the macro:
(defclass sample-class ()
((slot-1 :accessor slot-1
:initform "sample slot")))
(defvar *sample-instance*(make-instance 'sample-class))
(defmacro sample-macro (p)
`(if (typep ,p 'sample-class)
(progn
(print "evaluated")
(print ,(slot-1 p)))))
(sample-macro *sample-instance*)
I am confused as to why this is the error output
Execution of a form compiled with errors.
Form:
(SAMPLE-MACRO *SAMPLE-INSTANCE*)
Compile-time error:
(during macroexpansion of (SAMPLE-MACRO *SAMPLE-INSTANCE*))
There is no applicable method for the generic function
#<STANDARD-GENERIC-FUNCTION COMMON-LISP-USER::SLOT-1 (1)>
when called with arguments
(*SAMPLE-INSTANCE*).
See also:
The ANSI Standard, Section 7.6.6
[Condition of type SB-INT:COMPILED-PROGRAM-ERROR]
Shouldn't the macro expand and evaluate the s-form in the process? Why is the reader not finding the generic function slot-1?
I think you are confused about what macros do. Macros are transformations of source code. So consider what happens when the system tries to expand the macro form (sample-macro *sample-instance*). At macroexpansion time, p is the symbol *sample-instance*: a representation of a bit of source code.
So now, look at the backquoted form in the body of the macro: in it there is ,(slot-1 p): this will try and call slot-1 on whatever p is bound to, which is a symbol. This then fails and the macroexpansion fails as a result.
Well, you could 'fix' this in a way which seems obvious:
(defmacro sample-macro (p)
`(if (typep ,p 'sample-class)
(progn
(print "evaluated")
(print (slot-1 ,p)))))
And this seems to work. Using a macroexpansion tracer:
(sample-macro *sample-instance*)
-> (if (typep *sample-instance* 'sample-class)
(progn (print "evaluated") (print (slot-1 *sample-instance*))))
And if you use the macro it will 'work'. Except it won't work, at all: Consider this form: (sample-macro (make-instance 'sample-class)): well, let's look at that using the macro tracer:
(sample-macro (make-instance 'sample-class))
-> (if (typep (make-instance 'sample-class) 'sample-class)
(progn
(print "evaluated")
(print (slot-1 (make-instance 'sample-class)))))
Oh dear.
So we could work around this problem by rewriting the macro like this:
(defmacro sample-macro (p)
`(let ((it ,p))
(if (typep it 'sample-class)
(progn
(print "evaluated")
(print (slot-1 it)))
And now
(sample-macro (make-instance 'sample-class))
-> (let ((it (make-instance 'sample-class)))
(if (typep it 'sample-class)
(progn (print "evaluated") (print (slot-1 it)))))
Which is better. And in this case it's even safe, but in the great majority of cases we'd need to use a gensym for the thing I've called it:
(defmacro sample-macro (p)
(let ((itn (make-symbol "IT"))) ;not needed for this macro
`(let ((,itn ,p))
(if (typep ,itn 'sample-class)
(progn
(print "evaluated")
(print (slot-1 ,itn)))))))
And now:
(sample-macro (make-instance 'sample-class))
-> (let ((#:it (make-instance 'sample-class)))
(if (typep #:it 'sample-class)
(progn (print "evaluated") (print (slot-1 #:it)))))
So this (and in fact the previous version of it as well) is finally working.
But wait, but wait. What we've done is to turn this thing into something which:
binds the value of its argument to a variable;
and evaluates some code with that binding.
There's a name for something which does that, and that name is function.
(defun not-sample-macro-any-more (it)
(if (typep it 'sample-class)
(progn
(print "evaluated")
(print (slot-1 it)))))
This does everything that the working versions of sample-macro did but without all the needless complexity.
Well, it doesn't do one thing: it doesn't get expanded inline, and perhaps that means it might be a little slower.
Well, back in the days of coal-fired Lisp this was a real problem. Coal-fired Lisp systems had primitive compilers made of wood shavings and sawdust and ran on computers which were very slow indeed. So people would write things which should semantically be functions as macros so the wood-shaving compiler would inline the code. And sometimes this was even worth it.
But now we have advanced compilers (probably still mostly made of wood shavings and sawdust though) and we can say what we actually mean:
(declaim (inline not-sample-macro-any-more))
(defun not-sample-macro-any-more (it)
(if (typep it 'sample-class)
(progn
(print "evaluated")
(print (slot-1 it)))))
And now you can be reasonably assured that not-sample-macro-any-more will be compiled inline.
Even better in this case (but at the cost of almost certainly not having the inlining stuff):
(defgeneric not-even-slightly-sample-macro (it)
(:method (it)
(declare (ignore it))
nil))
(defmethod not-even-slightly-sample-macro ((it sample-class))
(print "evaluated")
(print (slot-1 it)))
So the summary here is:
Use macros for what they are for, which is transforming source code. If you don't want to do that, use functions. If you are sure the that the act of calling the functions is taking up lots of time, then consider declaring them inline to avoid that.
The other answers explained that macro execution is about transforming source code and values available at macro expansion time.
Let's also try to understand the error message. We need to take it literally:
Execution of a form compiled with errors.
Above says that it is about compilation.
Form:
(SAMPLE-MACRO *SAMPLE-INSTANCE*)
Above is the source form which is to be compiled.
Compile-time error:
(during macroexpansion of (SAMPLE-MACRO *SAMPLE-INSTANCE*))
Again: compilation and now specifically during macro expansion.
There is no applicable method for the generic function
#<STANDARD-GENERIC-FUNCTION COMMON-LISP-USER::SLOT-1 (1)>
when called with arguments
(*SAMPLE-INSTANCE*).
Now above is the interesting part: there is no applicable method for the generic function SLOT-1 and the argument *SAMPLE-INSTANCE*.
What is *SAMPLE-INSTANCE*? It's a symbol. In your code is a method, but it is for instances of class sample-class. But there is no method for symbols. So this will not work:
(setf p '*sample-instance*)
(slot-1 p)
That's basically what your code did. You expected to work with runtime values, but all you got at compile time was a source symbol...
The compiler error message showing a compile time error with a source-code element is an indication that there is mixup of runtime and macro-expansion time computation.
See also:
The ANSI Standard, Section 7.6.6
[Condition of type SB-INT:COMPILED-PROGRAM-ERROR]
To understand what the macro is doing, let's use macroexpand.
(macroexpand-1 '(sample-macro *sample-instance*))
=>
There is no applicable method for the generic function
#<STANDARD-GENERIC-FUNCTION COMMON-LISP-USER::SLOT-1 (1)>
when called with arguments
(*SAMPLE-INSTANCE*).
[Condition of type SB-PCL::NO-APPLICABLE-METHOD-ERROR]
Oops, same error message. I will simplify the macro and remove the evaluation around slot-1.
(defmacro sample-macro (p)
`(if (typep ,p 'sample-class)
(progn
(print "evaluated")
(print (slot-1 p)))))
(macroexpand-1 '(sample-macro *sample-instance*))
=>
(IF (TYPEP *SAMPLE-INSTANCE* 'SAMPLE-CLASS)
(PROGN (PRINT "evaluated") (PRINT (SLOT-1 P))))
The code looks good until the variable P. So will it work with, simply, ,p? No need to write ,(slot-1 p) since slot-1 is here correctly.
(defmacro sample-macro (p)
`(if (typep ,p 'sample-class)
(progn
(print "evaluated")
(print (slot-1 ,p)))))
(macroexpand-1 '(sample-macro *sample-instance*))
=>
(IF (TYPEP *SAMPLE-INSTANCE* 'SAMPLE-CLASS)
(PROGN (PRINT "evaluated") (PRINT (SLOT-1 *SAMPLE-INSTANCE*))))
The code looks correct.
(sample-macro *sample-instance*)
"evaluated"
"sample slot"
and it works.
I want to use the package cl-ppcre and series directly on my common lisp environment. I use sly, so in my slynkrc I add this code:
(setf (cdr (assoc '*print-length* slynk:*slynk-pprint-bindings*)) 20)
(setf *print-length* 20)
(setf *evaluator-mode* :interpret)
(ql:quickload '(:alexandria
:cl-ppcre
:cl-interpol
:series
:cl-actors
:chanl
:lparallel))
(eval-when (:compile-toplevel :execute :load-toplevel)
(series::install))
(defun λ-reader (stream char)
(declare (ignore char stream))
'LAMBDA)
(set-macro-character #\λ #'λ-reader)
(use-package :cl-ppcre)
(use-package :cl-interpol)
(interpol:enable-interpol-syntax)
The problem with this is whith the symbol function split. that is in both packages defined.
#<THREAD "main thread" RUNNING {10005605B3}>:
USE-PACKAGE #<PACKAGE "CL-PPCRE"> causes name-conflicts in
#<PACKAGE "COMMON-LISP-USER"> between the following symbols:
CL-PPCRE:SPLIT, SERIES:SPLIT
See also:
In Scala you can import, Renaming a class, but in this case I can use shadowing import, and import only what I need, what is the best solution for that, and if it is possible to import and rename a function in common lisp
You could maybe do it like this:
(defun alias% (as symbol &key (package *package*))
(when (fboundp symbol)
(setf (symbol-function as) (symbol-function symbol)))
(when (boundp symbol)
(setf (symbol-value as) (symbol-value symbol)))
(setf (symbol-plist as) (symbol-plist symbol))
;; maybe also documentation of all types
(shadowing-import as package))
(defmacro defalias (as symbol &key (package *package*))
`(eval-when (:compile-toplevel :load-toplevel :execute)
(alias% ',as ',symbol :package ,package)))
Then you can do:
(defalias foo cl:list)
(foo 1 2 3) ; => (1 2 3)
Looking at the doc on CLtL2, I'd say there is no macro to do that. Please prove me wrong.
Maybe the following works ? I didn't test properly edit: it doesn't work as is.
(use-package :cl-ppcre)
(setf (fdefinition 're-split) #'split) ;; create an alias
(unintern 'split)
(use-package :series)
And now use re-split and split.
I'd like to learn more about lisp macros and I want to create a simple implementation of the defun macro.
I'm also interested in lisp's source code in all the implementations.
This is a tricky question, because of bootstrapping: defun does a lot of things (iow, calls a lot of functions), but to define those functions one needs a working defun. Thus there are three(3!) definitions of defun in clisp/src/init.lisp: at lines
228
1789
1946
The very basic definition of defun could be this:
(defmacro defun (fname lambda-list &rest body)
`(setf (fdefinition ',fname)
(lambda ,lambda-list
(block ,fname ,#body))))
In fact, this is the first definition of defun in CLISP (line 228), except that there is no defmacro and no backquote at that moment yet, so the actual code looks a lot uglier.
See also Is defun or setf preferred for creating function definitions in common lisp and why? where I discuss macroexpansions of defuns.
You can easily check how your particular CL implementation, implemented defun by running
(macroexpand '(defun add2 (x) (+ x 2)))
On SBCL it expands to:
(PROGN
(EVAL-WHEN (:COMPILE-TOPLEVEL) (SB-C:%COMPILER-DEFUN 'ADD2 NIL T))
(SB-IMPL::%DEFUN 'ADD2
(SB-INT:NAMED-LAMBDA ADD2
(X)
(BLOCK ADD2 (+ X 2)))
(SB-C:SOURCE-LOCATION)))
T
To see the particular source code that implemented the I would use (on Emacs) the M-. key binding and then I will write defun and hit enter. Then Emacs will get to the source code:
(sb!xc:defmacro defun (&environment env name lambda-list &body body)
#!+sb-doc
"Define a function at top level."
[...]
I am not going to paste the whole macro as it is rather long. If you are not on Emacs, you can try searching in the repos as most implementations are open source.
BTW defun is not so special. You can implement much of it with setf-inf a symbol-function to a lambda. E.g.:
(setf (symbol-function 'ADD3) #'(lambda (x) (+ x 3)))
; => #<FUNCTION (LAMBDA (X)) {1006E94EBB}>
(add3 4)
; => 7
Why does the following not work?
;;;; foo.lisp
(in-package :cl-user)
(eval-when (:compile-toplevel :load-toplevel :execute)
(require :cl-interpol))
(cl-interpol:enable-interpol-syntax)
(defun read-and-eval (s)
(eval (read-from-string s)))
(cl-interpol:disable-interpol-syntax)
then:
LISP> (load (compile-file "foo.lisp"))
=> T
LISP> (read-and-eval
"(let ((a \"foo\")) (princ #?\"${a}\"))")
=> no dispatch function defined for #\?
Because there's only a single reader, with global state. You're effectively turning your macros on and off. In this case the reader macros are enabled only for the duration that your read-and-eval function is read at compile time.
In this case you would need to set the macros up within the read-and-eval function to ensure the reader is in the proper state when you need it.
CL:READ dispatches based on the readtable bound to CL:*READTABLE* at the time the call to READ runs. Under the hood ENABLE-INTERPOL-SYNTAX is creating a new readtable, setting CL:*READTABLE* to hold it, and stashing the old value of CL:*READTABLE*. DISABLE-INTERPOL-SYNTAX is unstashing the previous readtable and setting CL:*READTABLE* to again hold it. Minimally changing your original setup, you can arrange for the behavior you wanted by the following:
(in-package :cl-user)
(eval-when (:compile-toplevel :load-toplevel :execute)
(require :cl-interpol))
(cl-interpol:enable-interpol-syntax)
(defvar *interpol-reader* *readtable*)
(cl-interpol:disable-interpol-syntax)
(defun read-and-eval (s)
(let ((*readtable* *interpol-reader*))
(eval (read-from-string s))))
The call to disable the syntax could be placed anywhere after the defvar and read-and-eval will still work, but if you want to directly input interpol syntax in the file that syntax will have to be placed between the enable and disable calls. For that latter purpose it is significant that the interpol calls expand into EVAL-WHENs, for the same reason that it is necessary for your call to REQUIRE to be within an EVAL-WHEN; that is, the effects need to have already happened when the latter forms are READ.
CL-INTERPOL's interface abstracts what is happening, so I will show you how you might manually create and change a readtable:
;; Create a fresh readtable with standard syntax
(defvar *not-readtable* (copy-readtable nil))
;; A simple reader function
(defun not-reader (stream char &optional count)
"Like ' but for (not ...) instead of (quote ...)"
(declare (ignore count char))
`(not ,(read stream t nil t)))
;; Mutate that readtable so that the dispatch character you want
;; calls the function you want
(set-macro-character #\! 'not-reader nil *not-readtable*)
;; Try it out
(let ((*readtable* *not-readtable*))
(read-from-string "(if !foo bar baz)"))
=>
(IF (NOT FOO)
BAR
BAZ)