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:
parent
2f88d6710c
commit
04b67f8b14
18 changed files with 81 additions and 102 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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(); }
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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)); }
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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>},
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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});
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -4,4 +4,4 @@
|
|||
x : ℤ,
|
||||
y : ℤ
|
||||
Variable x : ℤ
|
||||
<null-kernel-object>
|
||||
nil
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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())
|
||||
|
|
Loading…
Reference in a new issue