refactor(kernel/object): remove 'null' object, and operator bool for kernel objects

Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
Leonardo de Moura 2013-12-08 14:37:38 -08:00
parent 2f88d6710c
commit 04b67f8b14
18 changed files with 81 additions and 102 deletions

View file

@ -402,9 +402,9 @@ operator_info frontend::find_op_for(expr const & n, bool unicode) const {
if (r || !is_constant(n)) {
return r;
} else {
object const & obj = find_object(const_name(n));
if (obj && obj.is_builtin() && obj.get_name() == const_name(n))
return to_ext(m_env).find_op_for(obj.get_value(), unicode);
optional<object> obj = find_object(const_name(n));
if (obj && obj->is_builtin() && obj->get_name() == const_name(n))
return to_ext(m_env).find_op_for(obj->get_value(), unicode);
else
return r;
}

View file

@ -48,8 +48,8 @@ public:
void add_definition(name const & n, expr const & v, bool opaque = false) { m_env.add_definition(n, v, opaque); }
void add_axiom(name const & n, expr const & t) { m_env.add_axiom(n, t); }
void add_var(name const & n, expr const & t) { m_env.add_var(n, t); }
object const & get_object(name const & n) const { return m_env.get_object(n); }
object const & find_object(name const & n) const { return m_env.find_object(n); }
object get_object(name const & n) const { return m_env.get_object(n); }
optional<object> find_object(name const & n) const { return m_env.find_object(n); }
bool has_object(name const & n) const { return m_env.has_object(n); }
typedef environment::object_iterator object_iterator;
object_iterator begin_objects() const { return m_env.begin_objects(); }

View file

@ -755,15 +755,15 @@ class parser::imp {
to check if \c id is a builtin symbol. If it is not throws an error.
*/
expr get_name_ref(name const & id, pos_info const & p) {
object const & obj = m_frontend.find_object(id);
optional<object> obj = m_frontend.find_object(id);
if (obj) {
object_kind k = obj.kind();
object_kind k = obj->kind();
if (k == object_kind::Definition || k == object_kind::Postulate || k == object_kind::Builtin) {
if (m_frontend.has_implicit_arguments(obj.get_name())) {
std::vector<bool> const & imp_args = m_frontend.get_implicit_arguments(obj.get_name());
if (m_frontend.has_implicit_arguments(obj->get_name())) {
std::vector<bool> const & imp_args = m_frontend.get_implicit_arguments(obj->get_name());
buffer<expr> args;
pos_info p = pos();
expr f = (k == object_kind::Builtin) ? obj.get_value() : mk_constant(obj.get_name());
expr f = (k == object_kind::Builtin) ? obj->get_value() : mk_constant(obj->get_name());
args.push_back(save(f, p));
// We parse all the arguments to make sure we
// get all explicit arguments.
@ -776,9 +776,9 @@ class parser::imp {
}
return mk_app(args);
} else if (k == object_kind::Builtin) {
return obj.get_value();
return obj->get_value();
} else {
return mk_constant(obj.get_name());
return mk_constant(obj->get_name());
}
} else {
throw parser_error(sstream() << "invalid object reference, object '" << id << "' is not an expression.", p);
@ -1160,8 +1160,8 @@ class parser::imp {
t = ::lean::apply_tactic(pr, pr_type);
} else {
name n = check_identifier_next("invalid apply command, identifier, '(' expr ')', or 'script-block' expected");
object const & o = m_frontend.find_object(n);
if (o && (o.is_theorem() || o.is_axiom())) {
optional<object> o = m_frontend.find_object(n);
if (o && (o->is_theorem() || o->is_axiom())) {
t = ::lean::apply_tactic(n);
} else {
using_script([&](lua_State * L) {

View file

@ -96,9 +96,9 @@ struct environment::imp {
unsigned w = 0;
auto proc = [&](expr const & c, unsigned) {
if (is_constant(c)) {
object const & obj = get_object_core(const_name(c));
optional<object> obj = get_object_core(const_name(c));
if (obj)
w = std::max(w, obj.get_weight());
w = std::max(w, obj->get_weight());
}
return true;
};
@ -145,22 +145,22 @@ struct environment::imp {
ancestors. Return null object if there is no object with the
given name.
*/
object const & get_object_core(name const & n) const {
optional<object> get_object_core(name const & n) const {
auto it = m_object_dictionary.find(n);
if (it == m_object_dictionary.end()) {
if (has_parent())
return m_parent->get_object_core(n);
else
return object::null();
return none_object();
} else {
return it->second;
return some_object(it->second);
}
}
object const & get_object(name const & n, environment const & env) const {
object const & obj = get_object_core(n);
object get_object(name const & n, environment const & env) const {
optional<object> obj = get_object_core(n);
if (obj) {
return obj;
return *obj;
} else {
throw unknown_object_exception(env, n);
}
@ -559,11 +559,11 @@ void environment::add_neutral_object(neutral_object_cell * o) {
m_ptr->m_objects.push_back(mk_neutral(o));
}
object const & environment::get_object(name const & n) const {
object environment::get_object(name const & n) const {
return m_ptr->get_object(n, *this);
}
object const & environment::find_object(name const & n) const {
optional<object> environment::find_object(name const & n) const {
return m_ptr->get_object_core(n);
}

View file

@ -137,15 +137,13 @@ public:
\brief Return the object with the given name.
It throws an exception if the environment does not have an object with the given name.
*/
object const & get_object(name const & n) const;
object get_object(name const & n) const;
/**
\brief Find a given object in the environment. Return the null
object if there is no object with the given name.
\remark Object implements operator bool(), and the null object returns false.
*/
object const & find_object(name const & n) const;
optional<object> find_object(name const & n) const;
/** \brief Return true iff the environment has an object with the given name */
bool has_object(name const & n) const { return static_cast<bool>(find_object(n)); }

View file

@ -164,12 +164,4 @@ object mk_axiom(name const & n, expr const & t) { return object(new axiom_object
object mk_var_decl(name const & n, expr const & t) { return object(new variable_decl_object_cell(n, t)); }
object mk_builtin(expr const & v) { return object(new builtin_object_cell(v)); }
object mk_builtin_set(expr const & r) { return object(new builtin_set_object_cell(r)); }
static object g_null_object;
object const & object::null() {
lean_assert(!g_null_object);
return g_null_object;
}
}

View file

@ -84,22 +84,15 @@ class object {
object_cell * m_ptr;
explicit object(object_cell * ptr):m_ptr(ptr) {}
public:
object():m_ptr(nullptr) {}
object(object const & s):m_ptr(s.m_ptr) { if (m_ptr) m_ptr->inc_ref(); }
object(object && s):m_ptr(s.m_ptr) { s.m_ptr = nullptr; }
~object() { if (m_ptr) m_ptr->dec_ref(); }
static object const & null();
friend void swap(object & a, object & b) { std::swap(a.m_ptr, b.m_ptr); }
void release() { if (m_ptr) m_ptr->dec_ref(); m_ptr = nullptr; }
object & operator=(object const & s) { LEAN_COPY_REF(object, s); }
object & operator=(object && s) { LEAN_MOVE_REF(object, s); }
explicit operator bool() const { return m_ptr != nullptr; }
object_kind kind() const { return m_ptr->kind(); }
friend object mk_uvar_decl(name const & n, level const & l);
@ -132,6 +125,11 @@ public:
object_cell const * cell() const { return m_ptr; }
};
inline optional<object> none_object() { return optional<object>(); }
inline optional<object> some_object(object const & o) { return optional<object>(o); }
inline optional<object> some_object(object && o) { return optional<object>(std::forward<object>(o)); }
object mk_uvar_decl(name const & n, level const & l);
object mk_builtin(expr const & v);
object mk_builtin_set(expr const & r);

View file

@ -208,8 +208,8 @@ class type_checker::imp {
case expr_kind::Value: {
// Check if the builtin value (or its set) is declared in the environment.
name const & n = to_value(e).get_name();
object const & obj = env().get_object(n);
if (obj && ((obj.is_builtin() && obj.get_value() == e) || (obj.is_builtin_set() && obj.in_builtin_set(e)))) {
object obj = env().get_object(n);
if ((obj.is_builtin() && obj.get_value() == e) || (obj.is_builtin_set() && obj.in_builtin_set(e))) {
return save_result(e, to_value(e).get_type(), shared);
} else {
throw invalid_builtin_value_reference(env(), e);

View file

@ -590,9 +590,9 @@ class elaborator::imp {
int get_const_weight(expr const & a) {
lean_assert(is_constant(a));
object const & obj = m_env.find_object(const_name(a));
if (obj && obj.is_definition() && !obj.is_opaque())
return obj.get_weight();
optional<object> obj = m_env.find_object(const_name(a));
if (obj && obj->is_definition() && !obj->is_opaque())
return obj->get_weight();
else
return -1;
}
@ -613,9 +613,11 @@ class elaborator::imp {
expr unfold(expr const & a) {
lean_assert(is_constant(a) || (is_app(a) && is_constant(arg(a, 0))));
if (is_constant(a)) {
return m_env.find_object(const_name(a)).get_value();
lean_assert(m_env.find_object(const_name(a)));
return m_env.find_object(const_name(a))->get_value();
} else {
return update_app(a, 0, m_env.find_object(const_name(arg(a, 0))).get_value());
lean_assert(m_env.find_object(const_name(arg(a, 0))));
return update_app(a, 0, m_env.find_object(const_name(arg(a, 0)))->get_value());
}
}

View file

@ -1006,7 +1006,7 @@ static int environment_add_axiom(lua_State * L) {
static int environment_find_object(lua_State * L) {
ro_environment env(L, 1);
return push_object(L, env->find_object(to_name_ext(L, 2)));
return push_optional_object(L, env->find_object(to_name_ext(L, 2)));
}
static int environment_has_object(lua_State * L) {
@ -1163,68 +1163,64 @@ static void open_environment(lua_State * L) {
DECL_UDATA(object)
object & to_nonnull_object(lua_State * L, int idx) {
object & r = to_object(L, idx);
if (!r)
throw exception("non-null kernel object expected");
return r;
}
static int object_is_null(lua_State * L) {
lua_pushboolean(L, !to_object(L, 1));
int push_optional_object(lua_State * L, optional<object> const & o) {
if (o)
push_object(L, *o);
else
lua_pushnil(L);
return 1;
}
static int object_keyword(lua_State * L) {
lua_pushstring(L, to_nonnull_object(L, 1).keyword());
lua_pushstring(L, to_object(L, 1).keyword());
return 1;
}
static int object_has_name(lua_State * L) {
lua_pushboolean(L, to_nonnull_object(L, 1).has_name());
lua_pushboolean(L, to_object(L, 1).has_name());
return 1;
}
static int object_get_name(lua_State * L) {
object const & o = to_nonnull_object(L, 1);
object const & o = to_object(L, 1);
if (!o.has_name())
throw exception("kernel object does not have a name");
return push_name(L, o.get_name());
}
static int object_has_type(lua_State * L) {
lua_pushboolean(L, to_nonnull_object(L, 1).has_type());
lua_pushboolean(L, to_object(L, 1).has_type());
return 1;
}
static int object_get_type(lua_State * L) {
object const & o = to_nonnull_object(L, 1);
object const & o = to_object(L, 1);
if (!o.has_type())
throw exception("kernel object does not have a type");
return push_expr(L, o.get_type());
}
static int object_has_cnstr_level(lua_State * L) {
lua_pushboolean(L, to_nonnull_object(L, 1).has_cnstr_level());
lua_pushboolean(L, to_object(L, 1).has_cnstr_level());
return 1;
}
static int object_get_cnstr_level(lua_State * L) {
object const & o = to_nonnull_object(L, 1);
object const & o = to_object(L, 1);
if (!o.has_cnstr_level())
throw exception("kernel object does not have a constraint level");
return push_level(L, o.get_cnstr_level());
}
static int object_get_value(lua_State * L) {
object const & o = to_nonnull_object(L, 1);
object const & o = to_object(L, 1);
if (!o.is_definition() && !o.is_builtin())
throw exception("kernel object is not a definition/theorem/builtin");
return push_expr(L, o.get_value());
}
static int object_get_weight(lua_State * L) {
object const & o = to_nonnull_object(L, 1);
object const & o = to_object(L, 1);
if (!o.is_definition())
throw exception("kernel object is not a definition");
lua_pushinteger(L, o.get_weight());
@ -1233,7 +1229,7 @@ static int object_get_weight(lua_State * L) {
#define OBJECT_PRED(P) \
static int object_ ## P(lua_State * L) { \
lua_pushboolean(L, to_nonnull_object(L, 1).P()); \
lua_pushboolean(L, to_object(L, 1).P()); \
return 1; \
}
@ -1246,7 +1242,7 @@ OBJECT_PRED(is_builtin)
OBJECT_PRED(is_builtin_set)
static int object_in_builtin_set(lua_State * L) {
lua_pushboolean(L, to_nonnull_object(L, 1).in_builtin_set(to_expr(L, 2)));
lua_pushboolean(L, to_object(L, 1).in_builtin_set(to_expr(L, 2)));
return 1;
}
@ -1254,11 +1250,7 @@ static int object_tostring(lua_State * L) {
std::ostringstream out;
formatter fmt = get_global_formatter(L);
options opts = get_global_options(L);
object & obj = to_object(L, 1);
if (obj)
out << mk_pair(fmt(to_object(L, 1), opts), opts);
else
out << "<null-kernel-object>";
out << mk_pair(fmt(to_object(L, 1), opts), opts);
lua_pushstring(L, out.str().c_str());
return 1;
}
@ -1266,7 +1258,6 @@ static int object_tostring(lua_State * L) {
static const struct luaL_Reg object_m[] = {
{"__gc", object_gc}, // never throws
{"__tostring", safe_function<object_tostring>},
{"is_null", safe_function<object_is_null>},
{"keyword", safe_function<object_keyword>},
{"has_name", safe_function<object_has_name>},
{"get_name", safe_function<object_get_name>},

View file

@ -23,6 +23,7 @@ UDATA_DEFS(justification)
UDATA_DEFS(metavar_env)
int push_optional_expr(lua_State * L, optional<expr> const & e);
int push_optional_justification(lua_State * L, optional<justification> const & j);
int push_optional_object(lua_State * L, optional<object> const & o);
/**
\brief Return the formatter object associated with the given Lua State.
This procedure checks for options at:

View file

@ -135,9 +135,9 @@ tactic apply_tactic(expr const & th, expr const & th_type, bool all) {
tactic apply_tactic(name const & th_name, bool all) {
return mk_tactic01([=](environment const & env, io_state const &, proof_state const & s) -> optional<proof_state> {
object const & obj = env.find_object(th_name);
if (obj && (obj.is_theorem() || obj.is_axiom()))
return apply_tactic(env, s, mk_constant(th_name), obj.get_type(), all);
optional<object> obj = env.find_object(th_name);
if (obj && (obj->is_theorem() || obj->is_axiom()))
return apply_tactic(env, s, mk_constant(th_name), obj->get_type(), all);
else
return none_proof_state();
});

View file

@ -396,10 +396,10 @@ protected:
environment m_env;
virtual expr visit_constant(expr const & c, context const &) {
object const & obj = m_env.find_object(const_name(c));
if (obj && obj.is_definition() && !obj.is_opaque() && !is_hidden(m_env, const_name(c))) {
optional<object> obj = m_env.find_object(const_name(c));
if (obj && obj->is_definition() && !obj->is_opaque() && !is_hidden(m_env, const_name(c))) {
m_unfolded = true;
return obj.get_value();
return obj->get_value();
} else {
return c;
}
@ -424,10 +424,10 @@ optional<proof_state> unfold_tactic_core(unfold_core_fn & fn, proof_state const
tactic unfold_tactic(name const & n) {
return mk_tactic01([=](environment const & env, io_state const &, proof_state const & s) -> optional<proof_state> {
object const & obj = env.find_object(n);
if (!obj || !obj.is_definition())
optional<object> obj = env.find_object(n);
if (!obj || !obj->is_definition())
return none_proof_state(); // tactic failed
unfold_fn fn(n, obj.get_value());
unfold_fn fn(n, obj->get_value());
return unfold_tactic_core(fn, s);
});
}

View file

@ -77,11 +77,11 @@ static void tst5() {
formatter fmt = mk_pp_formatter(f);
f.add_var("A", Type());
f.add_var("x", Const("A"));
object const & obj = f.find_object("x");
optional<object> obj = f.find_object("x");
lean_assert(obj);
lean_assert(obj.get_name() == "x");
std::cout << fmt(obj) << "\n";
object const & obj2 = f.find_object("y");
lean_assert(obj->get_name() == "x");
std::cout << fmt(*obj) << "\n";
optional<object> obj2 = f.find_object("y");
lean_assert(!obj2);
try {
f.get_object("y");
@ -118,7 +118,7 @@ static void tst8() {
frontend fe;
formatter fmt = mk_pp_formatter(fe);
fe.add_infixl("<-$->", 10, mk_refl_fn());
std::cout << fmt(fe.find_object("Trivial")) << "\n";
std::cout << fmt(*(fe.find_object("Trivial"))) << "\n";
}
static void tst9() {
@ -142,7 +142,7 @@ static void tst9() {
catch (exception &) {}
lean_assert(!f.find_object("y"));
f.add_definition("y", False);
lean_assert(is_bool(f.find_object("y").get_type()));
lean_assert(is_bool(f.find_object("y")->get_type()));
lean_assert(f.has_object("y"));
lean_assert(!f.has_object("z"));
bool found = false;
@ -173,7 +173,7 @@ static void tst11() {
lean_assert(f.has_implicit_arguments("g"))
name gexp = f.get_explicit_version("g");
lean_assert(f.find_object(gexp));
lean_assert(f.find_object("g").get_type() == f.find_object(gexp).get_type());
lean_assert(f.find_object("g")->get_type() == f.find_object(gexp)->get_type());
lean_assert(f.get_implicit_arguments("g") == std::vector<bool>({true, false, false}));
try {
f.mark_implicit_arguments("g", {true, false, false});

View file

@ -2,17 +2,14 @@
local env = get_environment()
local o1 = env:find_object(name("Int", "add"))
local o2 = env:find_object("xyz31213")
print(o1:get_value())
assert(is_kernel_object(o1))
assert(is_kernel_object(o2))
assert(not o1:is_null())
assert(o2:is_null())
assert(o1)
assert(o1:is_builtin())
assert(o1:keyword() == "Builtin")
assert(o1:get_name() == name("Int", "add"))
assert(not pcall(function() o2:get_name() end))
assert(not pcall(function() o2:keyword() end))
local o2 = env:find_object("xyz31213")
assert(not o2)
local found1 = false
local found2 = false

View file

@ -4,4 +4,4 @@
x : ,
y :
Variable x :
<null-kernel-object>
nil

View file

@ -7,7 +7,7 @@ for v in env:objects() do
end
end
assert(env:find_object("N"))
assert(env:find_object("Z"):is_null())
assert(not env:find_object("Z"))
assert(env:find_object("N"):is_var_decl())
assert(env:find_object("N"):has_type())
assert(env:find_object("N"):has_name())

View file

@ -11,7 +11,7 @@ for o in child:local_objects() do
print(o)
end
local eenv = empty_environment()
print(eenv:find_object("Int"):is_null())
print(not eenv:find_object("Int"))
assert(not pcall(function() env:parent() end))
local p = child:parent()
assert(p:has_children())