lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]

[Is there a comprehensive list somewhere of all the big ways to build DSLs in Lua?]

On Apr 27, 2017, at 3:00 PM, Russell Haley <> wrote:
> I was just contemplating how one would add a linq like feature to Lua
> for searching and returning result sets as tables without having to
> write iterators. This syntax would solve that problem quite nicely,
> wouldn't it? However, would that mean the need to add other functions
> like where(), join() and similar 'SQL like' concepts?

For any programming language people who aren't familiar with it, here's the outer language's syntactic view of LINQ: 

LINQ is a way of writing a kind of AST literal, parsed from a specific query sub-language.

The query sublanguage is itself interesting. At runtime, the AST can be executed directly, compiled to bytecode, or unparsed into SQL queries (for example). But what I am especially interested in for Lua are meta-mechanisms, the things that can support multiple little languages. LINQ is a good instance of something it would be nice to be able to implement, then.[1]

One solution is to create your language out of function calls, tables, operators, and values, in the way the native LPeg does. As I've complained ad tedium, there is still no good way to create new control mechanisms this way except through lambdas or Smalltalk/Ruby-style blocks; both postpone evaluation of code in the current scope. But maybe you don't need those control mechanisms very much. And even if you do need lambdas, lexical scoping always works the right way.

Deserving special mention for constructing DSLs are common syntax hacks, like chaining methods, abusing "f 'name' {}", etc.

Another is macros, sometimes just to augment the previous approach just enough. I have convinced myself that there will never be execution at compile-time in Lua (and also convinced myself that it is a good judgement for Lua). Sorta in the same category are various other meta-Luas. The cost is direct source compatibility.[2]

My favorite method (but alas the one I use least) is to parse a string at runtime and turn it into a Lua function. So taking the Wikipedia LINQ C# example, it would look something like:

results =  linq[[ 
  from c in SomeCollection
  where c.SomeProperty < 10
  select new {c.SomeProperty, c.OtherProperty} ]]

for result in ipairs(results) do

Conveniently for me, there are no unbound variables in that query. Because otherwise I'd have to write something like:

results = linq{[[
  from c in SomeCollection
  where c.SomeProperty < limit
  select new {c.SomeProperty, c.OtherProperty} ]],

Note that the stuff in linq[[ ]]'s function can't write to any variables in the outer scope.[3] It can write on objects it's passed, though.


[1]: I'd like it to be possible; that being said, I don't plan on implementing LINQ-for-Lua, unless perhaps a patient person pays me.

[2]: You could use LuaMacro 2 if you want macro-transformed source back. The laconic version of the Powell Doctrine is, "Have an exit plan." This applies to software too.

[3]: I like to use "%limit" as the syntax for variables exported from Lua. This is what Lua 4.0 did inside procedures, and who doesn't want to be reminded of the Lua before empty proxy-tables were necessary? ;-)