Compiler plugins

Hi,

after reading the ps-inline-asm announcement, I thought to myself that such tools should be run as compiler plugins. Idk exactly how, for instance, GHC plugins work, but my general understanding is that such a plugin would be able to preprocess the PureScript source code and send the preprocessed code for the compiler (and/or emit JS directly), meanwhile reporting any errors in the original source. Some use cases from the top of my head would be inlining JS (as in mentioned thread), inserting HTML tags into Halogen HTML expressions (think JSX), aiding type inference in some cases, expanding templates (I know, TH sucks, but there are some uses for it) etc. Some of it may probably already be achieved using external bundlers / standalone preprocessors; say

jsx :: forall w i. String -> HTML w i

render state = jsx "<img src={state.imageSrc}></img>"

and such code would then be threaded through a webpack plugin that would preprocess the code and then throw it back to the purs for compilation. However, it would not play nicely with tools like language server, which won’t be able to report errors until the plugin is run on the code.

I know it’s probably quite a change in a compiler, and something that I would be happy to implement but you will not be happy to maintain (I feel you :slight_smile:), do you think that it might be worth considering in a foreseeable future?

1 Like

Personal opinions, strongly worded, but non-authoritative:

Fully general compiler plugins that are capable of, for example, altering the surface syntax of PureScript, are never going to be supported. Leaving entirely aside the observation of how much of a defect magnet plugins tend to be, such things are a trade-off between how much control the programmer has and how much the ecosystem gets to know/assume about your programs, and I don’t think any of us would be happy with the idea of crippling the tooling around PureScript in that way. (It, uh, has enough problems.)

But you can do quite a lot with type classes and compile-time manipulation of strings. You can’t always get exactly the syntax you want, but you can often get close. See, for example:

(This is not necessarily an endorsement of those specific libraries for production use. All I’m trying to demonstrate is what’s possible, not what’s ready.)

Additionally, in a future version of PureScript, we may support a way for build tools to rewrite PureScript’s CoreFn IL and submit the new trees back to the compiler for the final code generation stage. This covers a number of possibilities, including ideas like static pointers and probably some of the inlining use cases you’re mentioning, as well as just optimizing away the tangles of type class instances that a type-class-heavy library would generate. Progress on that can be followed here. (Note that a major caveat to this technique will be that currently, CoreFn is untyped, and adding type information to CoreFn is probably a non-trivial hill to climb on its own.)

I’m not going to pretend that this covers 100% of the cases for which one might reach for a compiler plugin. And there are definitely areas where the language and the tooling around the language could be improved to smooth some of these paths. (Off the top of my head: make proxies/type-level values in general less verbose; improve compilation performance of projects that use type classes extra-heavily; make type-class-driven refinements to the autocomplete functionality of the IDE interface.) My advice is that proposing, discussing, and implementing those ideas narrowly is going to be substantially more productive than trying to make compiler plugins happen.

2 Likes