net.sandius.rembulan.lib.ModuleLib Maven / Gradle / Ivy
/*
* Copyright 2016 Miroslav Janíček
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* --
* Portions of this file are licensed under the Lua license. For Lua
* licensing details, please visit
*
* http://www.lua.org/license.html
*
* Copyright (C) 1994-2016 Lua.org, PUC-Rio.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package net.sandius.rembulan.lib;
import net.sandius.rembulan.StateContext;
import net.sandius.rembulan.Table;
import net.sandius.rembulan.TableFactory;
import net.sandius.rembulan.runtime.LuaFunction;
/**
* The package library provides basic facilities for loading modules in Lua. It exports
* one function directly in the global environment: {@link #_require() {@code require}}.
* Everything else is exported in a {@code table} package.
*/
public abstract class ModuleLib extends Lib {
@Override
public String name() {
return "package";
}
@Override
public Table toTable(TableFactory tableFactory) {
Table t = tableFactory.newTable();
t.rawset("config", _config());
t.rawset("cpath", _cpath());
t.rawset("loaded", _loaded());
t.rawset("loadlib", _loadlib());
t.rawset("path", _path());
t.rawset("preload", _preload());
t.rawset("searchers", _searchers());
t.rawset("searchpath", _searchpath());
return t;
}
@Override
public void preInstall(StateContext state, Table env) {
env.rawset("require", _require());
}
public abstract void install(Lib lib);
/**
* {@code require (modname)}
*
* Loads the given module. The function starts by looking into
* the {@link #_loaded() {@code package.loaded}} table to determine
* whether {@code modname} is already loaded. If it is, then {@code require} returns
* the value stored at {@code package.loaded[modname]}. Otherwise, it tries to find
* a loader for the module.
*
* To find a loader, {@code require} is guided by the {@code package.searchers} sequence.
* By changing this sequence, we can change how {@code require} looks for a module.
* The following explanation is based on the default configuration
* for {@code package.searchers}.
*
* First {@code require} queries {@code package.preload[modname]}. If it has a value,
* this value (which must be a function) is the loader. Otherwise {@code require}
* searches for a Lua loader using the path stored in {@code package.path}. If that also fails,
* it searches for a C loader using the path stored in {@code package.cpath}.
* If that also fails, it tries an all-in-one loader
* (see {@link #_searchers() {@code package.searchers}}).
*
* Once a loader is found, {@code require} calls the loader with two arguments:
* {@code modname} and an extra value dependent on how it got the loader. (If the loader came
* from a file, this extra value is the file name.) If the loader returns any non-nil value,
* {@code require} assigns the returned value to {@code package.loaded[modname]}.
* If the loader does not return a non-nil value and has not assigned any value
* to {@code package.loaded[modname]}, then {@code require} assigns true to this entry.
* In any case, require returns the final value of {@code package.loaded[modname]}.
*
* If there is any error loading or running the module, or if it cannot find any loader
* for the module, then {@code require} raises an error.
*
* @return the {@code require} function
*/
public abstract LuaFunction _require();
/**
* {@code package.config}
*
* A string describing some compile-time configurations for packages. This string is
* a sequence of lines:
*
*
* - The first line is the directory separator string. Default is '{@code \}' for Windows
* and '{@code /}' for all other systems.
* - The second line is the character that separates templates in a path.
* Default is '{@code ;}'.
* - The third line is the string that marks the substitution points in a template.
* Default is '{@code ?}'.
* - The fourth line is a string that, in a path in Windows, is replaced by
* the executable's directory. Default is '{@code !}'.
* - The fifth line is a mark to ignore all text after it when building
* the {@code luaopen_} function name. Default is '{@code -}'.
*
*
* @return the {@code package.config} string
*/
public abstract String _config();
/**
* {@code package.cpath}
*
* The path used by require to search for a C loader.
*
* Lua initializes the C path {@code package.cpath} in the same way it initializes
* the Lua path {@link #_path() {@code package.path}}, using the environment variable
* {@code LUA_CPATH_5_3} or the environment variable {@code LUA_CPATH} or a default path
* defined in {@code luaconf.h}.
*
* @return the {@code package.cpath} string
*/
public abstract String _cpath();
/**
* {@code package.loaded}
*
* A table used by {@link #_require() {@code require}} to control which modules
* are already loaded. When you require a module {@code modname}
* and {@code package.loaded[modname]} is not false, require simply returns the value
* stored there.
*
* This variable is only a reference to the real table; assignments to this variable do not
* change the table used by {@link #_require() {@code require}}.
*
* @return the {@code package.loaded} table
*/
public abstract Table _loaded();
/**
* {@code package.loadlib (libname, funcname)}
*
* Dynamically links the host program with the C library {@code libname}.
*
* If funcname is "{@code *}", then it only links with the library, making the symbols
* exported by the library available to other dynamically linked libraries. Otherwise,
* it looks for a function {@code funcname} inside the library and returns this function as
* a C function. So, {@code funcname} must follow the {@code lua_CFunction prototype}
* (see {@code lua_CFunction}).
*
* This is a low-level function. It completely bypasses the package and module system.
* Unlike {@link #_require() {@code require}}, it does not perform any path searching
* and does not automatically adds extensions. {@code libname} must be the complete file name
* of the C library, including if necessary a path and an extension. {@code funcname} must
* be the exact name exported by the C library (which may depend on the C compiler and linker
* used).
*
* This function is not supported by Standard C. As such, it is only available on some
* platforms (Windows, Linux, Mac OS X, Solaris, BSD, plus other Unix systems that support
* the {@code dlfcn} standard).
*
* @return the {@code package.loadlib} function
*/
public abstract LuaFunction _loadlib();
/**
* {@code package.path}
*
* The path used by {@link #_require() {@code require}} to search for a Lua loader.
*
* At start-up, Lua initializes this variable with the value of the environment variable
* {@code LUA_PATH_5_3} or the environment variable {@code LUA_PATH} or with a default path
* defined in {@code luaconf.h}, if those environment variables are not defined.
* Any "{@code ;;}" in the value of the environment variable is replaced by the default
* path.
*
* @return the {@code package.path} string
*/
public abstract String _path();
/**
* {@code package.preload}
*
* A table to store loaders for specific modules (see
* {@link #_require() {@code require}}).
*
* This variable is only a reference to the real table; assignments to this variable
* do not change the table used by {@link #_require() {@code require}}.
*
* @return the {@code package.preload} table
*/
public abstract Table _preload();
/**
* {@code package.searchers}
*
* A table used by {@link #_require() {@code require}} to control how to load
* modules.
*
* Each entry in this table is a searcher function. When looking for a module,
* {@code require} calls each of these searchers in ascending order, with the module name
* (the argument given to {@code require}) as its sole parameter. The function can return
* another function (the module loader) plus an extra value that will be passed to that loader,
* or a string explaining why it did not find that module (or nil if it has nothing
* to say).
*
* Lua initializes this table with four searcher functions.
*
* The first searcher simply looks for a loader in
* the {@link #_preload() {@code package.preload}} table.
*
* The second searcher looks for a loader as a Lua library, using the path stored at
* {@link #_path() {@code package.path}}. The search is done as described in function
* {@link #_searchpath() {@code package.searchpath}}.
*
* The third searcher looks for a loader as a C library, using the path given by
* the variable {@link #_cpath() {@code package.cpath}}. Again, the search is done
* as described in function {@link #_searchpath() {@code package.searchpath}}.
* For instance, if the C path is the string
*
* "./?.so;./?.dll;/usr/local/?/init.so"
*
* the searcher for module foo will try to open the files {@code ./foo.so}, {@code ./foo.dll},
* and {@code /usr/local/foo/init.so}, in that order. Once it finds a C library,
* this searcher first uses a dynamic link facility to link the application with the library.
* Then it tries to find a C function inside the library to be used as the loader.
* The name of this C function is the string "{@code luaopen_}" concatenated with a copy of
* the module name where each dot is replaced by an underscore. Moreover, if the module name
* has a hyphen, its suffix after (and including) the first hyphen is removed.
* For instance, if the module name is {@code a.b.c-v2.1}, the function name will
* be {@code luaopen_a_b_c}.
*
* The fourth searcher tries an all-in-one loader. It searches the C path for a library
* for the root name of the given module. For instance, when requiring {@code a.b.c},
* it will search for a C library for {@code a}. If found, it looks into it for
* an open function for the submodule; in our example, that would be {@code luaopen_a_b_c}.
* With this facility, a package can pack several C submodules into one single library,
* with each submodule keeping its original open function.
*
* All searchers except the first one (preload) return as the extra value the file name
* where the module was found, as returned
* by {@link #_searchpath() {@code package.searchpath}}. The first searcher returns
* no extra value.
*
* @return the {@code package.searchers} table
*/
public abstract Table _searchers();
/**
* {@code package.searchpath (name, path [, sep [, rep]])}
*
* Searches for the given name in the given {@code path}.
*
* A path is a string containing a sequence of templates separated by semicolons.
* For each template, the function replaces each interrogation mark (if any) in the template
* with a copy of name wherein all occurrences of {@code sep} (a dot, by default) were
* replaced by {@code rep} (the system's directory separator, by default), and then tries
* to open the resulting file name.
*
* For instance, if the path is the string
*
* "./?.lua;./?.lc;/usr/local/?/init.lua"
*
* the search for the name {@code foo.a} will try to open the files {@code ./foo/a.lua},
* {@code ./foo/a.lc}, and {@code /usr/local/foo/a/init.lua}, in that order.
*
* Returns the resulting name of the first file that it can open in read mode
* (after closing the file), or nil plus an error message if none succeeds.
* (This error message lists all file names it tried to open.)
*
* @return the {@code package.searchpath} function
*/
public abstract LuaFunction _searchpath();
}