Commit 2afa7d99 authored by Jamie A. Jennings's avatar Jamie A. Jennings

Changed packagetable interface to separate "add" from "set", so that we can...

Changed packagetable interface to separate "add" from "set", so that we can leverage the fact that "set" happens rarely.  We can assume that the packagetable grows monotonically and that its entries do not change -- except when "set" happens, which may trigger updates of data structures built with the assumptions that the table does not change. HOWEVER, the "set" procedure does nothing special right now, except to issue a warning
parent 26bac504
......@@ -320,13 +320,33 @@ function common.pkgtableref(tbl, importpath, prefix)
return probe.packagename, probe.env
end
function common.pkgtableset(tbl, importpath, prefix, p, e)
function common.pkgtableadd(tbl, importpath, prefix, p, e)
assert(p and e and type(importpath)=="string")
local new_entry = pkgtabletype.new{packagename=p, env=e}
if not tbl[importpath] then tbl[importpath] = {}; end
if tbl[importpath][prefix or 1] then
local errmsg =
"package name is '" .. p .. "', prefix is " ..
(prefix and ("'" .. prefix .. "'") or "nil")
assert(false, errmsg)
end
tbl[importpath][prefix or 1] = new_entry
end
-- We will not support updates to the package table (for now) because we want
-- the compiler to be able to index into the package table. Therefore, entries
-- should not be deleted or modified.
function common.pkgtableset(tbl, importpath, prefix, p, e)
assert(p and e and type(importpath)=="string")
common.warn("replacing package ", importpath)
local new_entry = pkgtabletype.new{packagename=p, env=e}
if tbl[importpath] then
tbl[importpath][prefix or 1] = new_entry
else
error("no entry '" .. importpath .. "' in package table")
end
end
----------------------------------------------------------------------------------------
-- Binding types: novalue, taggedvalue, pattern, macro, pfunction, value, environment
----------------------------------------------------------------------------------------
......
......@@ -273,8 +273,26 @@ local function load(e, input, fullpath)
return really_load(e, input, origin)
end
-- TODO
-- NOT EXPORTED: WE NEED THIS CAPABILITY FOR INTERACTIVE USE, SO SHOULD BE MADE
-- AVAILABLE AS en:import_force(package, as_name)
--
-- Force a reloading of the imported package, as opposed to e:load('import foo') which will not
-- re-load a package that is already loaded.
local function import_force(e, packagename, as_name)
local messages = {}
local ok, pkgname = loadpkg.import_force(e.compiler,
e.pkgtable,
e.libpath.value,
packagename, -- requested importpath
as_name, -- requested prefix
e.env,
messages)
return ok, pkgname, messages
end
-- Do the same as e:load('import foo as bar') which will not re-load a package
-- that is already loaded.
local function import(e, packagename, as_name)
local messages = {}
local ok, pkgname = loadpkg.import(e.compiler,
......
......@@ -7,13 +7,14 @@
-- LICENSE: MIT License (https://opensource.org/licenses/mit-license.html)
-- AUTHOR: Jamie A. Jennings
-- Environments can be extended in a way that new bindings shadow old ones. This permits a tree
-- of environments that model nested scopes. Currently, that nesting is used rarely. Grammar
-- compilation uses this.
-- Environments can be extended in a way that new bindings shadow old ones.
-- This permits a tree of environments that model nested scopes. Currently,
-- (in 2018) that nesting is used rarely. Grammar compilation uses this.
--
-- The root of an environment tree is the "base environment" for a package P. For every other
-- package, X, that is open in P, there is a binding in P: X.prefix->X.env where X.prefix is the
-- prefix used for X in P, and X.env is the package environment for X.
-- The root of an environment tree is the "base environment" for a package P.
-- For every other package, X, that is open in P, there is a binding in P's
-- environment: X.prefix -> X.env where X.prefix is the prefix used for X in P,
-- and X.env is the package environment for X.
local environment = {}
......
......@@ -148,7 +148,13 @@ function loadpkg.source(compiler, pkgtable, top_level_env, searchpath, source, o
-- The code we compiled defined a module, which we have instantiated as a package (in env).
-- But there is no importpath, so we use the packagename as the loadpath to create an entry
-- in the package table.
common.pkgtableset(pkgtable, a.block_pdecl.name, nil, a.block_pdecl.name, env)
if common.pkgtableref(pkgtable, a.block_pdecl.name, nil) then
-- We are overwriting an entry in the package table.
common.note(string.format("load: replacing package %s", a.block_pdecl.name))
common.pkgtableset(pkgtable, a.block_pdecl.name, nil, a.block_pdecl.name, env)
else
common.pkgtableadd(pkgtable, a.block_pdecl.name, nil, a.block_pdecl.name, env)
end
return true, a.block_pdecl.name, env
else
-- The caller must replace their top_level_env with the returned env in order to see the new
......@@ -176,7 +182,7 @@ local function import_from_source(compiler, pkgtable, searchpath, source_record,
if not compile(compiler, a, env, source_record, messages) then
return false
end
common.pkgtableset(pkgtable, origin.importpath, origin.prefix, origin.packagename, env)
common.pkgtableadd(pkgtable, origin.importpath, origin.prefix, origin.packagename, env)
return true, origin.packagename, env
end
......@@ -229,7 +235,7 @@ local function import_builtin(importpath, pkgtable, source_record, messages)
local pkgname, env = environment.get_builtin_package(importpath)
if pkgname then
assert(environment.is(env))
common.pkgtableset(pkgtable, importpath, origin.prefix, pkgname, env)
common.pkgtableadd(pkgtable, importpath, origin.prefix, pkgname, env)
return true, pkgname, env
end
local msg = "built-in package not found: " .. importpath
......@@ -269,7 +275,7 @@ local function import_one(compiler, pkgtable, searchpath, source_record, loading
return import_one_force(compiler, pkgtable, searchpath, source_record, loadinglist, messages)
end
function loadpkg.import(compiler, pkgtable, searchpath, packagename, as_name, env, messages)
local function import(importer, compiler, pkgtable, searchpath, packagename, as_name, env, messages)
assert(type(compiler)=="table")
assert(type(pkgtable)=="table")
assert(type(searchpath)=="string")
......@@ -279,12 +285,22 @@ function loadpkg.import(compiler, pkgtable, searchpath, packagename, as_name, en
assert(type(messages)=="table")
local origin = common.loadrequest.new{importpath=packagename, prefix=as_name}
local source_record = common.source.new{origin=origin}
local ok, pkgname, pkgenv = import_one_force(compiler, pkgtable, searchpath, source_record, {}, messages)
local ok, pkgname, pkgenv = importer(compiler, pkgtable, searchpath, source_record, {}, messages)
if not ok then return false; end -- message already in 'messages'
create_package_bindings(origin.prefix or pkgname, pkgenv, env)
return true, pkgname
end
-- Do the same as en:load('import foo as bar')
function loadpkg.import(compiler, pkgtable, searchpath, packagename, as_name, env, messages)
return import(import_one, compiler, pkgtable, searchpath, packagename, as_name, env, messages)
end
-- Force a reload of the package if it has already been loaded.
function loadpkg.import_force(compiler, pkgtable, searchpath, packagename, as_name, env, messages)
return import(import_one_force, compiler, pkgtable, searchpath, packagename, as_name, env, messages)
end
-- load_dependencies recursively loads each import in ideclist.
-- Returns success; side-effects the messages argument.
function load_dependencies(compiler, pkgtable, searchpath, source_record, a, target_env, loadinglist, messages)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment