Using a variable as arithmetic operator in Lua - lua

I want to use a variable that references an arithmetic operator within an if statement expression as shown below:
str = { '>60', '>60', '>-60', '=0' }
del = 75
function decode_prog(var1, var2)
op = string.sub(var1, 1, 1)
vb = tonumber(string.sub(var1, 2, 3))
if var2 op vb then
print("condition met")
else
print('condition not meet')
end
end
for i = 1, #str do
decode_prog(str[i], del)
end
When the above code executes, it should either print "condition met" or "condition not met" based on the result of the operation, however I am instead receiving an error.

You cannot substitute a native Lua operator with a variable that references a function, the only way to go about what you are attempted to do is to create a set of functions within an associative array and set the index as a reference to the respective operation you want to conduct.
Looking at your list, you have a greater than (>) and equal to (=). We create a table for these operations that takes two parameters as follows.
local operators = {
[">"] = function(x, y) return x > y end,
["="] = function(x, y) return x == y end,
-- Add more operations as required.
}
You can then invoke the respective function from the decode_prog function by obtaining the operation character from the string, along with the numeric value itself - this is possible because you can obtain the function from the associative array where the index is the string of the operation we want to conduct.
local result = operators[op](var2, number)
This calls upon the operators array, uses the op to determine which index we need to go to for our appropriate operation, and returns the value.
Final Code:
str = { '>60', '>60', '>-60', '=0' }
del = 75
local operators = {
[">"] = function(x, y) return x > y end,
["="] = function(x, y) return x == y end,
}
function decode_prog(var1, var2)
local op = string.sub(var1, 1, 1) -- Fetch the arithmetic operator we intend to use.
local number = tonumber(string.sub(var1, 2)) -- Strip the operator from the number string and convert the result to a numeric value.
local result = operators[op](var2, number) -- Invoke the respective function from the operators table based on what character we see at position one.
if result then
print("condition met")
else
print('condition not meet')
end
end
for i = 1, #str do
decode_prog(str[i], del)
end

I can't make much sense of your code or what you want to achieve doing that but if could simply use load.
You build your expression as a string and run it. Of course you should take care of two character operators like >= which I did not and you should validate your input.
local str={'>60','>60','>-60','=0'}
local del=75
function decode_prog(var1, var2)
local operator = var1:sub(1,1):gsub("=", "==")
local expr = string.format("return %d %s %s", var2,operator, var1:sub(2))
print(string.format("condition %smet", load(expr)() and "" or "not "))
end
for i,v in ipairs(str) do
decode_prog(v, del)
end

A very simple way would be to add a condition for each supported operator:
function decode_prog(var1, var2)
op = string.sub(var1, 1, 1)
vb = tonumber(string.sub(var1, 2)) --remove the last argument and use tonumber()
if vb == nil then return end --if the string does not contain number
if (op == ">" and var2 > vb) or (op == "=" and var2 == vb) --[[add more conditions here]] then
print("condition met")
else
print("condition not met")
end
end
I changed the vb=string.sub(var1,2,3) line too.
This form vb = tonumber(string.sub(var1, 2)) will allow use of numbers that have any number of digits and added tonumber() which will allow us to catch not-a-number errors when comparison would probably fail.
Then I added a logic to determine what the operator is and if the condition is met.
Operator limitations:
This will only work with operators that are one character and operator such as >= will not be possible unless you use a different character for it. ≥ will not play nicely, since it is multiple characters.

Related

How to make a custom ++, -=, += operator in lua?

How do I make a custom ++, -=, += operator in lua? Since it lacks increment/decrementing operators.
I'm trying to and here's my code:
local opTable = {}
debug.setmetatable(0, {
__call = function(a, op)
return opTable[op](a)
end
})
opTable["++", int + 1] -- The rest of the code works, this is the main line that's the problem.
local x = 2;
print(x++)
I also want to know how to do +=, and -=, or maybe how to do /= or *= and %=.
You can't make custom operators in Lua. It is not possible.
Your __call metamethod (if it actually works) would allow you to call x("++") (i.e. it allows you to call a number), not x++, and it would return x+1 without modifying x.
opTable["++", int + 1] makes no sense as a Lua statement. You probably wanted something like this:
opTable["++"] = function(int)
return int + 1
end
but it still won't do what you want. The syntax will still be x("++") and it will return x+1 and it won't modify x.

