Lua Notes

Let Over Lambda
Login

Let Over Lambda

https://letoverlambda.com/ is a excellent book about Common Lisp with a focus on the capabilities of its macros. These are some Nelua adaptions of its examples.

  1. aif
  2. sleep-units
  3. unhygienic variable injection
  4. conditional code
  5. hygienize and unwanted variable capture

aif

## local function aif(test, fthen, felse)
  local it = #[test]#
  if it then ## inject_statement(fthen)
  else ## inject_statement(felse)
  end
## end
local it = 'fake'

aif!(5, print(it), print('false'))
aif!(nil, print(it), print('false'))
assert(it == 'fake')

sleep-units

--[[
(defmacro sleep-units (value unit)
  `(sleep
      (* ,value
         ,(case unit
            ((s) 1)
            ((m) 60)
            ((h) 3600)
            ((d) 86400)
            ((ms) 1/1000)
            ((us) 1/1000000)))))
]]
local Duration = @enum{ s = 1, m, h, d, ms, us }

local function sleepunits(value: number, unit: Duration <comptime>)
  ## local units = { 1, 60, 3600, 86400, 1/1000, 1/1000000 }
  print('faking sleep for: ', value * #[units[unit.value]]#)
end

sleepunits(3, Duration.h)
sleepunits(2, Duration.h)
sleepunits(3, Duration.ms)

unhygienic variable injection

## function xinjector()
  in x
## end

local x = 1
local y: []integer = {#[xinjector]#()+1, #[xinjector]#()+2}
print(x, y[0], y[1])

conditional code

##[[
local doit
if pragmas.doit then
  function doit(thing)
    inject_statement(thing)
  end
else
  function doit(thing) end
end
]]

doit!(print('lalala'))
doit!(print '?')

usage:

$ nelua pragrun.nelua
$ nelua -Pdoit pragrun.nelua
lalala
?

hygienize and unwanted variable capture

local obscure_name: integer
## local function nif(pos, zero, neg)
  local function f(test: auto)
    obscure_name = test
    if     obscure_name > 0  then ## inject_statement(pos)
    elseif obscure_name == 0 then ## inject_statement(zero)
    else                          ## inject_statement(neg)
    end
  end
  ## return f
## end

local old_obscure = &obscure_name
## nif = hygienize(nif)

local obscure_name: integer = 100
local x = 2
nif!(print '+', print '0', print '-')(x)
nif!(print '+', print '0', print '-')(-x)
print(obscure_name, $old_obscure)