Doesn't this feature mean I have to use quasiquotation to build macro results if I want this behavior? I'm guessing if I try to use any function as I'm building macro results, it'll strip '' on the way into the function. This limits me to fexprs that don't use functions this way. And if I use a typical macro, that macro will probably be prepared for splicing itself, which means it too will intentionally strip '' on the way in.
Now that we're disarmed of functions and of splice-friendly macros (which probably encompasses almost the entire standard library!), we have to see if we can make do with whatever we have left. I don't think that's very much in the spirit of "first-class."
wart> (def helper(a b) `(cons ,a ,b))
wart> (mac foo(a b) (helper a b))
wart> (foo 1 '(2 3))
(1 2 3)
wart> (foo @'(1 (2 3)))
008eval.cc:79 calling macros with splice can have subtle effects (http://arclanguage.org/item?id=15659)
005types.cc:263 can't coerce number 2 to function
Eep! You're right, this is a fairly common use case.
The good news is that wart's warning system has held up. If it can't handle it it throws that warning.
I still emit the warning, because examples like this fail:
wart> (def helper(a b) `(cons ,a ,b))
wart> (mac foo args (helper @args))
wart> (foo @'(1 (2 3)))
008eval.cc:79 calling macros with splice can have subtle effects (http://arclanguage.org/item?id=15659)
005types.cc:263 can't coerce number 2 to function
wart> (mac foo(a b) `(cons ,a ,b))
wart> (mac bar(a b) (prn `(cons 3 ,@(foo a b)))) ; prn for debugging
wart> ((fn(x) (bar x x)) 'abc)
(cons 3 x . x)
004cell.cc:158 car of non-cons: x
004cell.cc:158 car of non-cons: x
(3 . abc)
My bar example is poorly constructed; besides that I think you're right.
wart> (mac foo(a b) `(cons ,a ,b))
wart> (mac bar(a b) `(cons 3 ,(foo a b)))
wart> ((fn(x) (bar x x)) 'abc)
005types.cc:263 can't coerce symbol abc to function
There was a typo in grandparent, so let me summarize the correct versions:
wart> (mac foo(a b) `(cons ,a ,b))
wart> (mac bar(a b) `(cons 3 ,@(foo a b)))
wart> ((fn(x) (bar x x)) @'(abc))
(3 . abc)
wart> (mac foo(a b) `(cons ,a ,b))
wart> (mac bar(a b) `(cons 3 ,(foo a b)))
wart> ((fn(x) (bar x x)) @'(abc))
005types.cc:263 can't coerce symbol abc to function ; no change
I think you're asking what happens to (''a b c). Hmm, I don't translate that to ''(a b c). It seems to be acting like (a b c). Does that seem right?
---
Another potential concern: I'm using a single boolean to track whether we encounter a '', and I reset it before unquote's eval and check it after. I think it might need to be a stack of booleans to handle nested expressions, but I've not been able to come up with a failing test case.
" '' is an internal detail. The reader provides no way to type it in. If you ever see it printed at the REPL, that's a bug."
If unquote adds a '', then `,'foo should return ''foo, right? Then 'write should write ''foo at the REPL.
In order to weasel out of anything that stripped '' from the arguments to a function, I tried putting `, around the whole command, in the hopes that it would somehow manipulate the state of the don't-strip-'' flag(s) for the duration of the command.
In any case, there's no reason foo should be called, is there? O_o
In other news, this might be an easy test case for the scope of the don't-strip-'' flag. If your implementation sets it to true on the way in and false on the way out, then it'll become false on the way out of the inner `, , rather than recovering its previous value of true.
"If unquote adds a '', then `,'foo should return ''foo, right?"
Unquote doesn't add '', @ does. Perhaps that changes your example?
"In any case, there's no reason foo should be called, is there? O_o"
:) Yeah that's a bug with my paren inference; it was implicitly wrapping the expression in parens. I'd never seen backquote-comma before. Here's a temporary workaround:
wart> (list `,(write `,'foo))
foo(foo) ; ignore the (foo) -- it's the return value