[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: [ANN] LuaMacro 2.1
- From: steve donovan <steve.j.donovan@...>
- Date: Wed, 18 May 2011 19:03:36 +0200
Hi all,
This is the second beta release of LuaMacro 2, yet another Lpeg-driven
syntactical candy store for Lua. A few bugs squished (like 'elseif'
not been recognized as a keyword) and some nice generalizations: for
instance, you can define new tokens (like '@@') and use them as
macros. Operator macros can be pass-through, so that you can safely
overload standard Lua tokens like '{' and '.'.
The front-end luam also sets a custom package loader, as suggested by
Alexander. So if require 'fred' fails, the package loader will look
for fred.m.lua and preprocess and load that.
There is an interactive prompt:
$> luam -i
Lua 5.1.4 Copyright (C) 1994-2008 Lua.org, PUC-Rio
Lua Macro 2.1 Copyright (C) 2007-2011 Steve Donovan
> require 'macro.all'
> forall i in {10,20,30} do print(i) end
10
20
30
> f = \x(x+1)
> = f(10)
11
https://github.com/stevedonovan/LuaMacro
There was recent discussion around new control structures, and I still
think that a macro facility provides the best laboratory for
experimentation. For instance, a simple case statement is a one-line
macro:
def_ case(x) do def_ (of elseif _value ==) local _value = x if false
then _END_END_
function test(n)
local res
case(n)
of 10 then
res = 1
of 20 then
res = 2
else
res = 3
end
return res
end
The 'of' is simply defined as an elseif (but notice that it is defined
within the scope of the case macro, and will _not_ exist outside the
case block) The _END_END_ is a built-in macro that ensures that the
final 'end' causes another 'end' to be emitted and closing the do
block. (So we don't have to do unnatural things like 'endcase')
Here is a 'with' statement
with aLongName do
.x = 1
.y = 2
end
Note the periods; we could fool with dynamic scope at this point (and
macros can smooth over the differences here between 5.1 and 5.2) but
personally I was burnt too often by the Pascal with statement; this is
one of the few places where Visual Basic syntax is better, IHMO.
The idea is to look at the token just before each period and decide
whether we should insert a table reference before it. Basically, if
the last token is not a name or ']' then we go ahead. Everything is
put inside a do block with a local alias to the expression.
M.define('with',function(get,put)
M.set_scoped_macro('.',function()
local lt,lv = M.last_token() -- peek before the period...
if lt ~= 'iden' and lt ~= ']' then -- complete the table lookup
return '_var.'
else
return nil,true -- pass through
end
end)
local expr = get:upto 'do'
return 'do local _var = '..tostring(expr)..'; '
end)
I agree that this is a little bit hacky. But the new meaning of '.'
again does not escape the with block so it cannot do arbitrary damage
elsewhere.
It's now possible to completely re-skin Lua - an example is here:
https://github.com/stevedonovan/LuaMacro/blob/master/tests/test-cskin.lua
Basically, cskin.lua defines a simple curly-braces version of Lua with
OOP in about 140 lines.
Personally, I think it's a bit scary and overboard. But it was an
interesting technical challenge ;) As always, don't use excessive
syntactical sugar if on a kilocalorie-restricted diet. Ask your health
professional if in doubt.
steve d.