I'll narrate this in the order I "discover" your code. Then I'll present some tweaks which I think mattered the most in the end.
I'm liking a lot of what you've done.
A few names could (should?) be improved. E.g. ast::operators does nothing to suggest its purpose. It's a lazy factory for binary operator expressions.
So, name it make_binary or ...