| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| <> Opts.showDefault | ||
| <> Opts.help "The output directory" | ||
|
|
||
| globWarningOnMisses :: (String -> IO ()) -> [FilePath] -> IO [FilePath] |
There was a problem hiding this comment.
Command.Graph, Command.Compile, and Command.Codegen all contain the same definition here, but I wasn't sure the most appropriate place to pull it out to for sharing.
If there is an appropriate place to move this then I will update all 3 of those modules.
Sorry, something went wrong.
There was a problem hiding this comment.
Sounds like a good idea. Create a Command.Common module?
Sorry, something went wrong.
| -- ^ Read the externs file for a module as a string and also return the actual | ||
| -- path for the file. | ||
| , codegen :: CF.Module CF.Ann -> Docs.Module -> ExternsFile -> SupplyT m () | ||
| , codegen :: CF.Module CF.Ann -> Docs.Module -> Maybe ExternsFile -> SupplyT m () |
There was a problem hiding this comment.
When performing codegen via purs codegen - we can create a stub ExternsFile via the CoreFn.Module - but it isn't actually the ExternsFile we want to write. I modified this so that we don't write a bogus ExternsFile during purs codegen
Sorry, something went wrong.
There was a problem hiding this comment.
Maybe it would be better to factor codegen the function into a function for each output (including the externs file), and only use the JS-outputting function for purs codegen.
Sorry, something went wrong.
There was a problem hiding this comment.
Good idea - I can go ahead and do that now
Sorry, something went wrong.
| -- ^ Read the externs file for a module as a string and also return the actual | ||
| -- path for the file. | ||
| , codegen :: CF.Module CF.Ann -> Docs.Module -> ExternsFile -> SupplyT m () | ||
| , codegen :: CF.Module CF.Ann -> Docs.Module -> Maybe ExternsFile -> SupplyT m () |
There was a problem hiding this comment.
Maybe it would be better to factor codegen the function into a function for each output (including the externs file), and only use the JS-outputting function for purs codegen.
Sorry, something went wrong.
| <> Opts.showDefault | ||
| <> Opts.help "The output directory" | ||
|
|
||
| globWarningOnMisses :: (String -> IO ()) -> [FilePath] -> IO [FilePath] |
There was a problem hiding this comment.
Sounds like a good idea. Create a Command.Common module?
Sorry, something went wrong.
|
|
||
| foreigns <- P.inferForeignModules filePathMap | ||
| (makeResult, makeWarnings) <- | ||
| liftIO |
There was a problem hiding this comment.
Is liftIO needed here?
Sorry, something went wrong.
| return paths | ||
|
|
||
| concatMapM :: (a -> IO [b]) -> [a] -> IO [b] | ||
| concatMapM f = fmap concat . mapM f |
There was a problem hiding this comment.
While you're messing around with this, you can import concatMapM from Protolude. Don't know why we aren't already doing that.
Sorry, something went wrong.
| concatMapM f = fmap concat . mapM f | ||
|
|
||
| -- | Arguments: use JSON, warnings, errors | ||
| printWarningsAndErrors :: Bool -> P.MultipleErrors -> Either P.MultipleErrors a -> IO () |
There was a problem hiding this comment.
This is just Command.Compile.printWarningsAndErrors True, right? Looks like another candidate for Command.Common.
Sorry, something went wrong.
There was a problem hiding this comment.
Ah, it is, great call
Sorry, something went wrong.
|
Sorry, things got busy around here, I'm going to pick this back up soon to address the feedback. |
Sorry, something went wrong.
|
@rhendric I've addressed your initial feedback. While doing the codegen refactoring, I noticed that purs codegen doesn't allow opting-in to generating source maps - I should probably add an option to the command to allow the user to opt-in to that. |
Sorry, something went wrong.
There was a problem hiding this comment.
Looking good! I have one outstanding question about the runSupplyT 0 here, and I suggest rebasing on master to clean up some conflicts and HLint nits, but I think this is in great shape already.
Sorry, something went wrong.
| foreigns <- P.inferForeignModules filePathMap | ||
| (makeResult, makeWarnings) <- | ||
| P.runMake purescriptOptions | ||
| $ runSupplyT 0 |
There was a problem hiding this comment.
In the normal compilation path, the codegen supply monad is initialized with the next unused number from previous parts of the compilation. Using 0 here raises the question of whether this reuse is necessary. If so, using 0 here might cause problems. If not (I suspect not), we should probably be consistent so that the produced code isn't different when generated just by purs compile versus purs compile; purs codegen.
So assuming it's safe to do so, I think we should remove the SupplyT from the signatures in MakeActions and push that detail into their implementations. But now would be a really good time for someone else to share why that wouldn't be safe!
Sorry, something went wrong.
There was a problem hiding this comment.
This is a great point. I tried reading through the usages of the supply monad in the codegen code and it looks like it's just for generating fresh variable names - it doesn't seem to me that it'd require we start off from where we left off in say typechecking - but I don't have enough experience to say for sure.
At work we've been using zephyr for quite a while, which also starts from 0 for codegen, so I'd be really surprised if it causes errors.
If it is the case that it doesn't matter, then I'll remove the SupplyT requirement and start it from zero within codegenJS.
Sorry, something went wrong.
There was a problem hiding this comment.
I spent some time going through the codegenJS implementation and I don't think that it is dangerous to always initial that supply with 0. The fact that zephyr was doing that for so long also makes me pretty confident based on my personal experience.
I went ahead and made the change you suggested, and all tests are passing.
If anyone knows more than I do and thinks that we should undo the change, I can do that too!
Sorry, something went wrong.
| M.fromList $ map ((\m -> (CoreFn.moduleName m, Right $ CoreFn.modulePath m)) . snd) $ rights mods | ||
|
|
||
| unless (null (lefts mods)) $ do | ||
| _ <- traverse (hPutStr stderr . formatParseError) $ lefts mods |
There was a problem hiding this comment.
hlint will yell at you for this when you rebase on master. Use traverse_.
Sorry, something went wrong.
| runCodegen foreigns filePathMap m = | ||
| P.codegenJS (makeActions foreigns filePathMap) False m |
There was a problem hiding this comment.
hlint will yell at you for this too, but actually I think you should probably just inline this whole definition.
Sorry, something went wrong.
|
I'll spend some time thinking about how we could add a meaningful test for this soon. Other than that, there is the outstanding question of initializing the codegen supply with 0, which I've gone ahead and done. Then this should be ready for a final review! |
Sorry, something went wrong.
| M.fromList $ map ((\m -> (CoreFn.moduleName m, Right $ CoreFn.modulePath m)) . snd) $ rights mods | ||
|
|
||
| unless (null (lefts mods)) $ do | ||
| traverse_ (hPutStr stderr . formatParseError) $ lefts mods |
There was a problem hiding this comment.
Since left mods is used twice, perhaps this should be turned into a let above?
let errList = lefts modsAlso, since filePathMap isn't used until after the unless block, perhaps it should go below this block but above the foreigns <- P.inferForeignMoudles filePathMap line?
Sorry, something went wrong.
| (makeResult, makeWarnings) <- | ||
| P.runMake purescriptOptions | ||
| $ traverse (P.codegenJS (makeActions foreigns filePathMap) codegenSourceMaps . snd) | ||
| $ rights mods |
There was a problem hiding this comment.
Here's a second rights mods. Perhaps that should also be moved to a let binding so more things can reuse it?
Sorry, something went wrong.
|
@colinwahl do you have bandwidth to finish this off? Can I help? |
Sorry, something went wrong.
|
@MaybeJustJames would you like to take this over from me? My bandwidth for compiler work is pretty low these days. The big open question is that I'm still not sure if #4092 (comment) could lead to any problems. |
Sorry, something went wrong.
|
As the question is over a year old, I'm inclined to say let's ship it and find out. |
Sorry, something went wrong.
|
Happy to take over. How would you like to do it? |
Sorry, something went wrong.
However you'd like to do it is fine with me - you could continue off this PR, or make a new branch and cherry-pick my changes, or just close it and start again from scratch. Let me know what you decide and if I should close this PR! |
Sorry, something went wrong.
IMHO it would be a shame to lose the context here. Could I get write permission to your branch so I can pick up from here? |
Sorry, something went wrong.
|
I was wondering - is this work necessary at all now that we have the backend optimizer? |
Sorry, something went wrong.
Supporting an optimizer was certainly my main goal for this - now that we've got purescript-backend-optimizer, I don't think I'd use the command (at least, I don't have anything in mind ATM). However, maybe someone's got other ideas :) |
Sorry, something went wrong.
|
It does strike me as a loss if the best general-purpose JavaScript backend for PureScript remains in a third-party project in the long term. I'm not sure how exactly this happened—I suspect the friction to contributing to PureScript is just too high for this level of innovation—but with enough time I would hope it can be mostly unforked. At that point, exposing the backend used by purs becomes a feature of interest again, unless the unforking includes some other mechanism for making the CoreFn-handling pipeline extensible. |
Sorry, something went wrong.
|
@rhendric I agree with you - my point here is that the new backend has shuffled the landscape quite a bit: it shows not only that it's possible to aggressively optimise the CoreFn, but also that it's possible to emit more performant JS outside of the compiler, and all of this while the implementation is in PureScript. |
Sorry, something went wrong.
|
Okay yeah, I agree with looking at bundle as an example. We got rid of bundle when the ecosystem around ES modules matured enough and we did enough work on our codegen that we could recommend another no-regrets tool to replace it; waiting for those things to happen was what made deprecating bundle take so long, as far as I know. Is purs-backend-es already that no-regrets tool for codegen? It's very impressive but also very young and possibly more aggressive than some of our users want. If it becomes that tool in the future, I don't see a significant barrier to ripping codegen back out, along with all the codegen internals. Just like with bundle, we'll paper over the switch in spago and basic users won't need to be aware of it. In the meantime, as long as there's some value in having a built-in JS backend (regardless of the language in which the backend is written or the repo in which it lives), I think there's still a case for exposing it, so users can benefit from custom optimizations and rewrites without needing to also use a third-party backend. |
Sorry, something went wrong.
purs-backend-es does not subsume compiler functionality.
So, I do not see any near term future where the current JS backend is rendered obsolete, though I would like a near term future where something like purs-backend-es can be used in a first-class way. That being said, if there are currently no pending users of this feature, I'm not sure what the point is. I think the fresh name issue seems like it can clearly cause a problem, however unlikely, and I'm not sure how you'd fix it. I don't know how I feel about merging a feature with a uncertain prospects and potentially buggy behavior. I'm happy to talk about purs-backend-es background/motivation in general, but I don't think this is the place. If you have any thoughts or questions, I'd love to hear from you on discourse! |
Sorry, something went wrong.
I agree. I wanted to get this through for zephyr specifically. There is potential for other optimization tools to make use of this interface even if an improved backend is eventually merged. |
Sorry, something went wrong.
Also expose the new codegenJS action for use in purs codegen
Always initialize supply with 0 as codegenJS implementation detail in order to get deterministic variable naming while doing a normal purs compile vs purs compile; purs codegen
Co-authored-by: Ryan Hendrickson <ryan.hendrickson@alum.mit.edu>
|
I think this PR can be closed, right? |
Sorry, something went wrong.
|
I would still vote to merge for the zephyr | ${other_optimizer} use case. |
Sorry, something went wrong.
|
Is the vision for purescript to have multiple codegen backends? If non-javascript backends are always going to be separate projects then maybe to makes sense for JavaScript codegen to be separate too? In which case this PR should be closed. If the vision for the compiler is to include multiple backends then I think a codegen command will remain useful |
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
Description of the change
Implements a new command: purs codegen
purs codegen takes globs to filepaths containing the JSON representation of a CoreFn Module (this can be generated by purs compile). It parses the core functional representation out of these files, and passes them in to the standard codegen function.
This command allows for CoreFn transformations to be written outside of the compiler (even in PureScript!) without having to worry about using PureScript as a library.
Example usage of this would be:
This intends to close #3339
Checklist: