]> git.lizzy.rs Git - metalua.git/blob - metalua/loader.lua
Merge branch 'master' of ssh://git.eclipse.org/gitroot/koneki/org.eclipse.koneki...
[metalua.git] / metalua / loader.lua
1 --------------------------------------------------------------------------------
2 -- Copyright (c) 2006-2013 Fabien Fleutot and others.
3 --
4 -- All rights reserved.
5 --
6 -- This program and the accompanying materials are made available
7 -- under the terms of the Eclipse Public License v1.0 which
8 -- accompanies this distribution, and is available at
9 -- http://www.eclipse.org/legal/epl-v10.html
10 --
11 -- This program and the accompanying materials are also made available
12 -- under the terms of the MIT public license which accompanies this
13 -- distribution, and is available at http://www.lua.org/license.html
14 --
15 -- Contributors:
16 --     Fabien Fleutot - API and implementation
17 --
18 --------------------------------------------------------------------------------
19
20 local M = require "package" -- extend Lua's basic "package" module
21
22 M.metalua_extension_prefix = 'metalua.extension.'
23
24 -- Initialize package.mpath from package.path
25 M.mpath = M.mpath or os.getenv 'LUA_MPATH' or
26     (M.path..";") :gsub("%.(lua[:;])", ".m%1") :sub(1, -2)
27
28 M.mcache = M.mcache or os.getenv 'LUA_MCACHE'
29
30 ----------------------------------------------------------------------
31 -- resc(k) returns "%"..k if it's a special regular expression char,
32 -- or just k if it's normal.
33 ----------------------------------------------------------------------
34 local regexp_magic = { }
35 for k in ("^$()%.[]*+-?") :gmatch "." do regexp_magic[k]="%"..k end
36
37 local function resc(k) return regexp_magic[k] or k end
38
39 ----------------------------------------------------------------------
40 -- Take a Lua module name, return the open file and its name,
41 -- or <false> and an error message.
42 ----------------------------------------------------------------------
43 function M.findfile(name, path_string)
44    local config_regexp = ("([^\n])\n"):rep(5):sub(1, -2)
45    local dir_sep, path_sep, path_mark, execdir, igmark =
46       M.config :match (config_regexp)
47    name = name:gsub ('%.', dir_sep)
48    local errors = { }
49    local path_pattern = string.format('[^%s]+', resc(path_sep))
50    for path in path_string:gmatch (path_pattern) do
51       --printf('path = %s, rpath_mark=%s, name=%s', path, resc(path_mark), name)
52       local filename = path:gsub (resc (path_mark), name)
53       --printf('filename = %s', filename)
54       local file = io.open (filename, 'r')
55       if file then return file, filename end
56       table.insert(errors, string.format("\tno lua file %q", filename))
57    end
58    return false, '\n'..table.concat(errors, "\n")..'\n'
59 end
60
61 ----------------------------------------------------------------------
62 -- Before compiling a metalua source module, try to find and load
63 -- a more recent bytecode dump. Requires lfs
64 ----------------------------------------------------------------------
65 local function metalua_cache_loader(name, src_filename, src)
66     local mlc          = require 'metalua.compiler'.new()
67     local lfs          = require 'lfs'
68     local dir_sep      = M.config:sub(1,1)
69     local dst_filename = M.mcache :gsub ('%?', (name:gsub('%.', dir_sep)))
70     local src_a        = lfs.attributes(src_filename)
71     local src_date     = src_a and src_a.modification or 0
72     local dst_a        = lfs.attributes(dst_filename)
73     local dst_date     = dst_a and dst_a.modification or 0
74     local delta        = dst_date - src_date
75     local bytecode, file, msg
76     if delta <= 0 then
77        print "NEED TO RECOMPILE"
78        bytecode = mlc :src_to_bytecode (src, name)
79        for x in dst_filename :gmatch('()'..dir_sep) do
80           lfs.mkdir(dst_filename:sub(1,x))
81        end
82        file, msg = io.open(dst_filename, 'wb')
83        if not file then error(msg) end
84        file :write (bytecode)
85        file :close()
86     else
87        file, msg = io.open(dst_filename, 'rb')
88        if not file then error(msg) end
89        bytecode = file :read '*a'
90        file :close()
91     end
92     return mlc :bytecode_to_function (bytecode)
93 end
94
95 ----------------------------------------------------------------------
96 -- Load a metalua source file.
97 ----------------------------------------------------------------------
98 function M.metalua_loader (name)
99    local file, filename_or_msg = M.findfile (name, M.mpath)
100    if not file then return filename_or_msg end
101    local luastring = file:read '*a'
102    file:close()
103    if M.mcache and pcall(require, 'lfs') then
104       return metalua_cache_loader(name, filename_or_msg, luastring)
105    else return require 'metalua.compiler'.new() :src_to_function (luastring, name) end
106 end
107
108
109 ----------------------------------------------------------------------
110 -- Placed after lua/luac loader, so precompiled files have
111 -- higher precedence.
112 ----------------------------------------------------------------------
113 table.insert(M.loaders, M.metalua_loader)
114
115 ----------------------------------------------------------------------
116 -- Load an extension.
117 ----------------------------------------------------------------------
118 function extension (name, mlp)
119     local complete_name = M.metalua_extension_prefix..name
120     local extend_func = require (complete_name)
121     if not mlp.extensions[complete_name] then
122         local ast =extend_func(mlp)
123         mlp.extensions[complete_name] =extend_func
124         return ast
125      end
126 end
127
128 return M