-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add plugin interface to allow frontend replacement #35149
Conversation
This patch introduces the new interface and forwards all frontend functions to it, generally avoiding any other code movement or refactoring.
I still feel a rather inexplicably intense dislike towards this design (I think mostly because Thus, this PR seems to make sense to me only for rapid prototyping (e.g. short term work), but not merging (e.g. long term support). |
The aim here is certainly to merge something which enables iteration on replacing the frontend by incrementally replacing flisp components, and supporting a transition period where the new parser can be made opt-in. This is not about having a perfect solution right now; it's about enabling iteration as a risk reduction strategy: Rewriting the entire frontend is going to take some time and it's not something I'd like to do in a single massive PR - I think there's a nonzero risk that such a large project will stall again (for whatever reason we cannot yet predict). So yes, I would like to merge this ugly but internal interface in the support of the above goals, with the aim of removing it as soon as possible. However, I'd be happy with an alternative solution provided it supports the goals:
|
Ok, so having a look at For flisp, in this PR we have the call chain
And in a potential julia replacement it would be
Am I correct in thinking it's this second thing you find particularly objectionable? |
Assuming I'm on the right track, would you find it better if we inverted this whole thing to make the old code path more ugly so that the new code path can stay in Julia? For example, suppose we had in # Call into flisp parser
function flisp_parse_string(...)
ccall(:jl_parse_string ...)
end
const _parse_string = Ref{Any}(flisp_parse_string)
function parse_string(args...)
_parse_string[](args...)
end flisp call chain from Julia is then
Whereas calling a pure julia parser would look like
A big downside of this approach is that we must deal with the difficulties of parser bootstrapping right away before we can reap any benefits. |
The precise goal is to make it easy to switch back and forth between the flisp parser, which is written in C and a potential pure julia parser. We'll likely be needing to that for a while, if only for bootstrapping purposes. In particular, I'd like to be able to have the parser be able to be a standalone .so, whether that so be written in flisp or Julia. Having the interface have a C ABI rather than a Julia ABI makes a lot of sense to me for that use case, esp since we call these functions both from C and Julia. @vtjnash I think it would help if you could elaborate on the precise nature of your objections, so we can improve this PR towards a useful state. |
Oh, I've left out what the call chain looks like from the C side. During the transition period we'd have something like for the flisp code,
for the julia replacement,
(just using parse_string as an example. All other frontend-related functions would need similar treatment.) |
This just looks like an arbitrary set of functions smashed together. There's 12 things in here, but only 2 are related to the parser ( If the goal is to do incremental development of the parser, I'd think the first step would be to export the actual guts of the parser, so that you can replace the specific internal components. You don't actually need much for that though, since you can just directly edit the scheme code on the fly (e.g. poke the |
Once we finish bootstrapping, we only call the parser from Julia (e.g. |
Do you refer to the I think it's fair to say that these chosen entry points are still coupled to the runtime state in an awkward way. In particular, there are many data flows which are implicit in the interface:
I feel like there's been a bunch of surface level reasons offered for why this approach is bad, but the implicit data flow is actually the bigger problem. @vtjnash would you agree this is the real problem? (@JeffBezanson — this is more what I was complaining about a few days ago on a call when I said the number of functions was large. It would have been more accurate to say "I feel bad about this interface" and to have a deeper think about the reasons.) |
To address some other assorted questions and quibbles:
Our current plan is to do a wholesale replacement by adapting The goal for lowering is to continue with #32201 in some form. Currently that's a fairly direct translation of lowering so it could be done more incrementally, in principle. Bootstrap would be "interesting".
There's 500 lines of flisp code in
I would have thought we'd continue to support the embedding API
So having said that myself, we've still got to make progress here in some way. I'd be kind of ok with just abandoning this approach for now and trying to more specifically attack the problem of replacing the parser. That may better inform exactly what interface we need. (But I'd also point out that Keno has already done such prototyping in #31954.) Another idea would be to make all the data flow explicit by passing callbacks which functions like Overall I would say I'm not wedded to the design here. I simply want a way forward and this is one possibility (essentially a modernization and cleanup of the approach taken in #31954). |
I think the reason So, I don't think there is any need for callbacks; anything involving evaluation can be done fully outside the front-end. The parser can just spit out expressions, and lowering can just convert expressions to other expressions. I think the |
I mean the queries like
Yeah, this is a new feature and hard to do well. The promise here is that you can only get warnings if you're doing top-level eval, so we know the caller is special and is expecting to handle warnings.
Correct, but that's largely why I moved this pass entirely into C now. Makes it much easier to deal with GC roots in particular.
We may want to revisit this now. In theory it reduces round-trips, but since docs are a macro, I'm guessing we almost always do the round trip anyways. So possibly might as well eliminate this now and just
That's actually lowering code, but it just usually is only needed if there was a macro. It's a legacy name.
True, though wouldn't be unusual for this to call into Julia directly and just assume it's there. |
Good to chat about this on a call, thanks guys. I think the consensus was: First step is to refactor parsing into a single entry point which takes a string and parsing flags (greedy etc), and returns a Julia Actually I think we forgot to cover the desired ABI. For now I'll go with C ABI. Another interesting snippet from the call — we discussed bootstrapping and the idea that we could distribute a simple text form of the parsed code to enable bootstrapping from C. Naturally SExpressions were mentioned :-) |
Yep. I know there's a plan/desire for this code not to be there... but in the current state of things it is.
Agreed, I remember what it was like before. Then one day (a year or two ago?) I was reading the source and I realized you'd cleaned it all up. Certainly it's a lot nicer now. |
Will be replaced by #35243 |
This is a revival of #32063, but with a lot less code movement. (Moving code can be done as separate NFC later if desired.)
The idea here is to allow the flisp frontend to be incrementally replaced with a frontend written in julia. Parts of the frontend can be replaced in a piecemeal fashion by starting with the result of
@ccall jl_flisp_frontend()::NTuple{12,Ptr{Cvoid}}
and only updating some of the pointers.It would be nice if
jl_frontend_t
could be slimmed down a lot in the future (perhaps along the lines of #31954 (comment)), but for now this patch reflects the frontend as it exists, avoiding any other code movement or refactoring.