Hello people,
I made a patch for shakespeare-sass which makes it support splices like the other shakespeare languages. I'd like to explain why and how because it's not easy to understand from my still ugly-and-undocumented code. First, how do these splices work in shakespeare in general? Answer: Shakespeare has its own small simple parser of Haskell expressions. Then, each shakespeare language has its own parser, and these parses reuse that Haskell expression parser to parse the splices. There is additionally a simple "text with splices" module in shakespeare which allows to embed splices in general plain text, and it uses that expression parser too. Now suppose you want to have SASS with splices supported in shakespeare! Obviously there is a problem: The libsass based SASS parser that can be found in Hackage, nicely wrapped in the 'hsass' package, is already written, in the C language! You can't embed the Haskell expression parser into it. So what do you do? Well, you have 2 options: 1. Write a SASS parser in Haskell for the shakespeare package 2. Run the 'hsass' parser on SASS sources that contain splices and then process the splices The 'shakespeare-sass' and 'yesod-sass' packages do neither, they simply don't support Haskell splices at all. I chose the 2nd option. My first attempt was like this: 1. Compile SASS into CSS using the 'hsass' package 2. Treat the CSS as a Lucius source file and process splices This failed because the SASS compiler apparently doesn't like shakespeare splices! If you write "#{avatar}" in your SASS source, the compiled CSS contains just "avatar". The compiler just strips some characters for reasons unknown to me. So, what do we do? I had an idea! Before running the SASS compiler, I'll run a preprocessor that encodes those special characters in the splices using just alphanumeric ASCII characters, so that the SASS compiler doesn't touch them, and after compilcation I'll run a postprocessor that decodes the splices back to the original form! And *then* treat the result as a Lucius source. Ikomi tried this today and it seems to work! The patch that makes this possible is quite ugly and dirty, I'd like to explain because it's important for the long term, the code should probably be cleaned and made safe and elegant: - Shakespeare 2.0.13 exposes 2 internal modules sue to a GHC bug. My code uses one of these modules. A future version is likely to stop exposing them or to break its API, a quick solution is to copy functions from those modules into my code. - You may say "wait but copying is ugly", I agree but guess what, there's a lot more copying I already had to do. I needed functions from shakespreare that it doesn't export. And also shakespeare uses parsec for parsing, and parsec doesn't have the 'match' function like attoparsec does, which means I couldn't reuse the parsers as much as I wanted to, and needed to write more code and copy some from shakespeare too. - There are many ways to encode strings into clean alphanumeric representations. I didn't care much about optimization, I just picked the first simple idea I had: Hex. The splices are encoded by converting the String to ByteString to the hex representation of the bytes. I considerd base 64 too, but it has a few symbols (I didn't check if the SASS compiler touches them) so I just went for something that doesn't. Final part: What are my thoughts about making this patch sane and elegant and future proof? Well, in shakespeare all the separate language parsers reuse the internals, and the internals are a mess. The best way to add a new shakespeare language is probably to include it in the shakespeare package itself. If its maintainer likes the idea, I can write a patch, and shakespeare will start supporting SASS. Either way, since I wrote the shakespeare-sass patch, I can keep maintaining it and making sure it keeps working. I can turn it into a patch to shakespeare itself like I said, but to make such a patch really clean and elegant I'd need to modify the internal modules and it would be hard to constantly rebase it on new shakespeare versions. Due to the shakespeare internals being ugly, really the best option I see is to get the the code into shakespeare, or perhaps to clean and stabilize its internals. Maybe start by making shakespeare uses megaparsec instead of parsec, for example, and make the parsers look less horrible. Design team: Just enjoy the patch and explore :) Ikomi knows how to use it Dev team: Indeed I need to document my code, either way this email explains the idea and any further questions and stability and security concerns are very welcome :) -- fr33
pgpoIlvnSzNHX.pgp
Description: OpenPGP digital signature
_______________________________________________ Dev mailing list Dev@lists.snowdrift.coop https://lists.snowdrift.coop/mailman/listinfo/dev