These forums are in read-only mode. Please see this news post for more information.

New forums can be found here


Go Back   WowAce Forums > General > Lua Code Discussion
Lua Code Discussion You scared? Terrified. Mortified. Petrified. Stupefied... by [coding].

Reply
 
Thread Tools
Old 08-19-2016   #1
TimothyLuke
Member
 
Join Date: Oct 2008
Posts: 19
Default Using loadscript to load a table

Hi All,

I'm trying to load a table from a string and rather than trying to write a string manipulation function to pull the table apart I was looking at using loadscript.

Code:
local testtable = {}
local importStr = [[testtable["Test"] = {
["a"] = 1,
["b"] = 2,
}]]

assert(loadstring(importStr))
If i evaluate testtable at this point its empty. Is there something I need to tell loadstring to allow it to access the local testtable?

I also tried

Code:
local loadfunc = loadstring(importStr)
loadfunc()
TimothyLuke is offline   Reply With Quote
Old 08-19-2016   #2
Seerah
Legendary Member
 
Seerah's Avatar
 
Join Date: May 2006
Posts: 6,724
Default Re: Using loadscript to load a table

Your table variable is local and only in the scope of the loadstring function.
__________________
Seerah is offline   Reply With Quote
Old 08-19-2016   #3
Farmbuyer
Amazing Member
 
Farmbuyer's Avatar
 
Join Date: Feb 2005
Posts: 1,183
Default Re: Using loadscript to load a table

Keep in mind that:
  1. the code given to loadstring is the guts of a function
  2. the eventual function runs in the global namespace by default, unless you change its environment

So, try something like this for a starting point:
Code:
local primary_definition = [===[
    print "compiled code running!"
    return {
        ["a"] = 1,
        ["b"] = 2,
        ["c"] = special_data,   -- global variable as far as it knows
    }
]===]
Passing arguments into your compiled function is a bit tricky. You can put everything in globals (sloppy but easy), or you can assemble the code string around them (precise but can be hard to read/maintain), or you can replace the namespace for that function. For the last method, you stuff all the things you want that function to see into a specific table. Advanced mode: chain that table into the actual global namespace, so that you don't break normal name lookup.

Code:
local fake_globals = setmetatable({
    special_data = 42,
    ....other_stuff_as_appropriate.... = whatever,
}, {__index = _G})
If you don't know all the values you need at the time you create that table, or if you need to change them during runtime, it's just a regular table. This is how you can give your compiled function access to other local names, which loadstring() doesn't see:
Code:
local actual_local_variable = 12345
fake_globals.special_data = actual_local_variable
Building the function looks like this:
Code:
local func, err = loadstring (primary_definition, "Your Addon's Name")
if func then
    -- Make the compiled function see this table as its "globals"
    setfenv (func, fake_globals)
    -- Running the code in primary_definition returns a newly created table
    -- with a/b/c indices
    local testtable = assert(func())
else
    print ("shit's on fire, yo")
    print (err)
end
The argument for your addon's name is just for something to show in stack dumps if loadstring() can't compile your code.
__________________
In wizardry, one must often be willing to consider serendipitous events as unqualified successes. -Vaarsuvius

Last edited by Farmbuyer; 08-19-2016 at 01:18 PM. Reason: expand reasons for replacing environment
Farmbuyer is offline   Reply With Quote
Old 08-19-2016   #4
Farmbuyer
Amazing Member
 
Farmbuyer's Avatar
 
Join Date: Feb 2005
Posts: 1,183
Default Re: Using loadscript to load a table

I'll add: if whatever code you're compiling might itself throw errors, you can make your calling code more robust by replacing "assert(func())" with
Code:
    -- the function inside primary_definition can return up to 3 values
    -- before we have to either add more holders, or redo this in a
    -- variadic helper function
    local okay, ret1, ret2, ret3 = pcall(func)
    if okay then
        -- ret1 is the table we created
        testtable = ret1
        -- ret2 and ret3 are reserved for future work when this addon is
        -- extended to replace Facebook in-game
    else
        -- ret1 is an error message
        print ("shit continues to be on fire", ret1)
    end
__________________
In wizardry, one must often be willing to consider serendipitous events as unqualified successes. -Vaarsuvius
Farmbuyer is offline   Reply With Quote
Old 08-19-2016   #5
TimothyLuke
Member
 
Join Date: Oct 2008
Posts: 19
Default Re: Using loadscript to load a table

Thanks Farmbuyer.

My final code ended up looking like

Code:
function GSSE:importSequence()
  local functiondefinition =  importStr .. [===[

  return Sequences
  ]===]
  GSPrintDebugMessage (functiondefinition, "GS-SequenceEditor")
  local fake_globals = setmetatable({
    Sequences = {},
    }, {__index = _G})
  local func, err = loadstring (functiondefinition, "GS-SequenceEditor")
  if func then
    -- Make the compiled function see this table as its "globals"
    setfenv (func, fake_globals)

    local TempSequences = assert(func())
    if not GSisEmpty(TempSequences) then
      local newkey = ""
      for k,v in pairs(TempSequences) do
        local tver = v.version
        if GSisEmpty(tver) then
          tver = 1
        end
        GSAddSequenceToCollection(k, v, tver)
        newkey = k
      end
      names = GSSE:getSequenceNames()
      listbox:SetList(names)
      listbox:SetValue(newkey)
    end
  else
    GSPrintDebugMessage (err, GNOME)
  end
TimothyLuke is offline   Reply With Quote
Reply


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT. The time now is 08:18 PM.