I guess the moral of the story here is that ,(...) evaluates the entire sexp, and puts the value there.
Yup! If your quasiquoted expression only contains unquotes, the expansion is simple. Basically,
`(sexp1 sexp2 ... ,sexpn ...)
will expand into
(list 'sexp1 'sexp2 ... sexpn ...)
This also applies recursively, so that
`(sexp1 (subexpr1 ,subexpr2))
(list 'sexp1 (list 'subexpr1 subexpr2))
With unquote-splicing, you can think of quasiquote expanding into cons, so
`(sexp1 sexp2 ,@sexp3)
will expand into
(cons (list 'sexp1 'sexp2) sexp3)
If you're interested, I encourage you to look over my implementation of quasiquote in Arc. It's actually pretty simple (175 lines with comments), and might help clarify how quasiquotation works.
I'll have to do more reading about macros.
I think you seem to have the mental model for macros down. And I've always said that macros aren't that magical, because they fall out as a natural consequence of the language. Hell, here's a simple Arc "interpreter" that shows how macros are handled differently from functions:
(def interpret (expr)
(if (acons expr)
(let op (interpret (car expr))
(if (isa op 'mac) (interpret (apply (rep op) (cdr expr)))
(isa op 'fn) (apply op (map interpret (cdr expr)))
(eval expr))) ; punt on special forms (fn, if, etc.)
(def maybe-lookup-name (expr)
(if (and (isa expr 'sym) (bound expr))
Here, interpret is really just another name for eval. Macros are simply functions whose inputs are unevaluated code. They construct some other bit of unevaluated code, and that result gets evaluated.
Quasiquote is then just a nice way to construct lists, whether it's unevaluated code for a macro to return or whatever. Its syntax takes some getting used to, but it comes with practice. Happy hacking!