2013-07-16 01:43:32 +00:00
|
|
|
/*
|
2013-07-19 17:29:33 +00:00
|
|
|
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
|
2013-07-16 01:43:32 +00:00
|
|
|
Released under Apache 2.0 license as described in the file LICENSE.
|
|
|
|
|
2013-07-19 17:29:33 +00:00
|
|
|
Author: Leonardo de Moura
|
2013-07-16 01:43:32 +00:00
|
|
|
*/
|
|
|
|
#include <cstring>
|
2013-07-21 22:56:18 +00:00
|
|
|
#include <vector>
|
|
|
|
#include <algorithm>
|
2013-08-08 02:10:12 +00:00
|
|
|
#include <sstream>
|
2013-09-13 10:35:29 +00:00
|
|
|
#include <string>
|
2013-12-09 22:56:48 +00:00
|
|
|
#include "util/thread.h"
|
2013-09-13 10:35:29 +00:00
|
|
|
#include "util/name.h"
|
2013-11-27 03:15:49 +00:00
|
|
|
#include "util/sstream.h"
|
2013-09-13 10:35:29 +00:00
|
|
|
#include "util/debug.h"
|
|
|
|
#include "util/rc.h"
|
|
|
|
#include "util/buffer.h"
|
|
|
|
#include "util/hash.h"
|
|
|
|
#include "util/trace.h"
|
|
|
|
#include "util/ascii.h"
|
2013-12-28 01:47:20 +00:00
|
|
|
#include "util/object_serializer.h"
|
2014-05-08 21:15:28 +00:00
|
|
|
#include "util/lua_list.h"
|
2013-07-16 01:43:32 +00:00
|
|
|
|
|
|
|
namespace lean {
|
|
|
|
constexpr char const * anonymous_str = "[anonymous]";
|
|
|
|
|
2013-07-26 18:43:53 +00:00
|
|
|
/**
|
|
|
|
\brief Actual implementation of hierarchical names.
|
|
|
|
*/
|
2013-07-16 01:43:32 +00:00
|
|
|
struct name::imp {
|
2013-07-16 17:11:14 +00:00
|
|
|
MK_LEAN_RC()
|
2013-07-16 01:43:32 +00:00
|
|
|
bool m_is_string;
|
2013-07-24 18:00:29 +00:00
|
|
|
unsigned m_hash;
|
2013-07-16 01:43:32 +00:00
|
|
|
imp * m_prefix;
|
|
|
|
union {
|
|
|
|
char * m_str;
|
|
|
|
unsigned m_k;
|
|
|
|
};
|
2013-07-19 17:29:33 +00:00
|
|
|
|
2013-07-16 17:11:14 +00:00
|
|
|
void dealloc() {
|
2013-07-16 01:43:32 +00:00
|
|
|
imp * curr = this;
|
2013-07-16 17:11:14 +00:00
|
|
|
while (true) {
|
|
|
|
lean_assert(curr->get_rc() == 0);
|
|
|
|
imp * p = curr->m_prefix;
|
|
|
|
if (curr->m_is_string)
|
|
|
|
delete[] reinterpret_cast<char*>(curr);
|
|
|
|
else
|
|
|
|
delete curr;
|
|
|
|
curr = p;
|
|
|
|
if (!curr || !curr->dec_ref_core())
|
|
|
|
break;
|
2013-07-16 01:43:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-24 18:00:29 +00:00
|
|
|
imp(bool s, imp * p):m_rc(1), m_is_string(s), m_hash(0), m_prefix(p) { if (p) p->inc_ref(); }
|
2013-07-16 01:43:32 +00:00
|
|
|
|
2013-12-28 20:04:56 +00:00
|
|
|
static void display_core(std::ostream & out, imp * p, char const * sep) {
|
2013-07-16 01:43:32 +00:00
|
|
|
lean_assert(p != nullptr);
|
|
|
|
if (p->m_prefix) {
|
2013-12-28 20:04:56 +00:00
|
|
|
display_core(out, p->m_prefix, sep);
|
|
|
|
out << sep;
|
2013-07-16 01:43:32 +00:00
|
|
|
}
|
2013-07-19 17:29:33 +00:00
|
|
|
if (p->m_is_string)
|
2013-07-16 01:43:32 +00:00
|
|
|
out << p->m_str;
|
|
|
|
else
|
|
|
|
out << p->m_k;
|
|
|
|
}
|
|
|
|
|
2013-12-28 20:04:56 +00:00
|
|
|
static void display(std::ostream & out, imp * p, char const * sep = lean_name_separator) {
|
2013-07-16 01:43:32 +00:00
|
|
|
if (p == nullptr)
|
|
|
|
out << anonymous_str;
|
|
|
|
else
|
2013-12-28 20:04:56 +00:00
|
|
|
display_core(out, p, sep);
|
2013-07-16 01:43:32 +00:00
|
|
|
}
|
2013-07-21 22:56:18 +00:00
|
|
|
|
2013-08-19 18:43:09 +00:00
|
|
|
friend void copy_limbs(imp * p, buffer<name::imp *> & limbs) {
|
2013-07-21 22:56:18 +00:00
|
|
|
limbs.clear();
|
|
|
|
while (p != nullptr) {
|
|
|
|
limbs.push_back(p);
|
|
|
|
p = p->m_prefix;
|
|
|
|
}
|
|
|
|
std::reverse(limbs.begin(), limbs.end());
|
|
|
|
}
|
2013-07-16 01:43:32 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
name::name(imp * p) {
|
2013-07-29 05:34:39 +00:00
|
|
|
m_ptr = p;
|
|
|
|
if (m_ptr)
|
|
|
|
m_ptr->inc_ref();
|
2013-07-16 01:43:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
name::name() {
|
2013-07-29 05:34:39 +00:00
|
|
|
m_ptr = nullptr;
|
2013-07-16 01:43:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
name::name(name const & prefix, char const * name) {
|
|
|
|
size_t sz = strlen(name);
|
2013-09-13 23:14:24 +00:00
|
|
|
lean_assert(sz < (1u << 31));
|
2013-07-16 01:43:32 +00:00
|
|
|
char * mem = new char[sizeof(imp) + sz + 1];
|
2013-07-29 05:34:39 +00:00
|
|
|
m_ptr = new (mem) imp(true, prefix.m_ptr);
|
2013-07-24 21:41:03 +00:00
|
|
|
std::memcpy(mem + sizeof(imp), name, sz + 1);
|
2013-07-29 05:34:39 +00:00
|
|
|
m_ptr->m_str = mem + sizeof(imp);
|
|
|
|
if (m_ptr->m_prefix)
|
|
|
|
m_ptr->m_hash = hash_str(sz, name, m_ptr->m_prefix->m_hash);
|
2013-07-24 18:00:29 +00:00
|
|
|
else
|
2013-07-29 05:34:39 +00:00
|
|
|
m_ptr->m_hash = hash_str(sz, name, 0);
|
2013-07-16 01:43:32 +00:00
|
|
|
}
|
|
|
|
|
2013-09-24 18:01:30 +00:00
|
|
|
name::name(name const & prefix, unsigned k, bool) {
|
2013-07-29 05:34:39 +00:00
|
|
|
m_ptr = new imp(false, prefix.m_ptr);
|
|
|
|
m_ptr->m_k = k;
|
|
|
|
if (m_ptr->m_prefix)
|
|
|
|
m_ptr->m_hash = ::lean::hash(m_ptr->m_prefix->m_hash, k);
|
2013-07-24 18:00:29 +00:00
|
|
|
else
|
2013-07-29 05:34:39 +00:00
|
|
|
m_ptr->m_hash = k;
|
2013-07-16 01:43:32 +00:00
|
|
|
}
|
|
|
|
|
2013-09-24 18:01:30 +00:00
|
|
|
name::name(name const & prefix, unsigned k):name(prefix, k, true) {
|
|
|
|
lean_assert(prefix.m_ptr);
|
|
|
|
}
|
|
|
|
|
2013-07-16 01:43:32 +00:00
|
|
|
name::name(char const * n):name(name(), n) {
|
|
|
|
}
|
|
|
|
|
2013-09-24 18:01:30 +00:00
|
|
|
name::name(unsigned k):name(name(), k, true) {
|
2013-07-16 01:43:32 +00:00
|
|
|
}
|
|
|
|
|
2013-07-29 05:34:39 +00:00
|
|
|
name::name(name const & other):m_ptr(other.m_ptr) {
|
2013-07-30 07:25:19 +00:00
|
|
|
if (m_ptr)
|
|
|
|
m_ptr->inc_ref();
|
2013-07-16 01:43:32 +00:00
|
|
|
}
|
|
|
|
|
2013-07-29 05:34:39 +00:00
|
|
|
name::name(name && other):m_ptr(other.m_ptr) {
|
2013-08-01 20:57:43 +00:00
|
|
|
other.m_ptr = nullptr;
|
2013-07-16 01:43:32 +00:00
|
|
|
}
|
|
|
|
|
2013-08-09 00:05:11 +00:00
|
|
|
name::name(std::initializer_list<char const *> const & l):name() {
|
|
|
|
if (l.size() == 0) {
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
auto it = l.begin();
|
|
|
|
*this = name(*it);
|
|
|
|
++it;
|
|
|
|
for (; it != l.end(); ++it)
|
|
|
|
*this = name(*this, *it);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-16 01:43:32 +00:00
|
|
|
name::~name() {
|
2013-07-29 05:34:39 +00:00
|
|
|
if (m_ptr)
|
|
|
|
m_ptr->dec_ref();
|
2013-07-16 01:43:32 +00:00
|
|
|
}
|
|
|
|
|
2013-08-13 22:13:54 +00:00
|
|
|
static name g_anonymous;
|
|
|
|
|
|
|
|
name const & name::anonymous() {
|
|
|
|
lean_assert(g_anonymous.is_anonymous());
|
|
|
|
return g_anonymous;
|
|
|
|
}
|
|
|
|
|
2013-12-09 22:56:48 +00:00
|
|
|
static atomic<unsigned> g_next_id(0);
|
2013-09-24 18:01:30 +00:00
|
|
|
|
|
|
|
name name::mk_internal_unique_name() {
|
2013-10-25 18:50:35 +00:00
|
|
|
unsigned id = g_next_id++;
|
2013-09-24 18:01:30 +00:00
|
|
|
return name(id);
|
|
|
|
}
|
|
|
|
|
2013-12-13 23:00:30 +00:00
|
|
|
name & name::operator=(name const & other) { LEAN_COPY_REF(other); }
|
2013-07-16 01:43:32 +00:00
|
|
|
|
2013-12-13 23:00:30 +00:00
|
|
|
name & name::operator=(name && other) { LEAN_MOVE_REF(other); }
|
2013-07-16 01:43:32 +00:00
|
|
|
|
2013-07-22 11:14:01 +00:00
|
|
|
name_kind name::kind() const {
|
2013-07-29 05:34:39 +00:00
|
|
|
if (m_ptr == nullptr)
|
2013-07-22 11:14:01 +00:00
|
|
|
return name_kind::ANONYMOUS;
|
2013-07-19 17:29:33 +00:00
|
|
|
else
|
2013-07-29 05:34:39 +00:00
|
|
|
return m_ptr->m_is_string ? name_kind::STRING : name_kind::NUMERAL;
|
2013-07-16 01:43:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
unsigned name::get_numeral() const {
|
|
|
|
lean_assert(is_numeral());
|
2013-07-29 05:34:39 +00:00
|
|
|
return m_ptr->m_k;
|
2013-07-16 01:43:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
char const * name::get_string() const {
|
|
|
|
lean_assert(is_string());
|
2013-07-29 05:34:39 +00:00
|
|
|
return m_ptr->m_str;
|
2013-07-16 01:43:32 +00:00
|
|
|
}
|
|
|
|
|
2013-07-21 22:08:14 +00:00
|
|
|
bool operator==(name const & a, name const & b) {
|
2013-07-29 05:34:39 +00:00
|
|
|
name::imp * i1 = a.m_ptr;
|
|
|
|
name::imp * i2 = b.m_ptr;
|
2013-07-16 01:43:32 +00:00
|
|
|
while (true) {
|
|
|
|
if (i1 == i2)
|
|
|
|
return true;
|
|
|
|
if ((i1 == nullptr) != (i2 == nullptr))
|
|
|
|
return false;
|
2013-07-24 18:00:29 +00:00
|
|
|
if (i1->m_hash != i2->m_hash)
|
|
|
|
return false;
|
2013-07-16 01:43:32 +00:00
|
|
|
lean_assert(i1 != nullptr);
|
|
|
|
lean_assert(i2 != nullptr);
|
|
|
|
if (i1->m_is_string != i2->m_is_string)
|
|
|
|
return false;
|
2013-07-21 22:08:14 +00:00
|
|
|
if (i1->m_is_string) {
|
|
|
|
if (strcmp(i1->m_str, i2->m_str) != 0)
|
2013-07-16 01:43:32 +00:00
|
|
|
return false;
|
2013-08-07 15:17:33 +00:00
|
|
|
} else {
|
2013-07-21 22:08:14 +00:00
|
|
|
if (i1->m_k != i2->m_k)
|
2013-07-16 01:43:32 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
i1 = i1->m_prefix;
|
|
|
|
i2 = i2->m_prefix;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-19 18:43:09 +00:00
|
|
|
bool is_prefix_of(name const & n1, name const & n2) {
|
2014-02-20 19:20:31 +00:00
|
|
|
if (n2.is_atomic())
|
|
|
|
return n1 == n2;
|
2013-08-19 18:43:09 +00:00
|
|
|
buffer<name::imp*> limbs1, limbs2;
|
|
|
|
name::imp* i1 = n1.m_ptr;
|
|
|
|
name::imp* i2 = n2.m_ptr;
|
|
|
|
copy_limbs(i1, limbs1);
|
|
|
|
copy_limbs(i2, limbs2);
|
|
|
|
unsigned sz1 = limbs1.size();
|
|
|
|
unsigned sz2 = limbs2.size();
|
|
|
|
if (sz1 > sz2)
|
|
|
|
return false;
|
|
|
|
else if (sz1 == sz2 && n1.hash() != n2.hash())
|
|
|
|
return false;
|
|
|
|
auto it1 = limbs1.begin();
|
|
|
|
auto it2 = limbs2.begin();
|
|
|
|
for (; it1 != limbs1.end(); ++it1, ++it2) {
|
|
|
|
i1 = *it1;
|
|
|
|
i2 = *it2;
|
|
|
|
if (i1->m_is_string != i2->m_is_string)
|
|
|
|
return false;
|
|
|
|
if (i1->m_is_string) {
|
|
|
|
if (strcmp(i1->m_str, i2->m_str) != 0)
|
|
|
|
return false;
|
|
|
|
} else if (i1->m_k != i2->m_k) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-08-08 23:30:35 +00:00
|
|
|
bool operator==(name const & a, char const * b) {
|
|
|
|
return a.m_ptr->m_is_string && strcmp(a.m_ptr->m_str, b) == 0;
|
|
|
|
}
|
|
|
|
|
2013-07-21 22:56:18 +00:00
|
|
|
int cmp(name::imp * i1, name::imp * i2) {
|
2013-08-19 18:43:09 +00:00
|
|
|
buffer<name::imp *> limbs1, limbs2;
|
2013-07-21 22:56:18 +00:00
|
|
|
copy_limbs(i1, limbs1);
|
|
|
|
copy_limbs(i2, limbs2);
|
|
|
|
auto it1 = limbs1.begin();
|
|
|
|
auto it2 = limbs2.begin();
|
|
|
|
for (; it1 != limbs1.end() && it2 != limbs2.end(); ++it1, ++it2) {
|
|
|
|
i1 = *it1;
|
|
|
|
i2 = *it2;
|
|
|
|
|
|
|
|
if (i1->m_is_string != i2->m_is_string)
|
|
|
|
return i1->m_is_string ? 1 : -1;
|
|
|
|
|
|
|
|
if (i1->m_is_string) {
|
|
|
|
int c = strcmp(i1->m_str, i2->m_str);
|
|
|
|
if (c != 0)
|
|
|
|
return c;
|
2013-08-07 15:17:33 +00:00
|
|
|
} else if (i1->m_k != i2->m_k) {
|
2013-07-21 22:56:18 +00:00
|
|
|
return i1->m_k < i2->m_k ? -1 : 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (it1 == limbs1.end() && it2 == limbs2.end())
|
|
|
|
return 0;
|
|
|
|
else return it1 == limbs1.end() ? -1 : 1;
|
|
|
|
}
|
|
|
|
|
2013-07-16 01:43:32 +00:00
|
|
|
bool name::is_atomic() const {
|
2013-07-29 05:34:39 +00:00
|
|
|
return m_ptr == nullptr || m_ptr->m_prefix == nullptr;
|
2013-07-16 01:43:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
name name::get_prefix() const {
|
2014-05-18 20:42:35 +00:00
|
|
|
return is_atomic() ? name() : name(m_ptr->m_prefix);
|
2013-07-16 01:43:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static unsigned num_digits(unsigned k) {
|
|
|
|
if (k == 0)
|
|
|
|
return 1;
|
2013-07-19 17:29:33 +00:00
|
|
|
int r = 0;
|
|
|
|
while (k != 0) {
|
|
|
|
k /= 10;
|
|
|
|
r++;
|
2013-07-16 01:43:32 +00:00
|
|
|
}
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2013-08-13 15:18:01 +00:00
|
|
|
size_t name::size() const {
|
2013-07-29 05:34:39 +00:00
|
|
|
if (m_ptr == nullptr) {
|
2013-07-16 01:43:32 +00:00
|
|
|
return strlen(anonymous_str);
|
2013-08-07 15:17:33 +00:00
|
|
|
} else {
|
2013-07-29 05:34:39 +00:00
|
|
|
imp * i = m_ptr;
|
2013-08-13 15:18:01 +00:00
|
|
|
size_t sep_sz = strlen(lean_name_separator);
|
2013-07-16 01:43:32 +00:00
|
|
|
size_t r = 0;
|
|
|
|
while (true) {
|
|
|
|
if (i->m_is_string) {
|
|
|
|
r += strlen(i->m_str);
|
2013-08-07 15:17:33 +00:00
|
|
|
} else {
|
2013-07-16 01:43:32 +00:00
|
|
|
r += num_digits(i->m_k);
|
|
|
|
}
|
|
|
|
if (i->m_prefix) {
|
|
|
|
r += sep_sz;
|
|
|
|
i = i->m_prefix;
|
2013-08-07 15:17:33 +00:00
|
|
|
} else {
|
2013-07-16 01:43:32 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-20 21:15:54 +00:00
|
|
|
unsigned name::hash() const {
|
2013-08-08 02:10:12 +00:00
|
|
|
return m_ptr ? m_ptr->m_hash : 11;
|
|
|
|
}
|
|
|
|
|
2013-09-03 17:09:19 +00:00
|
|
|
bool name::is_safe_ascii() const {
|
|
|
|
imp * i = m_ptr;
|
|
|
|
while (i) {
|
|
|
|
if (i->m_is_string) {
|
|
|
|
if (!::lean::is_safe_ascii(i->m_str))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
i = i->m_prefix;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-12-28 20:04:56 +00:00
|
|
|
std::string name::to_string(char const * sep) const {
|
2013-08-08 02:10:12 +00:00
|
|
|
std::ostringstream s;
|
2013-12-28 20:04:56 +00:00
|
|
|
imp::display(s, m_ptr, sep);
|
2013-08-08 02:10:12 +00:00
|
|
|
return s.str();
|
2013-07-20 21:15:54 +00:00
|
|
|
}
|
|
|
|
|
2013-07-16 01:43:32 +00:00
|
|
|
std::ostream & operator<<(std::ostream & out, name const & n) {
|
2013-08-13 15:18:01 +00:00
|
|
|
name::imp::display(out, n.m_ptr);
|
2013-07-16 01:43:32 +00:00
|
|
|
return out;
|
|
|
|
}
|
2013-08-06 03:06:07 +00:00
|
|
|
|
2013-09-03 18:07:28 +00:00
|
|
|
name operator+(name const & n1, name const & n2) {
|
|
|
|
if (n2.is_anonymous()) {
|
|
|
|
return n1;
|
2014-01-01 20:28:18 +00:00
|
|
|
} else if (n1.is_anonymous()) {
|
|
|
|
return n2;
|
2013-09-03 18:07:28 +00:00
|
|
|
} else {
|
|
|
|
name prefix;
|
|
|
|
if (!n2.is_atomic())
|
|
|
|
prefix = n1 + name(n2.m_ptr->m_prefix);
|
|
|
|
else
|
|
|
|
prefix = n1;
|
|
|
|
if (n2.m_ptr->m_is_string)
|
|
|
|
return name(prefix, n2.m_ptr->m_str);
|
|
|
|
else
|
|
|
|
return name(prefix, n2.m_ptr->m_k);
|
|
|
|
}
|
|
|
|
}
|
2013-11-27 03:15:49 +00:00
|
|
|
|
2014-05-18 20:42:35 +00:00
|
|
|
name name::append_before(char const * p) const {
|
|
|
|
if (is_anonymous()) {
|
|
|
|
return name(p);
|
|
|
|
} else if (is_string()) {
|
|
|
|
return name(get_prefix(), (std::string(p) + std::string(get_string())).c_str());
|
|
|
|
} else {
|
|
|
|
return name(name(get_prefix(), p), get_numeral());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
name name::append_after(char const * s) const {
|
|
|
|
if (is_anonymous()) {
|
|
|
|
return name(s);
|
|
|
|
} else if (is_string()) {
|
|
|
|
return name(get_prefix(), (std::string(get_string()) + std::string(s)).c_str());
|
|
|
|
} else {
|
|
|
|
return name(*this, s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
name name::append_after(unsigned i) const {
|
|
|
|
std::ostringstream s;
|
|
|
|
s << "_" << i;
|
|
|
|
return append_after(s.str().c_str());
|
|
|
|
}
|
|
|
|
|
2013-12-30 03:59:53 +00:00
|
|
|
enum name_ll_kind { LL_ANON = 0, LL_STRING = 1, LL_INT = 2, LL_STRING_PREFIX = 3, LL_INT_PREFIX = 4 };
|
|
|
|
name_ll_kind ll_kind(name const & n) {
|
|
|
|
if (n.is_anonymous())
|
|
|
|
return LL_ANON;
|
|
|
|
if (n.is_atomic())
|
|
|
|
return n.is_string() ? LL_STRING : LL_INT;
|
|
|
|
else
|
|
|
|
return n.is_string() ? LL_STRING_PREFIX : LL_INT_PREFIX;
|
|
|
|
}
|
|
|
|
|
2013-12-28 01:47:20 +00:00
|
|
|
class name_serializer : public object_serializer<name, name::ptr_hash, name::ptr_eq> {
|
|
|
|
typedef object_serializer<name, name::ptr_hash, name::ptr_eq> super;
|
|
|
|
public:
|
|
|
|
void write(name const & n) {
|
2013-12-30 03:59:53 +00:00
|
|
|
name_ll_kind k = ll_kind(n);
|
|
|
|
super::write_core(n, k, [&]() {
|
2013-12-28 01:47:20 +00:00
|
|
|
serializer & s = get_owner();
|
2013-12-30 03:59:53 +00:00
|
|
|
switch (k) {
|
|
|
|
case LL_ANON: break;
|
|
|
|
case LL_STRING: s.write_string(n.get_string()); break;
|
|
|
|
case LL_INT: s.write_unsigned(n.get_numeral()); break;
|
|
|
|
case LL_STRING_PREFIX: write(n.get_prefix()); s.write_string(n.get_string()); break;
|
|
|
|
case LL_INT_PREFIX: write(n.get_prefix()); s.write_unsigned(n.get_numeral()); break;
|
2013-12-28 01:47:20 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class name_deserializer : public object_deserializer<name> {
|
|
|
|
typedef object_deserializer<name> super;
|
|
|
|
public:
|
|
|
|
name read() {
|
2013-12-30 03:59:53 +00:00
|
|
|
return super::read_core([&](char c) {
|
2013-12-28 01:47:20 +00:00
|
|
|
deserializer & d = get_owner();
|
2013-12-30 03:59:53 +00:00
|
|
|
name_ll_kind k = static_cast<name_ll_kind>(c);
|
|
|
|
switch (k) {
|
|
|
|
case LL_ANON: return name();
|
|
|
|
case LL_STRING: return name(d.read_string().c_str());
|
|
|
|
case LL_INT: return name(name(), d.read_unsigned());
|
|
|
|
case LL_STRING_PREFIX: {
|
|
|
|
name prefix = read();
|
2013-12-28 01:47:20 +00:00
|
|
|
return name(prefix, d.read_string().c_str());
|
|
|
|
}
|
2013-12-30 03:59:53 +00:00
|
|
|
case LL_INT_PREFIX: {
|
|
|
|
name prefix = read();
|
|
|
|
return name(prefix, d.read_unsigned());
|
|
|
|
}}
|
2013-12-31 02:05:38 +00:00
|
|
|
throw_corrupted_file();
|
2013-12-28 01:47:20 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct name_sd {
|
|
|
|
unsigned m_serializer_extid;
|
|
|
|
unsigned m_deserializer_extid;
|
|
|
|
name_sd() {
|
|
|
|
m_serializer_extid = serializer::register_extension([](){ return std::unique_ptr<serializer::extension>(new name_serializer()); });
|
|
|
|
m_deserializer_extid = deserializer::register_extension([](){ return std::unique_ptr<deserializer::extension>(new name_deserializer()); });
|
|
|
|
}
|
|
|
|
};
|
|
|
|
static name_sd g_name_sd;
|
|
|
|
|
|
|
|
serializer & operator<<(serializer & s, name const & n) {
|
|
|
|
s.get_extension<name_serializer>(g_name_sd.m_serializer_extid).write(n);
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
name read_name(deserializer & d) {
|
|
|
|
return d.get_extension<name_deserializer>(g_name_sd.m_deserializer_extid).read();
|
|
|
|
}
|
|
|
|
|
2013-11-27 03:15:49 +00:00
|
|
|
DECL_UDATA(name)
|
|
|
|
|
|
|
|
static int mk_name(lua_State * L) {
|
|
|
|
int nargs = lua_gettop(L);
|
|
|
|
name r;
|
|
|
|
for (int i = 1; i <= nargs; i++) {
|
|
|
|
switch (lua_type(L, i)) {
|
|
|
|
case LUA_TNIL: break; // skip
|
|
|
|
case LUA_TNUMBER: r = name(r, lua_tointeger(L, i)); break;
|
|
|
|
case LUA_TSTRING: r = name(r, lua_tostring(L, i)); break;
|
|
|
|
case LUA_TUSERDATA: r = r + to_name(L, i); break;
|
|
|
|
default: throw exception(sstream() << "arg #" << i << " must be a hierarchical name, string, or integer");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return push_name(L, r);
|
|
|
|
}
|
|
|
|
|
|
|
|
name to_name_ext(lua_State * L, int idx) {
|
|
|
|
if (lua_isstring(L, idx)) {
|
|
|
|
return luaL_checkstring(L, idx);
|
|
|
|
} else if (lua_istable(L, idx)) {
|
|
|
|
name r;
|
|
|
|
int n = objlen(L, idx);
|
|
|
|
for (int i = 1; i <= n; i++) {
|
|
|
|
lua_rawgeti(L, idx, i);
|
|
|
|
switch (lua_type(L, -1)) {
|
|
|
|
case LUA_TNIL: break; // skip
|
|
|
|
case LUA_TNUMBER: r = name(r, lua_tointeger(L, -1)); break;
|
|
|
|
case LUA_TSTRING: r = name(r, lua_tostring(L, -1)); break;
|
|
|
|
case LUA_TUSERDATA: r = r + to_name(L, -1); break;
|
|
|
|
default: throw exception("invalid array arguments, elements must be a hierarchical name, string, or integer");
|
|
|
|
}
|
|
|
|
lua_pop(L, 1);
|
|
|
|
}
|
|
|
|
return r;
|
|
|
|
} else {
|
|
|
|
return to_name(L, idx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-02 01:40:18 +00:00
|
|
|
static int name_tostring(lua_State * L) { return push_string(L, to_name(L, 1).to_string().c_str()); }
|
|
|
|
static int name_eq(lua_State * L) { return push_boolean(L, to_name(L, 1) == to_name(L, 2)); }
|
|
|
|
static int name_lt(lua_State * L) { return push_boolean(L, to_name(L, 1) < to_name(L, 2)); }
|
|
|
|
static int name_hash(lua_State * L) { return push_integer(L, to_name(L, 1).hash()); }
|
|
|
|
#define NAME_PRED(P) static int name_ ## P(lua_State * L) { return push_boolean(L, to_name(L, 1).P()); }
|
2014-01-08 01:35:34 +00:00
|
|
|
NAME_PRED(is_atomic)
|
|
|
|
NAME_PRED(is_anonymous)
|
|
|
|
NAME_PRED(is_string)
|
|
|
|
NAME_PRED(is_numeral)
|
|
|
|
|
|
|
|
static int name_get_prefix(lua_State * L) {
|
|
|
|
if (to_name(L, 1).is_atomic())
|
|
|
|
throw exception("invalid get_prefix, non-atomic name expected");
|
|
|
|
return push_name(L, to_name(L, 1).get_prefix());
|
|
|
|
}
|
|
|
|
|
|
|
|
static int name_get_numeral(lua_State * L) {
|
2014-01-08 01:52:51 +00:00
|
|
|
if (!to_name(L, 1).is_numeral())
|
2014-01-08 01:35:34 +00:00
|
|
|
throw exception("invalid get_numeral, hierarchical name with numeric head expected");
|
2014-05-02 01:40:18 +00:00
|
|
|
return push_integer(L, to_name(L, 1).get_numeral());
|
2014-01-08 01:35:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int name_get_string(lua_State * L) {
|
2014-01-08 01:52:51 +00:00
|
|
|
if (!to_name(L, 1).is_string())
|
2014-01-08 01:35:34 +00:00
|
|
|
throw exception("invalid get_string, hierarchical name with string head expected");
|
2014-05-02 01:40:18 +00:00
|
|
|
return push_string(L, to_name(L, 1).get_string());
|
2014-01-08 01:35:34 +00:00
|
|
|
}
|
|
|
|
|
2014-05-18 20:42:35 +00:00
|
|
|
static int name_append_before(lua_State * L) { return push_name(L, to_name(L, 1).append_before(lua_tostring(L, 2))); }
|
|
|
|
static int name_append_after(lua_State * L) {
|
|
|
|
if (lua_isnumber(L, 2))
|
|
|
|
return push_name(L, to_name(L, 1).append_after(lua_tonumber(L, 2)));
|
|
|
|
else
|
|
|
|
return push_name(L, to_name(L, 1).append_after(lua_tostring(L, 2)));
|
|
|
|
}
|
|
|
|
|
2013-11-27 03:15:49 +00:00
|
|
|
static const struct luaL_Reg name_m[] = {
|
2014-05-18 20:42:35 +00:00
|
|
|
{"__gc", name_gc}, // never throws
|
|
|
|
{"__tostring", safe_function<name_tostring>},
|
|
|
|
{"__eq", safe_function<name_eq>},
|
|
|
|
{"__lt", safe_function<name_lt>},
|
|
|
|
{"is_atomic", safe_function<name_is_atomic>},
|
|
|
|
{"is_anonymous", safe_function<name_is_anonymous>},
|
|
|
|
{"is_numeral", safe_function<name_is_numeral>},
|
|
|
|
{"is_string", safe_function<name_is_string>},
|
|
|
|
{"get_prefix", safe_function<name_get_prefix>},
|
|
|
|
{"get_numeral", safe_function<name_get_numeral>},
|
|
|
|
{"get_string", safe_function<name_get_string>},
|
|
|
|
{"hash", safe_function<name_hash>},
|
|
|
|
{"append_before", safe_function<name_append_before>},
|
|
|
|
{"append_after", safe_function<name_append_after>},
|
2013-11-27 03:15:49 +00:00
|
|
|
{0, 0}
|
|
|
|
};
|
|
|
|
|
2013-11-27 18:32:15 +00:00
|
|
|
static void name_migrate(lua_State * src, int i, lua_State * tgt) {
|
|
|
|
push_name(tgt, to_name(src, i));
|
|
|
|
}
|
|
|
|
|
2014-04-30 23:32:10 +00:00
|
|
|
DEFINE_LUA_LIST(name, push_name, to_name_ext)
|
|
|
|
|
2013-11-27 03:15:49 +00:00
|
|
|
void open_name(lua_State * L) {
|
|
|
|
luaL_newmetatable(L, name_mt);
|
2013-11-27 18:32:15 +00:00
|
|
|
set_migrate_fn_field(L, -1, name_migrate);
|
2013-11-27 03:15:49 +00:00
|
|
|
lua_pushvalue(L, -1);
|
|
|
|
lua_setfield(L, -2, "__index");
|
|
|
|
setfuncs(L, name_m, 0);
|
|
|
|
|
|
|
|
SET_GLOBAL_FUN(mk_name, "name");
|
|
|
|
SET_GLOBAL_FUN(name_pred, "is_name");
|
2014-04-30 23:32:10 +00:00
|
|
|
|
|
|
|
open_list_name(L);
|
2013-11-27 03:15:49 +00:00
|
|
|
}
|
2013-09-03 18:07:28 +00:00
|
|
|
}
|
2013-08-07 19:10:10 +00:00
|
|
|
void print(lean::name const & n) { std::cout << n << std::endl; }
|