diff --git a/src/library/CMakeLists.txt b/src/library/CMakeLists.txt index 04b69d3a0..67944b894 100644 --- a/src/library/CMakeLists.txt +++ b/src/library/CMakeLists.txt @@ -2,7 +2,7 @@ add_library(library deep_copy.cpp expr_lt.cpp io_state.cpp occurs.cpp kernel_bindings.cpp io_state_stream.cpp bin_app.cpp resolve_macro.cpp kernel_serializer.cpp max_sharing.cpp normalize.cpp shared_environment.cpp module.cpp coercion.cpp - private.cpp placeholder.cpp aliases.cpp) + private.cpp placeholder.cpp aliases.cpp scope.cpp) # fo_unify.cpp hop_match.cpp) target_link_libraries(library ${LEAN_LIBS}) diff --git a/src/library/kernel_bindings.h b/src/library/kernel_bindings.h index 338a9ffa5..be77f49b0 100644 --- a/src/library/kernel_bindings.h +++ b/src/library/kernel_bindings.h @@ -23,7 +23,7 @@ UDATA_DEFS(substitution) UDATA_DEFS(io_state) int push_optional_expr(lua_State * L, optional const & e); int push_optional_justification(lua_State * L, optional const & j); -int push_optional_definition(lua_State * L, optional const & d); +int push_optional_declaration(lua_State * L, optional const & e); /** \brief Return the formatter object associated with the given Lua State. This procedure checks for options at: diff --git a/src/library/register_module.h b/src/library/register_module.h index c3e43f5a3..c5867a31e 100644 --- a/src/library/register_module.h +++ b/src/library/register_module.h @@ -12,6 +12,7 @@ Author: Leonardo de Moura #include "library/private.h" #include "library/placeholder.h" #include "library/aliases.h" +#include "library/scope.h" // #include "library/fo_unify.h" // #include "library/hop_match.h" @@ -23,6 +24,7 @@ inline void open_core_module(lua_State * L) { open_private(L); open_placeholder(L); open_aliases(L); + open_scope(L); // open_fo_unify(L); // open_hop_match(L); } diff --git a/src/library/scope.cpp b/src/library/scope.cpp new file mode 100644 index 000000000..f36161704 --- /dev/null +++ b/src/library/scope.cpp @@ -0,0 +1,118 @@ +/* +Copyright (c) 2014 Microsoft Corporation. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. + +Author: Leonardo de Moura +*/ +#include +#include "util/list.h" +#include "library/scope.h" +#include "library/kernel_bindings.h" + +namespace lean { +struct scope_ext : public environment_extension { + enum class scope_kind { Namespace, Section }; + struct section { + environment m_prev_env; + }; + list m_namespaces; + list
m_sections; + list m_scope_kinds; + scope_ext() {} +}; + +struct scope_ext_reg { + unsigned m_ext_id; + scope_ext_reg() { m_ext_id = environment::register_extension(std::make_shared()); } +}; + +static scope_ext_reg g_ext; +static scope_ext const & get_extension(environment const & env) { + return static_cast(env.get_extension(g_ext.m_ext_id)); +} +static environment update(environment const & env, scope_ext const & ext) { + return env.update(g_ext.m_ext_id, std::make_shared(ext)); +} + +environment begin_section_scope(environment const & env) { + // TODO(Leo) + return env; +} + +environment begin_namespace_scope(environment const & env, char const * n) { + scope_ext ext = get_extension(env); + ext.m_scope_kinds = list(scope_ext::scope_kind::Namespace, ext.m_scope_kinds); + ext.m_namespaces = list(name(get_namespace(env), n), ext.m_namespaces); + return update(env, ext); +} + +environment end_scope(environment const & env) { + scope_ext ext = get_extension(env); + if (is_nil(ext.m_scope_kinds)) + throw exception("environment does not have open scopes"); + switch (head(ext.m_scope_kinds)) { + case scope_ext::scope_kind::Namespace: + ext.m_namespaces = tail(ext.m_namespaces); + break; + case scope_ext::scope_kind::Section: + // TODO(Leo) + break; + } + ext.m_scope_kinds = tail(ext.m_scope_kinds); + return update(env, ext); +} + +name const & get_namespace(environment const & env) { + scope_ext const & ext = get_extension(env); + if (is_nil(ext.m_namespaces)) + return name::anonymous(); + else + return head(ext.m_namespaces); +} + +optional find(environment const & env, name const & n) { + scope_ext const & ext = get_extension(env); + for (auto const & p : ext.m_namespaces) { + name full_name = p + n; + if (auto d = env.find(full_name)) { + return d; + } + } + return env.find(n); +} + +name get_name_in_namespace(environment const & env, name const & n) { + if (auto d = env.find(n)) { + scope_ext const & ext = get_extension(env); + for (auto const & p : ext.m_namespaces) { + if (is_prefix_of(p, n)) { + name r = n.replace_prefix(p, name()); + if (auto d2 = find(env, r)) { + if (is_eqp(*d, *d2)) + return r; + } + return n; + } + } + } + return n; +} + +static int begin_section_scope(lua_State * L) { return push_environment(L, begin_section_scope(to_environment(L, 1))); } +static int begin_namespace_scope(lua_State * L) { return push_environment(L, begin_namespace_scope(to_environment(L, 1), lua_tostring(L, 2))); } +static int end_scope(lua_State * L) { return push_environment(L, end_scope(to_environment(L, 1))); } +static int get_namespace(lua_State * L) { return push_name(L, get_namespace(to_environment(L, 1))); } +static int get_name_in_namespace(lua_State * L) { + return push_name(L, get_name_in_namespace(to_environment(L, 1), to_name_ext(L, 2))); +} +static int find_decl(lua_State * L) { return push_optional_declaration(L, find(to_environment(L, 1), to_name_ext(L, 2))); } + +void open_scope(lua_State * L) { + SET_GLOBAL_FUN(begin_section_scope, "begin_section_scope"); + SET_GLOBAL_FUN(begin_namespace_scope, "begin_namespace_scope"); + SET_GLOBAL_FUN(end_scope, "end_scope"); + SET_GLOBAL_FUN(get_namespace, "get_namespace"); + SET_GLOBAL_FUN(get_name_in_namespace, "get_name_in_namespace"); + SET_GLOBAL_FUN(find_decl, "find_decl"); +} +} diff --git a/src/library/scope.h b/src/library/scope.h new file mode 100644 index 000000000..20dec80ec --- /dev/null +++ b/src/library/scope.h @@ -0,0 +1,49 @@ +/* +Copyright (c) 2013 Microsoft Corporation. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. + +Author: Leonardo de Moura +*/ +#pragma once +#include +#include "util/lua.h" +#include "kernel/environment.h" + +namespace lean { +/** + \brief Create a section scope. When a section is closed all definitions and theorems are relativized with + respect to var_decls and axioms. That is, var_decls and axioms become new arguments for the definitions and axioms. +*/ +environment begin_section_scope(environment const & env); + +/** + \brief Create a namespace scope. A namespace is just a mechanism + for appending the prefix n to declarations added to the + environment. +*/ +environment begin_namespace_scope(environment const & env, char const * n); + +/** + \brief End/close a scoped created using \c begin_section_scope or \c begin_namespace_scope. + Throws an exception if there is no open scope. +*/ +environment end_scope(environment const & env); + +/** + \brief Return the current namespace for \c env. The namespace is composed by the sequence + of names provided to \c begin_namespace_scope. +*/ +name const & get_namespace(environment const & env); + +/** + \brief Return the name of \c n in the current namespace of \c env. + Example: if the current namespace is foo.bar and \c n is foo.bar.bla.1, then + the result is bla.1. +*/ +name get_name_in_namespace(environment const & env, name const & n); + +/** \brief Find a declaration named \c n in \c env by taking the active namespaces into account. */ +optional find(environment const & env, name const & n); + +void open_scope(lua_State * L); +} diff --git a/tests/lua/namespace1.lua b/tests/lua/namespace1.lua new file mode 100644 index 000000000..2dee12ff2 --- /dev/null +++ b/tests/lua/namespace1.lua @@ -0,0 +1,23 @@ +local env = environment() +env = begin_namespace_scope(env, "foo") +assert(get_namespace(env) == name("foo")) +env = add_decl(env, mk_var_decl(name(get_namespace(env), "nat"), Type)) +env = add_decl(env, mk_var_decl(name(get_namespace(env), "int"), Type)) +env = begin_namespace_scope(env, "bar") +assert(get_namespace(env) == name("foo", "bar")) +assert(find_decl(env, "int"):name() == name("foo", "int")) +assert(find_decl(env, "nat"):name() == name("foo", "nat")) +env = add_decl(env, mk_var_decl(name(get_namespace(env), "int"), Type)) +assert(find_decl(env, "int"):name() == name("foo", "bar", "int")) +assert(get_name_in_namespace(env, name("foo", "bar", "int")) == name("int")) +assert(get_name_in_namespace(env, name("foo", "int")) == name("foo", "int")) -- it was shadowed by foo.bar.int +assert(get_name_in_namespace(env, name("foo", "nat")) == name("nat")) +env = end_scope(env) +assert(get_namespace(env) == name("foo")) +assert(get_name_in_namespace(env, name("foo", "bar", "int")) == name("bar", "int")) +assert(get_name_in_namespace(env, name("foo", "nat")) == name("nat")) +env = end_scope(env) +assert(get_name_in_namespace(env, name("foo", "bar", "int")) == name("foo", "bar", "int")) +assert(get_name_in_namespace(env, name("foo", "nat")) == name("foo", "nat")) +check_error(function() env = end_scope(env) end) +assert(get_namespace(env) == name())