Yes, the Julia parser is mostly a standard recursive descent parser. There’s not really any backtracking, but there’s plenty of places in which it post-processes the parsed output in an ad-hoc fashion. This is a bit like backtracking, but also somewhat like a lowering step built into the parser. It also makes certain parts of the existing parser hard to understand because parsing decisions might be second guessed in some other part of the code. There are places where a single token of input is put back into the token stream, but this is done locally so it’s mostly just an awkward way of peeking two tokens forward.
Most of the expression post-processing isn’t really necessary but comes about from reusing a single parsing function to parse subtly different parts of the grammar. I’ll hazard a guess that a formal Julia grammar would mostly be
LL(1) and no worse than
LL(3) in “most places” so generally it’s quite simple. But there’s a few problematic areas which might push the grammar into a more general class. Classifying parenthesized expressions as tuples vs blocks is particularly messy, especially considering anonymous function argument lists and the distinction between
Expr(:kw, ...) vs normal assignment
Expr(:(=), ...) for keyword arguments. There’s a few other oddities too.
tree-sitter uses the quite general
GLR parsing algorithm which I’d guess could deal with these cases without a problem.