2013-08-12 01:06:37 +00:00
|
|
|
/*
|
|
|
|
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
|
|
|
|
Released under Apache 2.0 license as described in the file LICENSE.
|
|
|
|
|
|
|
|
Author: Leonardo de Moura
|
|
|
|
*/
|
2013-09-13 03:04:10 +00:00
|
|
|
#include "util/rc.h"
|
2013-09-13 03:09:35 +00:00
|
|
|
#include "frontends/lean/operator_info.h"
|
2013-12-28 22:39:10 +00:00
|
|
|
#include "frontends/lean/frontend.h"
|
2013-08-12 01:06:37 +00:00
|
|
|
|
|
|
|
namespace lean {
|
2013-08-15 17:46:13 +00:00
|
|
|
/** \brief Actual implementation of operator_info */
|
2013-08-12 01:06:37 +00:00
|
|
|
struct operator_info::imp {
|
|
|
|
void dealloc() { delete this; }
|
|
|
|
MK_LEAN_RC();
|
|
|
|
fixity m_fixity;
|
|
|
|
unsigned m_precedence;
|
|
|
|
list<name> m_op_parts; // operator parts, > 1 only if the operator is mixfix.
|
2013-08-20 00:25:15 +00:00
|
|
|
list<expr> m_exprs; // possible interpretations for the operator.
|
2013-08-12 01:06:37 +00:00
|
|
|
|
2013-08-15 15:52:10 +00:00
|
|
|
imp(name const & op, fixity f, unsigned p):
|
|
|
|
m_rc(1), m_fixity(f), m_precedence(p), m_op_parts(cons(op, list<name>())) {}
|
2013-08-12 01:06:37 +00:00
|
|
|
|
|
|
|
imp(unsigned num_parts, name const * parts, fixity f, unsigned p):
|
2013-09-11 18:36:05 +00:00
|
|
|
m_rc(1), m_fixity(f), m_precedence(p), m_op_parts(to_list<name const *>(parts, parts + num_parts)) {
|
2013-08-12 01:06:37 +00:00
|
|
|
lean_assert(num_parts > 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
imp(imp const & s):
|
2013-08-20 00:25:15 +00:00
|
|
|
m_rc(1), m_fixity(s.m_fixity), m_precedence(s.m_precedence), m_op_parts(s.m_op_parts), m_exprs(s.m_exprs) {
|
2013-08-12 01:06:37 +00:00
|
|
|
}
|
2013-08-14 23:35:04 +00:00
|
|
|
|
|
|
|
bool is_eq(imp const & other) const {
|
|
|
|
return
|
|
|
|
m_fixity == other.m_fixity &&
|
|
|
|
m_precedence == other.m_precedence &&
|
|
|
|
m_op_parts == other.m_op_parts;
|
|
|
|
}
|
2013-08-12 01:06:37 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
operator_info::operator_info(imp * p):m_ptr(p) {}
|
|
|
|
|
|
|
|
operator_info::operator_info(operator_info const & info):m_ptr(info.m_ptr) { if (m_ptr) m_ptr->inc_ref(); }
|
|
|
|
|
|
|
|
operator_info::operator_info(operator_info && info):m_ptr(info.m_ptr) { info.m_ptr = nullptr; }
|
|
|
|
|
|
|
|
operator_info::~operator_info() { if (m_ptr) m_ptr->dec_ref(); }
|
|
|
|
|
2013-12-13 23:00:30 +00:00
|
|
|
operator_info & operator_info::operator=(operator_info const & s) { LEAN_COPY_REF(s); }
|
2013-08-12 01:06:37 +00:00
|
|
|
|
2013-12-13 23:00:30 +00:00
|
|
|
operator_info & operator_info::operator=(operator_info && s) { LEAN_MOVE_REF(s); }
|
2013-08-12 01:06:37 +00:00
|
|
|
|
2013-08-20 00:25:15 +00:00
|
|
|
void operator_info::add_expr(expr const & d) { lean_assert(m_ptr); m_ptr->m_exprs = cons(d, m_ptr->m_exprs); }
|
2013-08-12 01:06:37 +00:00
|
|
|
|
2013-08-20 00:25:15 +00:00
|
|
|
bool operator_info::is_overloaded() const { return m_ptr && !is_nil(m_ptr->m_exprs) && !is_nil(cdr(m_ptr->m_exprs)); }
|
2013-08-12 01:06:37 +00:00
|
|
|
|
2013-08-27 16:49:48 +00:00
|
|
|
list<expr> const & operator_info::get_denotations() const { lean_assert(m_ptr); return m_ptr->m_exprs; }
|
2013-08-12 01:06:37 +00:00
|
|
|
|
|
|
|
fixity operator_info::get_fixity() const { lean_assert(m_ptr); return m_ptr->m_fixity; }
|
|
|
|
|
|
|
|
unsigned operator_info::get_precedence() const { lean_assert(m_ptr); return m_ptr->m_precedence; }
|
|
|
|
|
|
|
|
name const & operator_info::get_op_name() const { lean_assert(m_ptr); return car(m_ptr->m_op_parts); }
|
|
|
|
|
|
|
|
list<name> const & operator_info::get_op_name_parts() const { lean_assert(m_ptr); return m_ptr->m_op_parts; }
|
|
|
|
|
2013-09-03 17:09:19 +00:00
|
|
|
bool operator_info::is_safe_ascii() const {
|
|
|
|
auto l = get_op_name_parts();
|
|
|
|
return std::all_of(l.begin(), l.end(), [](name const & p) { return p.is_safe_ascii(); });
|
|
|
|
}
|
|
|
|
|
2013-08-12 01:06:37 +00:00
|
|
|
operator_info operator_info::copy() const { return operator_info(new imp(*m_ptr)); }
|
|
|
|
|
2013-08-14 23:35:04 +00:00
|
|
|
bool operator==(operator_info const & op1, operator_info const & op2) {
|
|
|
|
if ((op1.m_ptr == nullptr) != (op2.m_ptr == nullptr))
|
|
|
|
return false;
|
|
|
|
if (op1.m_ptr)
|
|
|
|
return op1.m_ptr->is_eq(*(op2.m_ptr));
|
|
|
|
else
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-08-16 01:54:01 +00:00
|
|
|
operator_info infix(name const & op, unsigned precedence) {
|
|
|
|
return operator_info(new operator_info::imp(op, fixity::Infix, precedence));
|
|
|
|
}
|
2013-08-12 01:06:37 +00:00
|
|
|
operator_info infixr(name const & op, unsigned precedence) {
|
2013-08-15 15:52:10 +00:00
|
|
|
return operator_info(new operator_info::imp(op, fixity::Infixr, precedence));
|
2013-08-12 01:06:37 +00:00
|
|
|
}
|
|
|
|
operator_info infixl(name const & op, unsigned precedence) {
|
2013-08-15 15:52:10 +00:00
|
|
|
return operator_info(new operator_info::imp(op, fixity::Infixl, precedence));
|
2013-08-12 01:06:37 +00:00
|
|
|
}
|
|
|
|
operator_info prefix(name const & op, unsigned precedence) {
|
2013-08-15 15:52:10 +00:00
|
|
|
return operator_info(new operator_info::imp(op, fixity::Prefix, precedence));
|
2013-08-12 01:06:37 +00:00
|
|
|
}
|
|
|
|
operator_info postfix(name const & op, unsigned precedence) {
|
2013-08-15 15:52:10 +00:00
|
|
|
return operator_info(new operator_info::imp(op, fixity::Postfix, precedence));
|
2013-08-12 01:06:37 +00:00
|
|
|
}
|
|
|
|
operator_info mixfixl(unsigned num_parts, name const * parts, unsigned precedence) {
|
|
|
|
lean_assert(num_parts > 1); return operator_info(new operator_info::imp(num_parts, parts, fixity::Mixfixl, precedence));
|
|
|
|
}
|
|
|
|
operator_info mixfixr(unsigned num_parts, name const * parts, unsigned precedence) {
|
|
|
|
lean_assert(num_parts > 1); return operator_info(new operator_info::imp(num_parts, parts, fixity::Mixfixr, precedence));
|
|
|
|
}
|
|
|
|
operator_info mixfixc(unsigned num_parts, name const * parts, unsigned precedence) {
|
|
|
|
lean_assert(num_parts > 1); return operator_info(new operator_info::imp(num_parts, parts, fixity::Mixfixc, precedence));
|
|
|
|
}
|
2013-08-27 17:09:46 +00:00
|
|
|
operator_info mixfixo(unsigned num_parts, name const * parts, unsigned precedence) {
|
|
|
|
lean_assert(num_parts > 1); return operator_info(new operator_info::imp(num_parts, parts, fixity::Mixfixo, precedence));
|
|
|
|
}
|
2013-08-12 01:06:37 +00:00
|
|
|
|
2013-08-17 01:34:11 +00:00
|
|
|
char const * to_string(fixity f) {
|
|
|
|
switch (f) {
|
|
|
|
case fixity::Infix: return "Infix";
|
|
|
|
case fixity::Infixl: return "Infixl";
|
|
|
|
case fixity::Infixr: return "Infixr";
|
|
|
|
case fixity::Prefix: return "Prefix";
|
|
|
|
case fixity::Postfix: return "Postfix";
|
|
|
|
case fixity::Mixfixl: return "Mixfixl";
|
|
|
|
case fixity::Mixfixr: return "Mixfixr";
|
|
|
|
case fixity::Mixfixc: return "Mixfixc";
|
2013-08-27 17:09:46 +00:00
|
|
|
case fixity::Mixfixo: return "Mixfixo";
|
2013-08-17 01:34:11 +00:00
|
|
|
}
|
2013-11-11 17:19:38 +00:00
|
|
|
lean_unreachable(); // LCOV_EXCL_LINE
|
2013-08-17 01:34:11 +00:00
|
|
|
}
|
2013-08-12 01:06:37 +00:00
|
|
|
|
2013-08-13 15:18:01 +00:00
|
|
|
format pp(operator_info const & o) {
|
2013-08-12 01:06:37 +00:00
|
|
|
format r;
|
2013-08-27 22:59:13 +00:00
|
|
|
switch (o.get_fixity()) {
|
|
|
|
case fixity::Infix:
|
|
|
|
case fixity::Infixl:
|
|
|
|
case fixity::Infixr:
|
|
|
|
r = highlight_command(format(to_string(o.get_fixity())));
|
|
|
|
if (o.get_precedence() > 1)
|
|
|
|
r += format{space(), format(o.get_precedence())};
|
|
|
|
r += format{space(), format(o.get_op_name())};
|
|
|
|
return r;
|
|
|
|
case fixity::Prefix:
|
|
|
|
case fixity::Postfix:
|
|
|
|
case fixity::Mixfixl:
|
|
|
|
case fixity::Mixfixr:
|
|
|
|
case fixity::Mixfixc:
|
|
|
|
case fixity::Mixfixo:
|
|
|
|
r = highlight_command(format("Notation"));
|
|
|
|
if (o.get_precedence() > 1)
|
|
|
|
r += format{space(), format(o.get_precedence())};
|
|
|
|
switch (o.get_fixity()) {
|
|
|
|
case fixity::Prefix:
|
|
|
|
r += format{space(), format(o.get_op_name()), space(), format("_")};
|
|
|
|
return r;
|
|
|
|
case fixity::Postfix:
|
|
|
|
r += format{space(), format("_"), space(), format(o.get_op_name())};
|
|
|
|
return r;
|
|
|
|
case fixity::Mixfixl:
|
|
|
|
for (auto p : o.get_op_name_parts())
|
|
|
|
r += format{space(), format(p), space(), format("_")};
|
|
|
|
return r;
|
|
|
|
case fixity::Mixfixr:
|
|
|
|
for (auto p : o.get_op_name_parts())
|
|
|
|
r += format{space(), format("_"), space(), format(p)};
|
|
|
|
return r;
|
|
|
|
case fixity::Mixfixc: {
|
|
|
|
auto parts = o.get_op_name_parts();
|
|
|
|
r += format{space(), format(head(parts))};
|
|
|
|
for (auto p : tail(parts))
|
|
|
|
r += format{space(), format("_"), space(), format(p)};
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
case fixity::Mixfixo:
|
|
|
|
for (auto p : o.get_op_name_parts())
|
|
|
|
r += format{space(), format("_"), space(), format(p)};
|
|
|
|
r += format{space(), format("_")};
|
|
|
|
return r;
|
2013-11-11 17:19:38 +00:00
|
|
|
default: lean_unreachable(); // LCOV_EXCL_LINE
|
2013-08-27 22:59:13 +00:00
|
|
|
}
|
|
|
|
}
|
2013-11-11 17:19:38 +00:00
|
|
|
lean_unreachable(); // LCOV_EXCL_LINE
|
2013-08-12 01:06:37 +00:00
|
|
|
}
|
|
|
|
|
2013-08-17 01:34:11 +00:00
|
|
|
char const * notation_declaration::keyword() const {
|
|
|
|
return to_string(m_op.get_fixity());
|
|
|
|
}
|
|
|
|
|
2013-12-28 22:39:10 +00:00
|
|
|
void notation_declaration::write(serializer & s) const {
|
|
|
|
auto parts = m_op.get_op_name_parts();
|
|
|
|
s << "Notation" << length(parts);
|
|
|
|
for (auto n : parts)
|
|
|
|
s << n;
|
|
|
|
s << static_cast<char>(m_op.get_fixity()) << m_op.get_precedence() << m_expr;
|
|
|
|
}
|
|
|
|
static void read_notation(environment const & env, io_state const & ios, deserializer & d) {
|
|
|
|
buffer<name> parts;
|
|
|
|
unsigned num = d.read_unsigned();
|
|
|
|
for (unsigned i = 0; i < num; i++)
|
|
|
|
parts.push_back(read_name(d));
|
|
|
|
fixity fx = static_cast<fixity>(d.read_char());
|
|
|
|
unsigned p = d.read_unsigned();
|
|
|
|
expr e = read_expr(d);
|
|
|
|
switch (fx) {
|
|
|
|
case fixity::Infix: lean_assert(parts.size() == 1); add_infix(env, ios, parts[0], p, e); return;
|
|
|
|
case fixity::Infixl: lean_assert(parts.size() == 1); add_infixl(env, ios, parts[0], p, e); return;
|
|
|
|
case fixity::Infixr: lean_assert(parts.size() == 1); add_infixr(env, ios, parts[0], p, e); return;
|
|
|
|
case fixity::Prefix: lean_assert(parts.size() == 1); add_prefix(env, ios, parts[0], p, e); return;
|
|
|
|
case fixity::Postfix: lean_assert(parts.size() == 1); add_postfix(env, ios, parts[0], p, e); return;
|
|
|
|
case fixity::Mixfixl: add_mixfixl(env, ios, parts.size(), parts.data(), p, e); return;
|
|
|
|
case fixity::Mixfixr: add_mixfixr(env, ios, parts.size(), parts.data(), p, e); return;
|
|
|
|
case fixity::Mixfixc: add_mixfixc(env, ios, parts.size(), parts.data(), p, e); return;
|
|
|
|
case fixity::Mixfixo: add_mixfixo(env, ios, parts.size(), parts.data(), p, e); return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
static object_cell::register_deserializer_fn notation_ds("Notation", read_notation);
|
|
|
|
|
2013-08-12 01:06:37 +00:00
|
|
|
std::ostream & operator<<(std::ostream & out, operator_info const & o) {
|
|
|
|
out << pp(o);
|
|
|
|
return out;
|
|
|
|
}
|
2013-12-10 20:52:31 +00:00
|
|
|
|
2013-12-10 21:09:35 +00:00
|
|
|
io_state_stream const & operator<<(io_state_stream const & out, operator_info const & o) {
|
|
|
|
out.get_stream() << mk_pair(pp(o), out.get_options());
|
2013-12-10 20:52:31 +00:00
|
|
|
return out;
|
|
|
|
}
|
2013-08-12 01:06:37 +00:00
|
|
|
}
|