Writing a DSL in Lua (2015)

  • Lua is a much cooler and more useful language than I think it, publicly, gets credit for. I know it’s widely used in many industries but so many times I’ve read an article like this and thought that it could be even more widely useful.

    I’m currently writing a just for me static site generator in Fennel and it’s sad to see just how many powerful packages are abandoned. A lot of it is because they are mostly complete and part of why I like it is lack of churn but a last update on 18 months ago is very different from 10 years.

    I want to host knitting patterns with my site generator and techniques like this make it super easy to build a little pattern dsl. It’s stuff like that which makes me wish it was more widespread.

  • This is a nice example of one way to implement DSLs in a language that doesn't support them well.

    IIUC, they're using Lua's language's function application syntax, combined with the ability to introduce a different namespace environment for function lookup, and then they're evaluating the tree of function calls at run time.

    In languages that support doing this at compile time, through compile-time evaluation or compile-time syntax transformation, you can make run time faster. For example of syntax transformation, https://www.neilvandyke.org/racket/html-template/ shows an example of expanded syntax, where it's rendered some of the angle brackets and coalesced that with (escaped) HTML CDATA.

    If you wanted to extend that, to support chunks of traditional HTML angle-bracket syntax inline with code (without using string literals), like in React, you could define a Racket reader to parse those chunks and transform them to parentheses syntax above.

  • I love Lua for being able to do things like this.

    I was building a bunch of html pages for an htmx frontend and a golang back end, and got really exhausted from using the builtin `html/template` library in golang. I kept trying to build reusable components, and it just didn’t work as I wanted it to.

    I ended up doing this exact thing as mentioned in this blog post. https://github.com/DBarney/Glua Granted this is just for me, and for prototyping. I put it on GitHub so I wouldn’t loose it.

    Writing html got so much easier this way:

        local function Component(data)
         return div{"my name is", data.name}
        end
    
        return function(params)
          html{
            head{title="this is my page"},
            body{
              h1{"This is my small page I wrote"},
              p{
                "some content",
                "more content"
              },
              div{"page has some dynamic values",params.count},
                Component{name="daniel"}
            }
          }
        end
    
    Edit: formatting

  • Lua's LPeg library would also be a great option here. A couple of years ago I taught an interpreters class together with Roberto Ierusalimschy and we used LPeg for lexing and parsing. The end result was great. Even if you're not using PEGs for your implementation I would recommend spending 30 minutes and looking at LPeg.

  • Related:

    Writing a DSL in Lua (2015) - https://news.ycombinator.com/item?id=22223542 - Feb 2020 (41 comments)

  • While I’m surprised to see they aren’t writing about https://www.inf.puc-rio.br/~roberto/lpeg/ it looks like they’ve covered LPEG in a previous post, and their chosen method this time around is neat anyway!

  • MicroLua for the RP2040 has a nice dsl for the PIO assembly with some special use of methods: https://github.com/MicroLua/MicroLua/blob/main/lib/pico/hard...

        function pio_timer(_ENV)
        public(start):
            set(y, 0)
            mov(y, ~y)
        wrap_target()
        delay:
            pull()
            mov(x, osr)
        loop:
            jmp(x_dec, loop)
            mov(isr, ~y)
            push()
            jmp(y_dec, delay)
        end

  • It never fails to strike me as odd how polarizing Lua is. Some people (like me) find it really pleasant and fluid to use. Other people get hives from things like 1-based indexing and global-by-default. The intense complaints are just so silly, especially when the “better alternative” presented is typically Python, which is one of the worst languages I’ve ever used. Lua’s syntax and semantics are so much smaller and cleaner that it’s mindblowing how simple it makes rather complex and custom abstractions. When I use Lua I feel like I’m working on another level of abstraction than in other languages, almost a lisp, but with just the right amount of convenient / quality-of-life features that it makes everything trivial. Multiple inheritance, mixins, type constructors are all trivial classes, if you want them, or parts of them, or to do your own thing entirely, or you can choose none of it at all and merely build a very primitive C-composition scripting API for your library, and yes embedding languages inside it is therefore also trivial. I’ll never understand the mindset that leads people to hating it.

    “But bro, Python has C libraries!!”

    and?

    Lua is built out of C semantics and has a beautiful C API

    if I want native libraries, I’ll just take a little time to write a trivial wrapper for precisely as much functionality as I want from the library

  • I've always wanted to recreate a Python like syntax for Lua, this might be a good guide for that.

  • trailing closure syntax looks similar but is probably even a bit nicer. I just wish js would get this feature so we could stop using jsx.