It's pretty trivial to add macros to any language. The only thing that separates a macro from a regular function is time. In a normal function, the parameters are evaluated before being sent to the function. In a macro, the function is called before the parameters are evaluated. What separates lisp from other languages when it comes to macros is that the language is very simple and provides lots of tools for operating on the same data structure that you write your code in.

Of course you can add macros to any language, that doesn't mean they'll be anything like Lisp macros, because you're still writing code that has many different ways of expressing function calls. Importing a file? Oh, don't call a function. Instead write this special syntax which will call that function for you. Declaring or setting a variable? Same shit. What if you wanted to do something really fancy like create a class, oh yeah, there's a special way of saying that too. So now when you go to automate this stuff, you've gotta teach your computer all the special different ways to write everything. Lisp isn't lisp because it has macros. Lisp isn't lisp because it's simple. Lisp isn't lisp because it has a lot of really smart ways of doing basic things that we take for granted (like explicit vs implicit scope on local variables). Lisp is lisp because it has them all.

You can add the same extensibility that lisp has, macros, reader macros, operate on symbols, closures, whatever. You can do some of the really smart things that lisp does like explicitly scoping your variables or multiple dispatch. You can even have a really simple language, with a really simple syntax. But it's not Lisp's individual features that make it what it is, it's how these features interact with one another to give you something that's truly hard to replicate.

Yes, of course you can replace a block of code with another, but how easily? For example, yesterday I was thinking about a variable that represents the result of evaluating the previous form. So instead of having to read a method chain backwards: (wax (buff (rinse (soap car)))) it could read forward: (soap car) (rinse ?) (buff ?) (wax ?) Now whether or not this is a good or bad idea is completely fucking irrelevent. The point is that it's an idea, and until an idea is tested, we have no idea how bad or good it is. In lisp, in 5 minutes, I can write a macro that wraps around a block of code and implements this idea so I can actually play around with it in the real world instead of just in my head. You literally just take a bunch of forms in, put a let statement around the whole block, and then put a call to set the variable around each individual form (If you're not familiar with lisp. a form is kind of like a line of code, it's usually a function call but it can be a value as well). In lisp I can have very abstract programming ideas and then immediately implement them, without having to fight through the language to do so (ie without having to write a parser).

It's cool when other languages take stuff from lisp, it makes it easier to write lisp like code when I have to use other languages, but I've read a lot of articles on "Lisp macros in X Language" and none of them seem to understand that you can't just implement macros, you have to make the structure that code is written "first class". You have to give the programmer the tools they need to operate on a piece of code as naturally as they would a string, a number, or an array.