cannot load() returned values from string

32 Views Asked by At

I have this assignment from the official book about lua: Exercise 16.1: Frequently, it is useful to add some prefix to a chunk of code when loading it. (We saw an example previously in this chapter, where we prefixed a return to an expression being loaded.) Write a function loadwithprefix that works like load, except that it adds its extra first argument (a string) as a prefix to the chunk being loaded. Like the original load, loadwithprefix should accept chunks represented both as strings and as reader functions. Even in the case that the original chunk is a string, loadwithprefix should not actually concatenate the prefix with the chunk. Instead, it should call load with a proper reader function that first returns the prefix and then returns the original chunk.

function loadwithprefix(prefix, chunk)

local prefixflg = true
return function(...)
    local x = select(1, ...)
    local env = { x = x, __index = { _G = _G } }

    if not prfxflg then
        prfxflg = true
        return load(prefix, nil, nil, env)
    else
        return load(' return ' .. code(), nil, nil, env)
    end
end
end

local line = io .read()
local f = loadwithprefix('local x = ...; return x ', function(...) return line end)

for i = 1, 10 do
   print(string.rep('*', f(i)()))
end

I get : bad argument #2 to 'rep' (number expected, got nil) meaning i cannot evaluate the local x = ...; return x to actually return 1 from the for-loop statement. Any suggestion?

1

There are 1 best solutions below

1
Luatic On BEST ANSWER

Your loadwithprefix implementation is incorrect:

You return a function. This is not what you should be doing. You should be calling load with a function, not returning a function which calls load.

That function also doesn't make much sense: The first time it is called, it loads just the prefix, and returns the resulting function. The second time, it returns the first value returned by chunk - not a function, if chunk is a proper "reader". It also fails to account for chunk being a string.

Your testing code also has a minor flaw: f(i)() should be just f(i) if loadwithprefix was implemented correctly. (I also can't make much sense of the prefix. Do you want your suffixes to be something like + 42?)

Here's how I would implement loadwithprefix:

local function loadwithprefix(prefix, chunk, ...)
    local loaded_prefix = false
    return load(function()
        -- first read the prefix
        if not loaded_prefix then
            loaded_prefix = true
            return prefix
        end
        if type(chunk) == "string" then
            local str = chunk -- remember the string
            chunk = function() end -- return nothing the next time
            return str
        end
        return chunk() -- delegate to the original reader
    end, ...)
end

The ... is to pass mode and env arguments (and whatever else might be added in the future) through.