Lua - Function That Creates Detours - class

I need to make several detours to various functions and doing it one by one is just not an option. I'm looking for a function that will take a table, ideally, and this table is class. Loop through it and for each key, value pair that is a function make a function pointer with a prefix before the original function name. I have tried several variations to achieve this effect, but they all yield different problems. Some simply will not make detour pointer no matter what you give to them, others make detour pointers but they don't work, and some will overflow the stack or simply not be recognized.
I want to know if there is a way, ie rawsets, metatable overrides, constant looping until they do match, etc to make it so the function can get a table (or a string that has the same name as the table, thus a loadstring method would work here too) and loop through each function and make a working detour pointer...no matter what.
I prefer using the self:prefix_orig_name(...) syntax [... can be replaced with actual args].
Here's 2 variations I have tried with example useage.
-- 1st Method
detours = detours or {}
function detour(object, class) -- Class is an extra arg that I would send if for some reason just sending an object didn't work...it was theory oh'ed
if detours[object] then -- Check if the detour already exists...might be worth remaking it especially if the function gets overridden several times in different places?
print("detour: Previous " .. object .. " detour found, using previous detour")
return
end
for name, func in pairs(class and class or loadstring("return " .. object)()) do
-- the loadstring method here is used because the argument received is a string of the same name as the table...thus loading it will yield a table
if type(func) == "function" then
local execute, error = loadstring(object .. ".custom_detour_" .. name .. " = " .. object .. "." .. name) -- This makes the actual pointer
if error then
print("detour Error: " .. " Failed to detour: " .. object .. " Error: " .. error)
end
local luanch, assert = pcall(execute)
if not luanch then
print("detour Error: " .. " Failed to detour: " .. object .. " Error: " .. assert)
end
end
end
print("Table: " .. object .. " successfully detourd")
detours[object] = true -- tells us we made a detour of this table/string
end
-- 2nd Method
function detour(object) -- Takes a table
for k, v in pairs(object) do
if type(v) == "function" and not detours[k] then
if not object.custom_detour_ then
object.custom_detour_ = clone(object) -- use a simple cloning function (shallow) to put a clone of the main table into a sub table of the main table
end
if object["custom_detour_" .. k] ~= object.custom_detour_[k] then
object["custom_detour_" .. k] = object.custom_detour_[k] -- this makes it so the self:custom_detour_orig_name(...) syntax can be used, if I am not mistaken
end
end
end
end
-- Example Usage:
MyClass = class() -- class function is relatively OOP standard
function MyClass:init()
self._something = true
end
function MyClass:change(value)
self._something = value
end
function MyClass:table_print(tbl) -- just making funcs up
for k, v in pairs(tbl) do
print(v)
end
end
my_class = MyClass:new()
-- 1st Method
detour("MyClass")
--2nd Method
detour(MyClass)
I personally prefer the 1st method or at least a string, because I can log each detour and if a problem arises later on, it makes debugging easier...but I am for whatever will work.

Simple detouring is easy to do with closures; no need for loadstring:
function detour(cls)
local detours = {}
for key, value in pairs(cls) do
if type(value) == "function" then -- note: ignores objects with __call metamethod
detours["custom_detour_"..key] = function(...)
-- Do whatever you want here
return value(...)
end
end
end
for key, value in pairs(detours) do
cls[key] = value
end
end

Related

Ada - Commando- line reader and processer

