There indeed was a language named LISP 2: https://dl.acm.org/doi/pdf/10.1145/1464291.1464362
I posted it on HN two weeks ago but it didn't get much traction: https://news.ycombinator.com/item?id=41640147
How it this different from tree-sitter, except that you can feed the modified code back to the language to evaluate?
I mean, don't get me wrong, Julia metaprogramming seems lovely, but it just seems to me that the word loses meaning if it can applied to all languages with AST macros, no matter how gnarly the AST data structure is (is Rust homoiconic because of proc_macro?).
However, that's not a parsed data structure; it's a Julia expression to construct one. Though I don't have Julia installed, apparently you can just as well write that as :(a + b*c + 1), as explained a few paragraphs further down the page than I guess you read: https://docs.julialang.org/en/v1/manual/metaprogramming/#Quo.... That's also how Julia represents it for output, by default. What you've written there is the equivalent of Lisp (list '+ 'a (list '* 'b 'c) 1), or perhaps (cons '+ (cons 'a (cons (cons '* (cons 'b (cons 'c '()))) (cons 1 '())))). The data structure is as simple as Prolog's, consisting of a .head such as :call and a list of .args. Prolog's, in turn, is only slightly more complex than Lisp's. From a certain point of view, Prolog's structure is actually simpler than Lisp's, but it's arguable.
How this is different from having a tree-sitter parser is that it's trivially easy to construct and analyze such structures, and not just at compile time.
Possibly the source of your confusion is the syntactic sugar which converts x + y + z into what we'd write in Lisp as (+ x y z), and also converts back? I would argue that such syntactic sugar is precisely what you want for constructing and analyzing expressions. That is, it's part of what makes Julia homoiconic in a more useful sense than J. Random Language equipped with a parser for its own syntax.