The macros run at compile-time, and emit code by use of the <[ ]> blocks -- those get turned into ASTs at compile-time and get filled with the proper data.
Julia is not lisp like, and has macros [1]. The way it works is that your code is first interpreted to get the AST that looks like LISP code (`a+bc+1` becomes `+(a,(b,c),1)`) and your macro operates on that. So basically it works like a lisp macro (until you want to create a macro that creates macro, which is something I haven't done but heard about).
Sweet.js (http://sweetjs.org) and MacroPy (https://github.com/lihaoyi/macropy) come to mind. Actually "real macros" are just macros which operate on AST instead of on strings, they are hard to do if you have to re-implement language parser, but rather easy if the language exposes its AST api, like in Python case.
Haskell's "Template Haskell" system is pretty sophisticated... And challenging enough to be some deep black magic.
You end up being able to reify the entire Haskell syntax tree from "quoted" fragments, manipulate and generate a modified tree, and then "print" it back into program flow.
Totally capable, but not terrifically fun. It also has some compilation restrictions which are annoying if necessary.
I just (last night) dug into some TH hackery. I put together a quasiquoter for testing/debugging that would walk a do block and decorate every statement with (`onException` ...) set up to print the source location when an exception is thrown. I actually had to first parse with haskell-src-exts to get the location info, and currently I'm turning it into an ExpQ by pretty-printing and reparsing - which I don't love, but gets the job done.
TH also ruins Haskell by inserting inivisble code with spooky action at a distance, where you have to pre-import symbols that TH will insert later, and compiler errors refer to code defined somewhere else but print line numbers of where the generated code is inserted. TH needs a compiler!