lua-users home
lua-l archive

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


On 21/12/2012, at 11:24 AM, Finn Wilcox <finnw@firecloudsw.co.uk> wrote:

> On 20/12/2012 19:59, Geoff Leyland wrote:
>> 
>> Attached.  Note where "add" is required in expression.lua, after expression:new, but before the use of add.  It's not quite like this in the actual code, but this kind of problem does turn up.
>> 
> I like this solution better.  I'll update my stackoverflow answer.

Ultimately it didn't work for me.  Or at least I couldn't get it to work.  Or at least it got tricky enough that I tried something else.

Turns out that the example I gave didn't actually test that the "add" operator got an __add metamethod in time - for that I need to test (R.a + R.b) + (R.b + R.c).  All R.a + R.b proved was that a "ref" operator had an __add, and ref wasn't in the require loop.


On 21/12/2012, at 11:11 AM, Kevin Martin <kev82@khn.org.uk> wrote:

> Have you considered using a lazy require, something like:

Well, it did turn out to be something like that in the end, only a bit more tailored to the case in hand.  It's the last few lines of expression.lua.  Same kind of thing that Steve and Finn suggested.

I still feel like there's a simpler solution somewhere.


----- expression.lua

local expression = {}
expression.__index = expression
local ops

function expression:new_op(o)
  o = o or {}
  o.__index = o
  for k, v in pairs(ops) do o[k] = v end
  return setmetatable(o, self)
end

function expression:new(o)
  return setmetatable(o or {}, self)
end

function expression.eval(exp, vars)
  local mt = getmetatable(exp)
  local f = mt and mt.__eval
  return (f and f(exp, vars)) or exp
end

local op_mods = setmetatable({}, { __index = function(t, k) t[k] = require(k) return t[k] end })
ops = { __add = function (a, b) return op_mods.add:new{a, b} end }

return expression

----- ref.lua

local ref = require("expression"):new_op()

function ref:__eval(vars)
  return vars[self[1]] or self
end

function ref:__tostring()
  return self[1]
end

return ref

----- add.lua

local expression = require("expression")
local add = expression:new_op(add)

function add:__eval(vars)
  local a = expression.eval(self[1], vars)
  local b = expression.eval(self[2], vars)
  if a == self[1] and b == self[2] then return self end
  return a + b
end

function add:__tostring()
  return tostring(self[1]) .. " + " .. tostring(self[2])
end

return add

----- main.lua

local expression = require("expression")
local ref = require("ref")

local R = setmetatable({}, { __index = function(t, k) return ref:new{k} end })

print(expression.eval((R.a + R.b) + (R.c + R.d), { b = 2 }))