/* Copyright (c) 2015 Microsoft Corporation. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Author: Leonardo de Moura */ #include "library/attribute_manager.h" #include "library/constants.h" #include "library/normalize.h" #include "library/num.h" #include "library/typed_expr.h" #include "frontends/lean/decl_attributes.h" #include "frontends/lean/parser.h" #include "frontends/lean/tokens.h" #include "frontends/lean/util.h" namespace lean { void decl_attributes::parse(parser & p) { if (!p.curr_is_token(get_lbracket_tk())) return; p.next(); while (true) { auto pos = p.pos(); bool deleted = p.curr_is_token_or_id(get_sub_tk()); if (deleted) { if (m_persistent) throw parser_error("cannot remove attribute globally (solution: use 'local attribute')", pos); p.next(); } auto name = p.check_id_next("invalid attribute declaration, identifier expected"); if (name == "priority") { if (deleted) throw parser_error("cannot remove priority attribute", pos); auto pos = p.pos(); expr pre_val = p.parse_expr(); pre_val = mk_typed_expr(mk_constant(get_num_name()), pre_val); expr val = p.elaborate(list(), pre_val).first; val = normalize(p.env(), val); if (optional mpz_val = to_num_core(val)) { if (!mpz_val->is_unsigned_int()) throw parser_error("invalid 'priority', argument does not fit in a machine integer", pos); m_prio = optional(mpz_val->get_unsigned_int()); } else { throw parser_error("invalid 'priority', argument does not evaluate to a numeral", pos); } } else { if (!is_attribute(p.env(), name)) throw parser_error(sstream() << "unknown attribute [" << name << "]", pos); auto const & attr = get_attribute(p.env(), name); if (!deleted) { for (auto const & entry : m_entries) { if (!entry.deleted() && are_incompatible(*entry.m_attr, attr)) { throw parser_error(sstream() << "invalid attribute [" << name << "], declaration was already marked with [" << entry.m_attr->get_name() << "]", pos); } } } auto data = deleted ? attr_data_ptr() : attr.parse_data(p); m_entries = cons({&attr, data}, m_entries); if (name == "parsing_only") m_parsing_only = true; } if (p.curr_is_token(get_comma_tk())) { p.next(); } else { p.check_token_next(get_rbracket_tk(), "invalid attribute declaration, ']' expected"); if (p.curr_is_token(get_lbracket_tk())) p.next(); else break; } } } environment decl_attributes::apply(environment env, io_state const & ios, name const & d) const { buffer entries; to_buffer(m_entries, entries); unsigned i = entries.size(); while (i > 0) { --i; auto const & entry = entries[i]; if (entry.deleted()) { if (!entry.m_attr->is_instance(env, d)) throw exception(sstream() << "cannot remove attribute [" << entry.m_attr->get_name() << "]: no prior declaration on " << d); env = entry.m_attr->unset(env, ios, d, m_persistent); } else { unsigned prio = m_prio ? *m_prio : LEAN_DEFAULT_PRIORITY; env = entry.m_attr->set_untyped(env, ios, d, prio, entry.m_params, m_persistent); } } return env; } bool decl_attributes::ok_for_inductive_type() const { for (entry const & e : m_entries) if (e.m_attr->get_name() != "class" || e.deleted()) return false; return true; } bool decl_attributes::has_class() const { for (entry const & e : m_entries) if (e.m_attr->get_name() == "class" && !e.deleted()) return true; return false; } }