[PD-dev] new loader replacement progress report
Claude Heiland-Allen
claudiusmaximus at goto10.org
Sun Jul 18 09:41:29 CEST 2010
Hi everyone,
I've been working on some algorithms to eventually replace the way Pd
finds and loads and creates objects. Sorry for the length of this mail,
but you can skip some sections if you don't care about implementation
details and/or user interface details :)
Table of Contents
* Specifications
* Example Loaders
* Clearer Error Messages
* Test Inputs
* Test Outputs
Specifications
--------------
As agreed by everyone so far, the new load order will be roughly:
for path in paths do -- the core does this bit
for loader in loaders do
loader(path, libray, object)
instead of the old, problematic:
for loader in loaders do
for path in paths do -- the loader does this bit
loader(path, library, object)
I restructured the loader plugin mechanism to be (pseudocode):
typedef err libloadfun(symbol *dir, symbol *lib);
typedef err objloadfun(symbol *dir, symbol *lib, symbol *obj);
struct loader {
symbol *name;
float priority;
libloadfun *libfun;
objloadfun *objfun;
}
Example Loaders
---------------
-- binary loader is super simple
Loader.new("bin", 70,
function(dir, lib) return loadbin(dir, lib) end,
function(dir, lib, obj) return loadbin(dir, obj) end)
-- directory loader is needed if there is no main library file
-- the core code checks the results to see if it succeeded
Loader.new("dir", 10,
function(dir, lib)
if dir:sub(-1 - #lib, -1) == ("/" .. lib) then
return function() end
else
return nil, "dir doesn't match lib"
end
end,
nil -- directory loader can't load objects
)
-- the abstraction loader is quite complicated
-- if the file exists it creates a callback that
-- registers the class, with a constructor that
-- runs the abstraction itself
-- a Context here is essentially a 'canvas'
Loader.new("txt", 30,
nil, -- abstractions cannot register new classes
function(dir, lib, obj)
local src = dir .. "/" .. obj .. ".txt.lua"
local f, err = fileexists(src)
if f then
local ldir, lobj = dir, obj
return function()
register(lobj, src, function(o, arguments)
Context.push(Context.new({ ldir }))
runtxt(ldir, lobj)
Context.pop()
end, src)
end
else
return nil, err
end
end)
The current implementation is entirely in Lua, in an unpublished git
repository. I'll upload it somewhere if there is any interest.
Clearer Error Messages
----------------------
The main upshot so far is clearer error messages instead of random
possibly-working-but-perhaps-not implementation defined behaviour when
more than one library defines the same name:
OBJECT [obj4]
obj4 ... couldn't create (ambiguous)
(found in: 'lib4')
(found in: 'lib3')
(found in: 'lib1')
(found in: 'lib5')
(found in: 'lib2')
disambiguate by [import lib2/obj4]
replacing lib2 by the library you want to import from
OBJECT [obj2]
obj2 ... couldn't create (ambiguous qualified import)
(imported: 'lib2/obj2')
(imported: 'lib1/obj2')
disambiguate by removing extra qualified imports
The error messages for objects that are not found are better too:
OBJECT [obj8]
obj8 ... couldn't create (no such object)
(looked in: 'lib4')
(looked in: 'vanilla')
(looked in: 'lib3')
(looked in: 'lib1')
(looked in: 'lib5')
(looked in: 'lib2')
OBJECT [lib1/obj8]
lib1/obj8 ... couldn't create (no such object in library)
OBJECT [lib6/obj1]
lib6/obj1 ... couldn't create (no such library)
Note for that last [libc6/obj1] example: if libc6 actually did exist in
the path but was not imported, the error would currently be the same. I
want to make it so that [somelibrary/someobject] would work even when
[somelibrary] is not imported (but such "implicit imports" would be
deprecated, and warnings emitted).
Test Inputs
-----------
The test input directory structure (.bin.lua approximates .pd_linux etc,
.txt.lua approximates .pd patches/abstractions):
----8<----
.:
global prj1
./global:
lib1 lib2 lib3 lib3.bin.lua lib4 lib5.bin.lua vanilla
./global/lib1:
obj1.txt.lua obj3.txt.lua obj4.txt.lua obj5.txt.lua obj7.txt.lua
obj2.txt.lua obj4.bin.lua obj5.bin.lua obj6.bin.lua
./global/lib2:
lib2.bin.lua obj2.txt.lua obj4.bin.lua obj5.bin.lua obj6.bin.lua
obj1.txt.lua obj3.txt.lua obj4.txt.lua obj5.txt.lua obj7.txt.lua
./global/lib3:
obj1.txt.lua obj3.txt.lua obj4.txt.lua obj5.txt.lua obj7.txt.lua
obj2.txt.lua obj4.bin.lua obj5.bin.lua obj6.bin.lua
./global/lib4:
obj1.txt.lua obj3.txt.lua obj4.txt.lua obj5.txt.lua obj7.txt.lua
obj2.txt.lua obj4.bin.lua obj5.bin.lua obj6.bin.lua
./global/vanilla:
debug.bin.lua
./prj1:
prj1.txt.lua
----8<----
The test input file (prj1.txt.lua) imports stuff and creates objects:
----8<----
import({
"lib1", "lib1/obj1", "lib1/obj2",
"lib2", "lib2/obj2", "lib2/obj3",
"lib3",
"lib4",
"lib5"
})
for o = 1,8 do
object("obj" .. o)
end
for l = 1,6 do for o = 1,8 do
object("lib" .. l .. "/" .. "obj" .. o)
end end
----8<----
Test Outputs
------------
The full raw output:
http://claudiusmaximus.goto10.org/t/pd/pd-new-loader-test-4-verbose.txt
The output with the STAT lines filtered out:
http://claudiusmaximus.goto10.org/t/pd/pd-new-loader-test-4-quiet.txt
The output with the STAT lines sorted and duplicates counted:
http://claudiusmaximus.goto10.org/t/pd/pd-new-loader-test-4-statistics.txt
(The counts are low because the results are cached, this will need to be
changed for live-coding abstractions etc...)
Hopefully I'm heading in the right direction with this, if not then yell
loudly!
Thanks,
Claude
--
http://claudiusmaximus.goto10.org
More information about the Pd-dev
mailing list