A program that loads and processes command-line arguments should be created.
Here comes a few examples on how it should look when you run it (bold text is the text that the user will type):
Terminal prompt % **./my_program**
No arguments given.
Terminal prompt % **./my_program 123**
Wrong amounts of arguments given.
Terminal prompt % **./my_program 10 XYZ 999 Greetings!**
Wrong amounts of arguments given.
Terminal prompt % **./my_program 3 HELLO**
Message: HELLOHELLOHELLO
The program "./my program" is ending.
Terminal prompt % **./my_program 0 Bye**
Message:
The program "./my program" is ending.
This is my code so far:
with Ada.Text_IO; use Ada.text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
with Ada.Command_Line; use Ada.Command_Line;
procedure my_program is
type String is array (Positive) of Character;
N : Integer;
Text : String;
begin
N := Argument_Count;
if N = 0 then
Put_Line("No arguments given.");
elsif N /= 2 then
Put_Line("Wrong number of arguments given.");
elsif N = 2 then
Put("Message: ");
for I in 1 .. N loop
Put(Text);
New_Line;
end loop;
Put("The program """);
Put(""" is ending. ");
end if;
end my_program;
My program handles the first 3 three cases but when I go ahead with the 4th and 5th (last) case I get an error code at the row Put(Text) where it says
Missing argument for parameter "Item" in call to "Put"
I don't know if I declared my string right because I don't want a string of a specific length. Can anyone come up with something that could help me solve case 4 and 5? It would be nice and highly appreciated
This seems to be a homework or exam question, so I would usually not provide a full answer. But Chris already gave that (with some defects), so here is my suggestion. Compared to Chris's solution, I try to avoid using unnecessary variables, and I favour case statements over if-then-else cascades, and I try to reduce the scope of exception handlers. I prefer to put use clauses in the subprogram so that the context-clause section contains only with clauses. I use the string-multiplying "*" operator from Ada.Strings.Fixed, but that is perhaps an unnecessary refinement.
with Ada.Command_Line;
with Ada.Strings.Fixed;
with Ada.Text_IO;
procedure My_Program
is
use Ada.Strings.Fixed;
use Ada.Text_IO;
begin
case Ada.Command_Line.Argument_Count is
when 0 =>
Put_Line ("No arguments given.");
when 2 =>
begin
Put_Line (
Natural'Value (Ada.Command_Line.Argument(1))
* Ada.Command_Line.Argument(2));
exception
when Constraint_Error =>
Put_Line ("Invalid input for argument 1.");
end;
when others =>
Put_Line ("Wrong amount of arguments given.");
end case;
Put_Line (
"The program """
& Ada.Command_Line.Command_Name
& """ is ending.");
end My_Program;
Note that my version:
Rejects negative first arguments (like "-3").
Outputs the repeated strings on a single line, as was required by the examples given.
Includes the name of the program in the final message, as was also required.
Given the clarification in comments as to the purpose of the program, to print a message n times where n is the first argument, and the message is the second argument, you need to parse the first argument as an integer. This can be done with Integer'Value.
Now, that raises the prospect of the user not running the program with an integer. So we have to handle the possible Constraint_Error exception.
with Ada.Text_IO; use Ada.text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
with Ada.Command_Line; use Ada.Command_Line;
procedure my_program is
argc : Integer;
N : Integer;
begin
argc := Argument_Count;
if argc = 0 then
Put_Line("No arguments given.");
elsif argc /= 2 then
Put_Line("Wrong number of arguments given.");
else
n := Integer'Value(Argument(1));
Put("Message: ");
for I in 1 .. N loop
Put_Line(Argument(2));
end loop;
Put("The program """);
Put(""" is ending. ");
end if;
exception
when Constraint_Error =>
Put_Line("Invalid input for argument 1.");
end my_program;
As an aside, when we've checked in our conditional if argc is zero, and that it doesn't equal two, we don't have to use elsif. The only other possibility is that it is 2.
You say
My program handles the first 3 three cases but when I go ahead with the 4th and 5th (last) case I get an error code at the row Put(Text) where it says "Missing argument for parameter "Item" in call to "Put". "
which doesn't make sense, because your program as shown doesn't compile. I guess what you mean is "when I try to add the code to handle cases 4 and 5, it doesn't compile".
The reason why it doesn’t compile is hidden in the actual error messages:
leun.adb:24:10: no candidate interpretations match the actuals:
leun.adb:24:10: missing argument for parameter "Item" in call to "put" declared at a-tiinio.ads:97, instance at a-inteio.ads:18
...
leun.adb:24:14: expected type "Standard.Integer"
leun.adb:24:14: found type "String" defined at line 7
leun.adb:24:14: ==> in call to "Put" at a-tiinio.ads:80, instance at a-inteio.
You have at line 7
type String is array (Positive) of Character;
which is both misleading and not what you meant.
It’s ’not what you meant’ because array (Positive) means an array of fixed length from 1 to Positive’Last, which will not fit into your computer’s memory. What you meant is array (Positive range <>).
Even with this correction, it's 'misleading' because although it would be textually the same as the declaration of the standard String in ARM 3.6.3(4), in Ada two different type declarations declare two different types. So, when you write Put(Text); the Put that you meant to call (the second in ARM A.10.7(16)) doesn’t match because it’s expecting a parameter of type Standard.String but Text is of type my_program.String.
Cure for this problem: don’t declare your own String type.

Call a script with definitions in a function

We have a script that defines values to names similar to #define in c. For example:
script.m:
ERR_NOERROR = 0;
ERR_FATAL = 1;
This script already exists and is used for value replacement when reading data from files.
Now we have a function (or more) that does some analysis and we would like to use the same definition in this function to avoid magic numbers. But when the script is called from the function we get an error.
Attempt to add "ERR_NOERROR" to a static workspace.
See MATLAB Programming, Restrictions on Assigning to Variables for details.
And this does not help much in the understanding of the problem.
The question is how can we make these definitions visible/usable in the functions with having to copying it every time.
Example:
function foo = bar(a)
run(script.m) %also tried running it without the run command
if a == ERR_NOERROR
foo = 5;
else
foo = 6;
end
end
edit:
There was a nested function,below in the function which I was not aware of. This explains the problem.
This kind of scoping error happens when you use nested or anonymous function within a function. The solution is well documented.
To your case, you can avoid nested function, or "Convert the script to a function and pass the variable using arguments", as the documentation suggests.
EDIT: I should have made it clear that the error occurs even if the script is not called within the nested function. Similar scenario is that, in debug mode (by setting up a break point), it will be an error if one tries to create a temporal variable to test something.
This is not a direct answer, rather a recommendation to switch to another method, which will not be mixing scope and workspace.
Instead of defining your constant in a script, you could make a class containing only constant properties. ex: code for error_codes.m:
classdef error_codes
% ---------------------------------------------------------------------
% Constant error code definition
% ---------------------------------------------------------------------
properties (Constant = true)
noerror = 0 ;
fatal = 1 ;
errorlvl2 = 2 ;
errorlvl3 = 3 ;
warning = -1 ;
% etc ...
end
end
I use this style for many different type of constants. For tidiness, I groups them all in a Matlab package directory (The directories which starts with a + character.
The added benefit of using constant class properties is the safety that the values cannot be changed in the middle of the code (your variables defined in a script could easily be overwritten by a careless user).
So assuming my file error_codes.m is placed in a folder:
\...somepath...\+Constants\error_codes.m
and of course the folder +Constants is on the MATLAB path, then to use it as in your example, instead of calling the script, just initialise an instance of the class, then use the constant values when you need them:
function foo = bar(a)
ERR = Constants.error_codes ;
if a == ERR.noerror
foo = 5;
else
foo = 6;
end
or it can works in switch statement too:
switch a
case ERR.noerror
foo = 5 ;
case ERR.warning
foo = 42 ;
case ERR.fatal
foo = [] ;
end

Workaround equivalent of "inputname" to return structure name?

I know that, inside a MATLAB function, inputname(k) will return the k-th argument iff the argument is a variable name. Is there any way to write some parsing code that can retrieve the full input argument when that argument is a structure, e.g. foo.bar ? The reason I want to be able to do this is that I'm writing some tools for generic use where the input could be either a named variable or a named structure element.
My primary intent is to be able to store and return the input argment(s) as part of a structure or other variable that the function returns. This is a 'chain of custody' feature which makes it easier for me or others to verify the source data sets used to generate the output data sets.
I don't want the user to have to self-parse externally, or to have to deal with some kludge like
function doit(name,fieldname)
if(exist('fieldname','var'))
name = name.(fieldname);
myinput = [inputname(1),inputname(2)];
else
myinput = inputname(1);
end
% do the function stuff
(I call this a kludge because it both requires the user to enter strange arguments and because it fouls up the argument sequence for functions with multiple inputs)
There is no support from the language to get the input names when passing structs. The reason is probably x.a is internally a call to subsref which returns a new variable, all context is lost. The only possibility you have is using the debug tools and parse the code. There is no other option.
function x=f(varargin)
[ST, I] = dbstack('-completenames', 1);
if numel(ST)>0
fid=fopen(ST(1).file,'r');
for ix=2:ST(1).line;fgetl(fid);end
codeline=fgetl(fid);
fclose(fid);
fprintf('function was called with line %s\n',codeline);
else
fprintf('function was called from base workspace\n');
end
end
From there you may try to parse the code line to get the individual argument names.
Far uglier than Daniel's approach, and probably will crash on the wrong OS, but here's a hack that works to retrieve the first argument; easily adjusted to retrieve all arguments.
[~,myname] = system('whoami');
myname = strtrim(myname(4:end)); % removes domain tag in my Windows envir
% sorry about " \' " fouling up SO's color parsing
myloc = ['C:\Users\' , myname , '\AppData\Roaming\MathWorks\MATLAB\R2015a\History.xml'] ;
f = fopen(myloc,'r');
foo = fscanf(f,'%s');
fclose(f);
pfoo = findpat(foo,'myFunctionName');
% just look for the last instance
namstart = find(foo(pfoo(end):(pfoo(end)+30)) =='(',1) +pfoo(end);
% catch either ')' or ','
namend(1) = find(foo((namstart):end)== ')',1) -2 +namstart;
if numel(find(foo((namstart):end)== ',',1)),
namend(2) = find(foo((namstart):end)== ',',1) -2 +namstart;
end
thearg = foo(namstart:(min(namend)) );

Preventing Function Overriding in Lua Table

In my program when two functions with the same name are defined for the same table, I want my program to give an error. What's happening is that it's simply just calling the last function and executing it.
Here's a sample code
Class{'Cat'}
function Cat:meow( )
print("Meow!")
end
function Cat:meow()
print("Mmm")
end
kitty = Cat:create()
kitty:meow()
The result of the execution is only: "Mmm"
Instead I want something like an error message to be given.
Unfortunately, __newindex does not intercept assignments to fields which already exist. So the only way to do this is to keep Cat empty and store all its contents in a proxy table.
I don't know the nature of your OOP library, so you'll have to incorporate this example on your own:
local Cat_mt = {}
-- Hide the proxy table in closures.
do
local proxy = {}
function Cat_mt:__index(key)
return proxy[key]
end
function Cat_mt:__newindex(key, value)
if proxy[key] ~= nil then
error("Don't change that!")
end
proxy[key] = value
end
end
Cat = setmetatable({}, Cat_mt)

Lua - How to pass object's function as parameter to another function

local a = {}
function a:test1(value)
print(value)
end
local b = {}
function b:test2(v1, v2)
v2(100);
end
b:test2(_, a.test1)
Doesn't work. Value is nil. I could find a solution doing an encapsulation in an anonymous function
b:test2(variable, function(value) a:test1(value) end)
But I find it pretty bad mkay
What is the correct syntax ?
anotherObject:aFunction(variable, object.doStuff) is the correct syntax.
Using a colon : with a function is just syntactic sugar for a call or declaration with an implicit self parameter as the first argument. If you would like to follow the pattern you've shown in your example in a cleaner way, you could use a helper function.
local function bind(t, k)
return function(...) return t[k](t, ...) end
end
You then apply it like so.
anotherObject:aFunction(variable, bind(object, 'doStuff'))
Edit: I believe the solution to your problem will require binding at some level, without resorting to modifying the Lua interpreter or using a code translation step.
This is fundamentally because functions in Lua do not carry any information about their origin. I.e., tables do not inherently own the functions that they store.
For example, the following is perfectly legitimate Lua code.
function Circle:area() -- function Circle.area(self)
-- ...
end
-- Evaluate the function in the "area" slot with Square as the self parameter.
Circle.area(Square)
Of course, you could try a paradigm shift, but it may be too late for that if you're building an entire application based on the idea of functions being tied to the table that they have been indexed from, as you said.
Therefore, I propose the following crazy solution.
local mt = {}
function mt:__index(k)
local v = self._slots[k]
if v == nil then
-- Ascend the inheritance tree.
-- This has to be done with rawget all the way up,
-- otherwise inherited functions would be repeatedly bound.
local p = self
repeat
p = rawget(p, '_parent')
if not p then break end
v = p._slots[k]
until v
end
if type(v) == 'function' then
-- Return a self-bound version of the function.
return function(...) return v(self, ...) end
end
return v
end
function mt:__newindex(k, v)
self._slots[k] = v
end
--- Demo & Tests ---
local function Object(parent)
local o = setmetatable({_slots = {}}, mt)
if parent then rawset(o, '_parent', parent) end
return o
end
local o1 = Object()
local o2 = Object(o1)
assert(o1.abc == nil, 'o1.abc should be nil')
o1.abc = 3
assert(o1.abc == 3, 'o1.abc should be 3')
assert(o2.abc == 3, 'o2.abc should be 3, inherited from o1')
o2.abc = 7
assert(o2.abc == 7, 'o2.abc should be 7, overriding o1')
assert(o1.abc == 3, 'o1.abc should be 3, unaffected by o2 setter')
function o1:test(bar)
return self.abc + bar
end
assert(type(o1.test) == 'function', 'o1.test should be a function')
assert(type(o2.test) == 'function', 'o2.test should be a function, inherited from o1')
assert(o1.test(5) == 8, 'o1.test(5) should return 3 + 5 = 8')
assert(o2.test(11) == 18, 'o2.test(11) should return 7 + 11 = 18')
function o2:test2(fn)
return self.abc + fn(7)
end
assert(o2.test2(o1.test) == 17, 'o2.test2(o1.test) should return 7 + (3 + 7) = 17')
o2.test3 = o1._slots.test -- proper function copying
assert(o2.test3(11) == 18, 'o2.test3(5) should return 7 + 11 = 18')
o2.abc = nil
assert(o2.abc == 3, 'o2.abc should be 3 again, inherited from o1 after clearing')
o2.abc = false
assert(o2.abc == false, 'o2.abc should be false, __index needs to differentiate between nil and false')
This metatable will provide you with what you want, with inherited and bound functions to boot. You will just need to make sure that all of the tables that you want to follow this pattern also follow the method of object creation shown in the example code.
To explain, each table made in this way has any new assignment redirected into the _slots sub-table and any new retrieval checked up the _parent inheritance tree. If the type of the value is a function, then it returns a new closure with the original self that started the check bound to the function found.
Obviously, calling a function from one of these objects with the : colon syntax is going to be a silly idea, since it would evaluate to o.fn(o, o), and that is probably not what you want. Another caveat is that copying functions onto these objects, from these objects, will not work as expected. o1.newfn = o2.fn will put an o2 bound function into o1, which in turn will be re-bound to o1. The end result would be something like o2.fn(o2, o1). You will have to copy functions from the _slots table.
In conclusion: Even though this works, I would not personally recommend it in the long run, since it may be confusing to anyone used to how Lua works with tables, indexing, and functions, and there will be overhead. You might be able to do away with some it via memoizing the closures, but I'll leave that decision up to you. Good luck!
Object method declared with : needs object instance as the first parameter. It gets added automatically if you call it with :, but as you passed just a function pointer, you need to pass this as well. This means whenever you pass a function in some object somewhere, you also have to pass object instance. This works:
local a = {}
function a:test1(value)
print(value)
end
local b = {}
function b:test2(obj, v2)
v2(obj, 100); -- object instance is always the first param of a ":"-style func
end
b:test2(a, a.test1) -- passing object instance and a function
Building on #ryan-stein's neat bind() solution, in a module I've found this to be slightly more concise:
local m = {}
m.__index = m
m.word = 'bar'
function m:bind(fn)
return function(...) return self[fn](self, ...) end
end
function m:foo(fn)
print("Foo " .. self.word)
end
function m:start()
hs.timer.new(42, self:bind('foo'))
end
your code will be work. the reason Ryan has said.
I doubt that in the function anotherObject:aFunction(), you were using a wrong way to call the object.stuff.The correct way as this:
local a = {}
function a:test1()
print(1)
end
local b = {}
function b:test2(v1, v2)
v2();
end
b:test2(_, a.test1)