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)) { if (r || !is_constant(n)) {
return r; return r;
} else { } else {
object const & obj = find_object(const_name(n)); optional<object> obj = find_object(const_name(n));
if (obj && obj.is_builtin() && obj.get_name() == 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); return to_ext(m_env).find_op_for(obj->get_value(), unicode);
else else
return r; 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_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_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); } 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 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); } 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); } bool has_object(name const & n) const { return m_env.has_object(n); }
typedef environment::object_iterator object_iterator; typedef environment::object_iterator object_iterator;
object_iterator begin_objects() const { return m_env.begin_objects(); } 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. 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) { 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) { 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 (k == object_kind::Definition || k == object_kind::Postulate || k == object_kind::Builtin) {
if (m_frontend.has_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()); std::vector<bool> const & imp_args = m_frontend.get_implicit_arguments(obj->get_name());
buffer<expr> args; buffer<expr> args;
pos_info p = pos(); 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)); args.push_back(save(f, p));
// We parse all the arguments to make sure we // We parse all the arguments to make sure we
// get all explicit arguments. // get all explicit arguments.
@ -776,9 +776,9 @@ class parser::imp {
} }
return mk_app(args); return mk_app(args);
} else if (k == object_kind::Builtin) { } else if (k == object_kind::Builtin) {
return obj.get_value(); return obj->get_value();
} else { } else {
return mk_constant(obj.get_name()); return mk_constant(obj->get_name());
} }
} else { } else {
throw parser_error(sstream() << "invalid object reference, object '" << id << "' is not an expression.", p); 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); t = ::lean::apply_tactic(pr, pr_type);
} else { } else {
name n = check_identifier_next("invalid apply command, identifier, '(' expr ')', or 'script-block' expected"); name n = check_identifier_next("invalid apply command, identifier, '(' expr ')', or 'script-block' expected");
object const & o = m_frontend.find_object(n); optional<object> o = m_frontend.find_object(n);
if (o && (o.is_theorem() || o.is_axiom())) { if (o && (o->is_theorem() || o->is_axiom())) {
t = ::lean::apply_tactic(n); t = ::lean::apply_tactic(n);
} else { } else {
using_script([&](lua_State * L) { using_script([&](lua_State * L) {

View file

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

View file

@ -137,15 +137,13 @@ public:
\brief Return the object with the given name. \brief Return the object with the given name.
It throws an exception if the environment does not have an 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 \brief Find a given object in the environment. Return the null
object if there is no object with the given name. 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 */ /** \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)); } 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_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(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)); } 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; object_cell * m_ptr;
explicit object(object_cell * ptr):m_ptr(ptr) {} explicit object(object_cell * ptr):m_ptr(ptr) {}
public: public:
object():m_ptr(nullptr) {}
object(object const & s):m_ptr(s.m_ptr) { if (m_ptr) m_ptr->inc_ref(); } 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(object && s):m_ptr(s.m_ptr) { s.m_ptr = nullptr; }
~object() { if (m_ptr) m_ptr->dec_ref(); } ~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); } 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 const & s) { LEAN_COPY_REF(object, s); }
object & operator=(object && s) { LEAN_MOVE_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(); } object_kind kind() const { return m_ptr->kind(); }
friend object mk_uvar_decl(name const & n, level const & l); friend object mk_uvar_decl(name const & n, level const & l);
@ -132,6 +125,11 @@ public:
object_cell const * cell() const { return m_ptr; } 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_uvar_decl(name const & n, level const & l);
object mk_builtin(expr const & v); object mk_builtin(expr const & v);
object mk_builtin_set(expr const & r); object mk_builtin_set(expr const & r);

View file

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

View file

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

View file

@ -23,6 +23,7 @@ UDATA_DEFS(justification)
UDATA_DEFS(metavar_env) UDATA_DEFS(metavar_env)
int push_optional_expr(lua_State * L, optional<expr> const & e); 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_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. \brief Return the formatter object associated with the given Lua State.
This procedure checks for options at: 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) { 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> { return mk_tactic01([=](environment const & env, io_state const &, proof_state const & s) -> optional<proof_state> {
object const & obj = env.find_object(th_name); optional<object> obj = env.find_object(th_name);
if (obj && (obj.is_theorem() || obj.is_axiom())) if (obj && (obj->is_theorem() || obj->is_axiom()))
return apply_tactic(env, s, mk_constant(th_name), obj.get_type(), all); return apply_tactic(env, s, mk_constant(th_name), obj->get_type(), all);
else else
return none_proof_state(); return none_proof_state();
}); });

View file

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

View file

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

View file

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

View file

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

View file

@ -7,7 +7,7 @@ for v in env:objects() do
end end
end end
assert(env:find_object("N")) 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"):is_var_decl())
assert(env:find_object("N"):has_type()) assert(env:find_object("N"):has_type())
assert(env:find_object("N"):has_name()) assert(env:find_object("N"):has_name())

View file

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