]> git.lizzy.rs Git - metalua.git/blob - src/lib/metalua/package2.lua
fixes on the compilation process separation through io.popen()
[metalua.git] / src / lib / metalua / package2.lua
1 local package = package
2
3 require 'metalua.mlc'
4
5 package.metalua_extension_prefix = 'metalua.extension.'
6
7 package.mpath = os.getenv 'LUA_MPATH' or
8    './?.mlua;/usr/local/share/lua/5.1/?.mlua;'..
9    '/usr/local/share/lua/5.1/?/init.mlua;'..
10    '/usr/local/lib/lua/5.1/?.mlua;'..
11    '/usr/local/lib/lua/5.1/?/init.mlua'
12
13
14 ----------------------------------------------------------------------
15 -- resc(k) returns "%"..k if it's a special regular expression char,
16 -- or just k if it's normal.
17 ----------------------------------------------------------------------
18 local regexp_magic = table.transpose{
19    "^", "$", "(", ")", "%", ".", "[", "]", "*", "+", "-", "?" }
20 local function resc(k)
21    return regexp_magic[k] and '%'..k or k
22 end
23
24 ----------------------------------------------------------------------
25 -- Take a Lua module name, return the open file and its name,
26 -- or <false> and an error message.
27 ----------------------------------------------------------------------
28 function package.findfile(name, path_string)
29    local config_regexp = ("([^\n])\n"):rep(5):sub(1, -2)
30    local dir_sep, path_sep, path_mark, execdir, igmark =
31       package.config:strmatch (config_regexp)
32    name = name:gsub ('%.', dir_sep)
33    local errors = { }
34    local path_pattern = string.format('[^%s]+', resc(path_sep))
35    for path in path_string:gmatch (path_pattern) do
36       --printf('path = %s, rpath_mark=%s, name=%s', path, resc(path_mark), name)
37       local filename = path:gsub (resc (path_mark), name)
38       --printf('filename = %s', filename)
39       local file = io.open (filename, 'r')
40       if file then return file, filename end
41       table.insert(errors, string.format("\tno lua file %q", filename))
42    end
43    return false, table.concat(errors, "\n")..'\n'
44 end
45
46 ----------------------------------------------------------------------
47 -- Execute a metalua module sources compilation in a separate process
48 -- Sending back the bytecode directly is difficult, as some shells
49 -- (at least MS-Windows') interpret some characters. So rather than
50 -- base64-encoding the bytecode, AST is returned from the child
51 -- process, and converted to bytecode then function in the calling
52 -- process.
53 ----------------------------------------------------------------------
54 local function spring_load(filename)
55    -- FIXME: handle compilation errors
56    local pattern = 
57       [=[lua -l metalua.compiler -l serialize -e ]=]..
58       [=["print(serialize(mlc.ast_of_luafile [[%s]]))"]=]
59    local cmd = string.format (pattern, filename)
60    --print ("running command: ``" .. cmd .. "''")
61    local fd = io.popen (cmd)
62    local ast_src = fd:read '*a'
63    fd:close()
64    local ast = lua_loadstring (ast_src) () -- much faster than loadstring()
65    return mlc.function_of_ast (ast, filename)
66 end
67
68 ----------------------------------------------------------------------
69 -- Load a metalua source file.
70 ----------------------------------------------------------------------
71 function package.metalua_loader (name)
72    local file, filename_or_msg = package.findfile (name, package.mpath)
73    if not file then return filename_or_msg end
74    if package.metalua_nopopen then
75       local luastring = file:read '*a'
76       file:close()
77       return mlc.function_of_luastring (luastring, name)
78    else
79       file:close()
80       return spring_load (filename_or_msg)
81    end
82 end
83
84 ----------------------------------------------------------------------
85 -- Placed after lua/luac loader, so precompiled files have
86 -- higher precedence.
87 ----------------------------------------------------------------------
88 table.insert(package.loaders, package.metalua_loader)
89
90 ----------------------------------------------------------------------
91 -- Load an extension.
92 ----------------------------------------------------------------------
93 function extension (name, noruntime)
94    local complete_name = package.metalua_extension_prefix..name
95    local x = require (complete_name)
96    if x==true then return
97    elseif type(x) ~= 'table' then
98       error ("extension returned %s instead of an AST", type(x))
99    else
100       return x
101    end
102 end
103
104 return package