Lua __eq on tables with different metatables

I have found the following quote on this site http://lua-users.org/wiki/MetamethodsTutorial:
__eq is called when the == operator is used on two tables, the reference equality check failed, and both tables have the same __eq metamethod (!).
Now I tested it with Lua 5.3.5 and this is not at all what I observed:
a = {}
b = {}
m = {}
m2 = {}
setmetatable(a, m)
setmetatable(b, m2)
m.__eq = function(p1, p2) print("why"); return true end
m2.__eq = function(p1, p2) print("why2"); return true end
This is the code I tested with.
> a == b
why
true
> b == a
why2
true
It looks like it does the same thing as with the comparison operators, where it just takes the left table and uses its metamethod.
Did this change in recent Lua versions or did I make an error with my test?
Thanks for your help.
That changed in Lua 5.3. The readme says it introduced "more flexible rules for some metamethods". Compare the Lua 5.2 reference manual:
the == operation. The function getequalhandler defines how Lua chooses a metamethod for equality. A metamethod is selected only when both values being compared have the same type and the same metamethod for the selected operation, and the values are either tables or full userdata.
function getequalhandler (op1, op2)
if type(op1) ~= type(op2) or
(type(op1) ~= "table" and type(op1) ~= "userdata") then
return nil -- different values
end
local mm1 = metatable(op1).__eq
local mm2 = metatable(op2).__eq
if mm1 == mm2 then return mm1 else return nil end
end
The "eq" event is defined as follows:
function eq_event (op1, op2)
if op1 == op2 then -- primitive equal?
return true -- values are equal
end
-- try metamethod
local h = getequalhandler(op1, op2)
if h then
return not not h(op1, op2)
else
return false
end
end
Note that the result is always a boolean.
With the Lua 5.3 reference manual:
the equal (==) operation. Behavior similar to the addition operation, except that Lua will try a metamethod only when the values being compared are either both tables or both full userdata and they are not primitively equal. The result of the call is always converted to a boolean.

How would I get the index of a char in a string?

