WoW:API loadstring: Difference between revisions

From AddOn Studio
Jump to navigation Jump to search
(And that's how you document functions =))
 
m (Move page script moved page API loadstring to API loadstring without leaving a redirect)
 
(4 intermediate revisions by 3 users not shown)
Line 1: Line 1:
{{tocright}}
{{wowlua}}
Parse a string as Lua code and return it as a reference to a function.
Parse a string as Lua code and return it as a reference to a function.
  func, errorMessage = loadstring("luaCodeBlock"[, "chunkName"]);
  func, errorMessage = loadstring("luaCodeBlock"[, "chunkName"]);


== Arguments ==
== Arguments ==
=== Parameters ===
;luaCodeBlock
:;luaCodeBlock:String - a string of Lua code. Can be very long.
:String - a string of Lua code. Can be very long.
:;chunkName:String - optionally name the code block. Will be shown as the "file name" in error messages. If not given, the file name will be "[string: ''first line of your Lua code here...'']".
;chunkName
:String - optionally name the code block. Will be shown as the "file name" in error messages. If not given, the file name will be "[string: ''first line of your Lua code here...'']".


=== Returns ===
=== Returns ===
:;func:Function reference - nil if there was a syntax error in the code block
;func
:;errorMessage:String - will contain an error message if ''func'' was nil.
:Function reference - nil if there was a syntax error in the code block
;errorMessage
:String - will contain an error message if ''func'' was nil.


== Examples ==
== Examples ==


=== Emulating [[API RunScript|RunScript]] === <div style="margin-left: 3%;">
=== Emulating RunScript() ===


  [[API assert|assert]](loadstring("DEFAULT_CHAT_FRAME:AddMessage(\"Hello, World!\")")) ();
  assert(loadstring("DEFAULT_CHAT_FRAME:AddMessage(\"Hello, World!\")")) ();


If an error occurs, the assert will trigger and automatically display the errorMessage return since assert()s second parameter is the error message to display. If it is successful, the function reference returned will also be returned out through the assert() call, and then be executed directly by the "()".
If an error occurs, the assert will trigger and automatically display the errorMessage return since assert()s second parameter is the error message to display. If it is successful, the function reference returned will also be returned out through the assert() call, and then be executed directly by the "()".




</div>
=== Catching all errors ===
=== Catching all errors === <div style="margin-left: 3%;">
  local func, errorMessage = loadstring("DEFAULT_CHAT_FRAME:AddMessage(\"Hello, World!\")");
  local func, errorMessage = loadstring("DEFAULT_CHAT_FRAME:AddMessage(\"Hello, World!\")");
  if(not func) then
  if(not func) then
   ''... do something with errorMessage and return out?''
   ''... do something with errorMessage and return out?''
  end
  end
  local success, errorMessage = [[API pcall|pcall]](func);
  local success, errorMessage = pcall(func);
  if(not success) then
  if(not success) then
   ''... do something with errorMessage and return out?''
   ''... do something with errorMessage and return out?''
Line 33: Line 35:




</div>
=== Returning values ===
=== Returning values === <div style="margin-left: 3%;">
Since the code block is actually a function, you can return values out of it just like with a function. ''(ignoring error handling for now)''
Since the code block is actually a function, you can return values out of it just like with a function. ''(ignoring error handling for now)''
   local func = assert(loadstring("return 38+4, \"Hello, World!\";"));
   local func = assert(loadstring("return 38+4, \"Hello, World!\";"));
Line 42: Line 43:




</div>
=== Protecting the global environment ===
=== Protecting the global environment === <div style="margin-left: 3%;">


Lua can manipulate the environment that a function gets to see with [[API setfenv|setfenv]](). It is however important to remember that already-existing functions that the code is allowed to call retain their original environments, so e.g. giving protected code access to the standard [[API setglobal|setglobal]]() is probably not a good idea.
Lua can manipulate the environment that a function gets to see with [[API setfenv|setfenv]](). It is however important to remember that already-existing functions that the code is allowed to call retain their original environments, so e.g. giving protected code access to the standard [[API setglobal|setglobal]]() is probably not a good idea.
Line 68: Line 68:




</div>
=== Creating "real" functions through loadstring ===
 
=== Creating "real" functions through loadstring === <div style="margin-left: 3%;">
 
  local func = assert(loadstring([[
  local func = assert(loadstring([[
   return function(a,b)
   return function(a,b)
Line 84: Line 81:


Will result in "meaning_of_life_the_universe_and_everything" containing the number 42.
Will result in "meaning_of_life_the_universe_and_everything" containing the number 42.
</div>
{{LUA}}

Latest revision as of 04:46, 15 August 2023

WoW Lua

Parse a string as Lua code and return it as a reference to a function.

func, errorMessage = loadstring("luaCodeBlock"[, "chunkName"]);

Arguments[edit]

luaCodeBlock
String - a string of Lua code. Can be very long.
chunkName
String - optionally name the code block. Will be shown as the "file name" in error messages. If not given, the file name will be "[string: first line of your Lua code here...]".

Returns[edit]

func
Function reference - nil if there was a syntax error in the code block
errorMessage
String - will contain an error message if func was nil.

Examples[edit]

Emulating RunScript()[edit]

assert(loadstring("DEFAULT_CHAT_FRAME:AddMessage(\"Hello, World!\")")) ();

If an error occurs, the assert will trigger and automatically display the errorMessage return since assert()s second parameter is the error message to display. If it is successful, the function reference returned will also be returned out through the assert() call, and then be executed directly by the "()".


Catching all errors[edit]

local func, errorMessage = loadstring("DEFAULT_CHAT_FRAME:AddMessage(\"Hello, World!\")");
if(not func) then
  ... do something with errorMessage and return out?
end
local success, errorMessage = pcall(func);
if(not success) then
  ... do something with errorMessage and return out?
end


Returning values[edit]

Since the code block is actually a function, you can return values out of it just like with a function. (ignoring error handling for now)

 local func = assert(loadstring("return 38+4, \"Hello, World!\";"));
 local sum, message = func();

You cannot pass parameters into a loadstring()ed function like you can with regular functions. But, on the other hand, you can freely modify the string itself so getting values into it is usually not a problem.


Protecting the global environment[edit]

Lua can manipulate the environment that a function gets to see with setfenv(). It is however important to remember that already-existing functions that the code is allowed to call retain their original environments, so e.g. giving protected code access to the standard setglobal() is probably not a good idea.

local func = assert(loadstring([[
  print( 
    format("format is %s", tostring(format)) 
  );
  print("setglobal is "..tostring(getglobal("setglobal")));
]]));
local smallenv = {format=format, tostring=tostring, getglobal=getglobal};
smallenv.print = function(msg) DEFAULT_CHAT_FRAME:AddMessage(msg); end

setfenv(func, smallenv);
func();

Note how we're using the "[[", "]]" quoting style here. Such strings can span multiple lines. The above could of course also be written in a single line with regular quotes; it's just an example.

The above code cannot manipulate anything in the global environment. All it has access to is what we give it. It will output something like this in the default chat frame:

format is function:00127436
setglobal is nil

If the protected code modifies its environment, e.g. to return values out, we can examine the changes via looking at "smallenv". E.g. if the protected code does greeting = "So long and thanks for the fish";, we get hold of it via accessing smallenv.greeting.


Creating "real" functions through loadstring[edit]

local func = assert(loadstring([[
  return function(a,b)
    local result = a+b;
    return result;
  end
]]));

userdefFunc = func();

meaning_of_life_the_universe_and_everything = userdefFunc(38, 4);

Will result in "meaning_of_life_the_universe_and_everything" containing the number 42.