Add support for creating unique internal names.

Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
Leonardo de Moura 2013-09-24 11:01:30 -07:00
parent 1779b29355
commit e23813f15d
8 changed files with 49 additions and 35 deletions

View file

@ -28,7 +28,7 @@ Author: Leonardo de Moura
#include "frontends/lean/elaborator_exception.h"
namespace lean {
static name g_choice_name(name(name(name(0u), "library"), "choice"));
static name g_choice_name = name::mk_internal_unique_name();
static expr g_choice = mk_constant(g_choice_name);
static format g_assignment_fmt = format(":=");
static format g_unification_u_fmt = format("\u2248");

View file

@ -99,7 +99,7 @@ static unsigned g_level_cup_prec = 5;
// A name that can't be created by the user.
// It is used as placeholder for parsing A -> B expressions which
// are syntax sugar for (Pi (_ : A), B)
static name g_unused(name(0u), "parser");
static name g_unused = name::mk_internal_unique_name();
/**
\brief Actual implementation for the parser functional object

View file

@ -7,7 +7,7 @@ Author: Leonardo de Moura
#include "library/context_to_lambda.h"
namespace lean {
static expr g_fake = Const(name(name(0u), "context_to_lambda"));
static expr g_fake = Const(name::mk_internal_unique_name());
expr context_to_lambda(context::iterator it, context::iterator const & end, expr const & e) {
if (it == end) {
return e;

View file

@ -141,7 +141,7 @@ void tst2() {
expr mk_big(expr f, unsigned depth, unsigned val) {
if (depth == 1)
return Const(name(val));
return Const(name(name("foo"), val));
else
return f(mk_big(f, depth - 1, val << 1), mk_big(f, depth - 1, (val << 1) + 1));
}

View file

@ -17,7 +17,7 @@ using namespace lean;
expr mk_big(expr f, unsigned depth, unsigned val) {
if (depth == 1)
return mk_constant(name(val));
return mk_constant(name(name("foo"), val));
else
return f(mk_big(f, depth - 1, val << 1), mk_big(f, depth - 1, (val << 1) + 1));
}
@ -25,7 +25,7 @@ expr mk_big(expr f, unsigned depth, unsigned val) {
static void tst1() {
expr f = Const("f");
expr r = mk_big(f, 16, 0);
expr n = Const(name(0u));
expr n = Const(name("foo"));
for (unsigned i = 0; i < 20; i++) {
r = abstract(r, n);
}

View file

@ -13,7 +13,6 @@ using namespace lean;
static void tst1() {
name n("foo");
lean_assert(n == name("foo"));
lean_assert(n != name(1));
lean_assert(name(n, 1) != name(n, 2));
lean_assert(name(n, 1) == name(n, 1));
lean_assert(name(name(n, 1), 2) != name(name(n, 1), 1));
@ -37,13 +36,6 @@ static void tst1() {
lean_assert(name(n, 1) < name(n, "xxx"));
lean_assert(name(n, 1) < name(name(n, "xxx"), 1));
lean_assert(name() < name(name(n, "xxx"), 1));
lean_assert(name(1) < name(name(n, "xxx"), 1));
lean_assert(name(1) < name(2));
lean_assert(name(2) > name(1));
lean_assert(name(1) > name());
lean_assert(name(2) < name(name("foo"), 1));
lean_assert(name(0u) < name(name(1), "foo"));
lean_assert(name(2) > name(name(1), "foo"));
}
static name mk_big_name(unsigned num) {
@ -76,24 +68,15 @@ static void tst4() {
lean_assert(!is_prefix_of(name{"foo"}, name{"fo", "bla", "foo"}));
lean_assert(!is_prefix_of(name{"foo", "bla", "foo"}, name{"foo", "bla"}));
lean_assert(is_prefix_of(name{"foo", "bla"}, name(name{"foo", "bla"}, 0u)));
lean_assert(is_prefix_of(name(name(0u), 1u), name(name(0u), 1u)));
lean_assert(!is_prefix_of(name(name(0u), 3u), name(name(0u), 1u)));
lean_assert(is_prefix_of(name(name(0u), 1u), name(name(name(0u), 1u), "foo")));
lean_assert(!is_prefix_of(name(name(2u), 1u), name(name(name(0u), 1u), "foo")));
lean_assert(!is_prefix_of(name(name(0u), 3u), name(name(name(0u), 1u), "foo")));
lean_assert(!is_prefix_of(name(name("bla"), 1u), name(name(name(0u), 1u), "foo")));
}
static void tst5() {
name n(0u);
lean_assert(n.size() == 1);
lean_assert(name().size() > 0);
lean_assert(name({"foo", "bla", "boing"}).get_prefix() == name({"foo", "bla"}));
lean_assert(!name({"foo", "bla", "boing"}).is_atomic());
lean_assert(name({"foo"}).is_atomic());
lean_assert(strcmp(name({"foo", "bla", "boing"}).get_string(), "boing") == 0);
lean_assert(name(name(0u), 1u).get_numeral() == 1u);
lean_assert(name(2u).get_numeral() == 2u);
lean_assert(name(name("foo"), 1u).get_numeral() == 1u);
lean_assert(name::anonymous().is_anonymous());
name n1("foo");
name n2 = n1;
@ -101,30 +84,32 @@ static void tst5() {
std::cout << name::anonymous() << "\n";
std::cout << name({"foo", "bla", "boing"}).get_prefix() << "\n";
lean_assert(name("foo").is_string());
lean_assert(name(0u).is_numeral());
lean_assert(name(name(0u), "foo").is_string());
lean_assert(name(name("boo"), "foo").is_string());
lean_assert(name(name("foo"), 0u).is_numeral());
lean_assert(name(name(0u), "foo").get_prefix().is_numeral());
lean_assert(name(name("foo"), 0u).get_prefix().is_string());
}
static void tst6() {
lean_assert(name({"foo", "bla"}).is_safe_ascii());
lean_assert(name(123u).is_safe_ascii());
lean_assert(name(name(name(230u), "bla"), "foo").is_safe_ascii());
lean_assert(!name({"foo", "b\u2200aaa"}).is_safe_ascii());
lean_assert(!name({"\u2200", "boo"}).is_safe_ascii());
lean_assert(!name(name(name(230u), "bla\u2200"), "foo").is_safe_ascii());
lean_assert(!name(name(name("baa"), "bla\u2200"), "foo").is_safe_ascii());
}
static void tst7() {
lean_assert(name("foo") + name("bla") == name({"foo", "bla"}));
lean_assert(name("foo") + name({"bla", "test"}) == name({"foo", "bla", "test"}));
lean_assert(name({"foo", "hello"}) + name({"bla", "test"}) == name({"foo", "hello", "bla", "test"}));
lean_assert(name("foo") + (name(10u) + name({"bla", "test"})) == name(name(name(name("foo"), 10u), "bla"), "test"));
lean_assert(name("foo") + (name("bla") + name({"bla", "test"})) == name(name(name(name("foo"), "bla"), "bla"), "test"));
lean_assert(name() + name({"bla", "test"}) == name({"bla", "test"}));
lean_assert(name({"bla", "test"}) + name() == name({"bla", "test"}));
lean_assert(name(10u) + name(20u) == name(name(10u), 20u));
}
static void tst8() {
name u1 = name::mk_internal_unique_name();
name u2 = name::mk_internal_unique_name();
lean_assert(u1 != u2);
std::cout << u1 << " " << u2 << "\n";
}
int main() {
@ -135,5 +120,6 @@ int main() {
tst5();
tst6();
tst7();
tst8();
return has_violations() ? 1 : 0;
}

View file

@ -9,6 +9,7 @@ Author: Leonardo de Moura
#include <algorithm>
#include <sstream>
#include <string>
#include <atomic>
#include "util/name.h"
#include "util/debug.h"
#include "util/rc.h"
@ -102,7 +103,7 @@ name::name(name const & prefix, char const * name) {
m_ptr->m_hash = hash_str(sz, name, 0);
}
name::name(name const & prefix, unsigned k) {
name::name(name const & prefix, unsigned k, bool) {
m_ptr = new imp(false, prefix.m_ptr);
m_ptr->m_k = k;
if (m_ptr->m_prefix)
@ -111,10 +112,14 @@ name::name(name const & prefix, unsigned k) {
m_ptr->m_hash = k;
}
name::name(name const & prefix, unsigned k):name(prefix, k, true) {
lean_assert(prefix.m_ptr);
}
name::name(char const * n):name(name(), n) {
}
name::name(unsigned k):name(name(), k) {
name::name(unsigned k):name(name(), k, true) {
}
name::name(name const & other):m_ptr(other.m_ptr) {
@ -150,6 +155,13 @@ name const & name::anonymous() {
return g_anonymous;
}
static std::atomic<unsigned> g_next_id(0);
name name::mk_internal_unique_name() {
unsigned id = std::atomic_fetch_add(&g_next_id, 1u);
return name(id);
}
name & name::operator=(name const & other) { LEAN_COPY_REF(name, other); }
name & name::operator=(name && other) { LEAN_MOVE_REF(name, other); }

View file

@ -19,10 +19,12 @@ class name {
friend int cmp(imp * i1, imp * i2);
imp * m_ptr;
explicit name(imp * p);
explicit name(unsigned k);
// the parameter bool is only used to distinguish this constructor from the public one.
name(name const & prefix, unsigned k, bool);
public:
name();
name(char const * name);
explicit name(unsigned k);
name(name const & prefix, char const * name);
name(name const & prefix, unsigned k);
name(name const & other);
@ -35,6 +37,20 @@ public:
name(std::initializer_list<char const *> const & l);
~name();
static name const & anonymous();
/**
\brief Create a unique internal name that is not meant to exposed
to the user. Different modules require a unique name.
The unique name is created using a numeric prefix.
A module that needs to create several unique names should
the following idiom:
<code>
name unique_prefix = name::mk_internal_unique_name();
name unique_name_1(unique_prefix, 1);
...
name unique_name_k(unique_prefix, k);
</code>
*/
static name mk_internal_unique_name();
name & operator=(name const & other);
name & operator=(name && other);
/** \brief Return true iff \c n1 is a prefix of \c n2. */