So, essentially i'm trying to create a function that solves for the value of x.
for example, x + 4 = 8
So I'm trying to make it so, it replaces x with "" and then it gets the symbol in front of it in this case, "+" and replaces it with ""
but In Order to do so, and not remove an imaginary symbol behind it, I need to make it check if the index is 1.
My Brain Hurts.
Here's what I have for the function, I deleted some of the code for getting the index, cause It didn't work.
mathMod.solveExpression = function(variable, expression)
if (string.find(expression, "=") == nil) then
-- void
else
-- continue with search but with variable
if (string.find(expression, variable) == nil) then
-- void
else
-- ooh time for some sneaky equations
local copy = expression
for i = 1, #expression do
local c = expression:sub(i,i)
if (expression == c) then
end
end
end
end
end
/ Link To My Code`https://pastebin.com/DnKPdw2q /
If your equations are all of the form var op a = b, try this code, which uses Lua pattern matching:
s=" x + 4 = 8 "
var,op,a,b = s:match("(%w+)%s*(%p)%s*(%d+)%s*=%s*(%d+)")
print(var,op,a,b)
The pattern captures the first word as the var, skips spaces, captures a punctuation char as the operation, skips spaces, captures operand a, skips the equal sign possibly surrounded by spaces, and finally captures operand b.

When sethook is set to an empty function, is it considerable performance hit?

I'm writing small profiling library for my lua code based on hooks, because I cannot use any of the existing ones (company policies).
I'm considering if it makes sense to allow always working on-demand profiling for all of my scripts just by setting variable to true, eg.
function hook(event)
if prof_enabled then
do_stuff()
end
end
--(in main context)
debug.sethook(hook, "cr")
So the question is, should I expect a significant performance hit if prof_enabled = false and hook is always set? I'm not expecting exact answer, but rather some insights (maybe, for example lua interpreter will optimize it anyway?)
I know that the best solution would be to only set the hook when it's required, but I cannot do that here.
There are ways of doing that without hook functions. One way is to replace functions of interest with a "generated" function that does profiling things (like count number of calls) and then calls the "real" function. Like this:
-- set up profiling
local profile = {}
-- stub function to profile an existing function
local function make_profile_func (fname, f)
profile [fname] = { func = f, count = 0 }
return function (...)
profile [fname].count = profile [fname].count + 1
local results = { f (...) } -- call original function
return unpack (results) -- return results
end -- function
end -- make_profile_func
function pairsByKeys (t, f)
local a = {}
-- build temporary table of the keys
for n in pairs (t) do
table.insert (a, n)
end
table.sort (a, f) -- sort using supplied function, if any
local i = 0 -- iterator variable
return function () -- iterator function
i = i + 1
return a[i], t[a[i]]
end -- iterator function
end -- pairsByKeys
-- show profile, called by alias
-- non-profiled functions
local npfunctions = {
string_format = string.format,
string_rep = string.rep,
string_gsub = string.gsub,
table_insert = table.insert,
table_sort = table.sort,
pairs = pairs,
}
function show_profile (name, line, wildcards)
print (npfunctions.string_rep ("-", 20), "Function profile - alpha order",
npfunctions.string_rep ("-", 20))
print ""
print (npfunctions.string_format ("%25s %8s", "Function", "Count"))
print ""
for k, v in pairsByKeys (profile) do
if v.count > 0 then
print (npfunctions.string_format ("%25s %8i", k, v.count))
end -- if
end -- for
print ""
local t = {}
for k, v in npfunctions.pairs (profile) do
if v.count > 0 then
npfunctions.table_insert (t, k)
end -- if used
end -- for
npfunctions.table_sort (t, function (a, b) return profile [a].count > profile [b].count end )
print (npfunctions.string_rep ("-", 20), "Function profile - count order",
npfunctions.string_rep ("-", 20))
print ""
print (npfunctions.string_format ("%25s %8s", "Function", "Count"))
print ""
for _, k in ipairs (t) do
print (npfunctions.string_format ("%25s %8i", k, profile [k].count))
end -- for
print ""
end -- show_profile
-- replace string functions by profiling stub function
for k, f in pairs (string) do
if type (f) == "function" then
string [k] = make_profile_func (k, f)
end -- if
end -- for
-- test
for i = 1, 10 do
string.gsub ("aaaa", "a", "b")
end -- for
for i = 1, 20 do
string.match ("foo", "f")
end -- for
-- display results
show_profile ()
In this particular test I called string.gsub 10 times and string.match 20 times. Now the output is:
-------------------- Function profile - alpha order --------------------
Function Count
gsub 10
match 20
-------------------- Function profile - count order --------------------
Function Count
match 20
gsub 10
You could do other things, like time functions, if you had a high-precision timer.
I adapted this from a post on the MUSHclient forum where I also got precise timings.
What make_profile_func does is keep a copy of the original function pointer in an upvalue, and return a function that adds one to a call count, calls the original function, and returns its results. The beauty of this is that you can omit the overhead by simply not replacing the functions with their generated counterparts.
In other words, omit these lines and there will be no overhead:
for k, f in pairs (string) do
if type (f) == "function" then
string [k] = make_profile_func (k, f)
end -- if
end -- for
There is a bit of fiddling around in the code to use non-profiled versions of the functions that are used in generating the profiles (otherwise you get a slightly misleading reading).

Compare values of different type in Lua 5.2

I want to overload the == (equality) operator for <number> == <table> and <table> == <number> expressions.
However, it seems to me that Lua only uses the __eq metamethod when the two sides of the equation are of the same type.
For instance, the following snippet does not work as I expected
x = {1,2}
setmetatable (x, {__eq = function (x,y) print "!" return x[y] ~= nil end})
print (x == 1)
but this one does:
x = {1,2}
setmetatable (x, {__eq = function (x,y) print "!" return x[y] ~= nil end})
print (x == {1})
Is it possible to implement == for <number> == <table> and <table> == <number> expressions?
I'm running the latest version (5.2.2).
It's not possible.
If two objects have different basic types, the equality operation results in false, without even calling the metamethod.
It is not possible to override equality for values of different types.

Resources