The short answer is that this is expected behaviour.
You seem to be expecting foo-,arg
to be something like (intern (concat "foo-" (symbol-name ',arg)))
, but there's no reason why that should be the case.
For starters ,arg
evaluates arg
to whatever arbitrary lisp object it has as its value, so there mightn't even be a sensible way to form the end of a symbol name from that value.
Moreover, note that the lisp reader has to read your code into objects before they can be evaluated. For your expectation to work, it would need to read all of foo-,arg
into a form which would subsequently do the interning at evaluation time.
In practice foo-
is read as a symbol, and ,arg
is read into a form recognised by the backquote
processing.
We can call the reader ourselves to see what it actually produces (or rather, we can see the printed representation of those lisp objects; internally those objects are not text, but they are converted back into text for display purposes).
(read "(defmacro test (arg) `(message foo-,arg))")
=> (defmacro test (arg) (\` (message foo- (\, arg))))
Here we see that foo-,arg
has been read into two forms, represented as foo-
and (\, arg)
.
The list structure (\, arg)
is recognised by backquote-process
(backquote-process '(message foo-,arg))
=> (1 list (quote message) (quote foo-) arg)
Naturally we can also see this form in the definition of the test
macro:
(symbol-function 'test)
=> (macro lambda (arg) (list (quote message) (quote foo-) arg))
To get the result you were after, the reader would need to have produced something along these lines:
(read "(defmacro test (arg) `(message foo-,arg))")
=> (defmacro test (arg) (\` (message ,(intern (concat "foo-" (symbol-name (eval arg)))))))