Skip to content

Commit e64bcff

Browse files
committed
feat(tactic): make docstrings of imported modules accessible
1 parent 80c1b4d commit e64bcff

File tree

7 files changed

+81
-36
lines changed

7 files changed

+81
-36
lines changed

library/init/meta/tactic.lean

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -543,7 +543,7 @@ It updates the environment in the tactic_state, and returns an expression of the
543543
where l_i's and a_j's are the collected dependencies.
544544
-/
545545
meta constant add_aux_decl (c : name) (type : expr) (val : expr) (is_lemma : bool) : tactic expr
546-
meta constant module_doc_strings : tactic (list (option name × string))
546+
meta constant module_doc_strings : tactic (list (option string × string))
547547
/-- Set attribute `attr_name` for constant `c_name` with the given priority.
548548
If the priority is none, then use default -/
549549
meta constant set_basic_attribute (attr_name : name) (c_name : name) (persistent := ff) (prio : option nat := none) : tactic unit

src/library/documentation.cpp

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ Author: Leonardo de Moura
1515
namespace lean {
1616
struct documentation_ext : public environment_extension {
1717
/** Doc string for the current module being processed. It does not include imported doc strings. */
18-
list<doc_entry> m_module_doc;
18+
optional<std::string> m_module_doc;
1919
/** Doc strings for declarations (including imported ones). We store doc_strings for declarations in the .olean files. */
2020
name_map<std::string> m_doc_string_map;
2121
};
@@ -36,25 +36,16 @@ static environment update(environment const & env, documentation_ext const & ext
3636
struct doc_modification : public modification {
3737
LEAN_MODIFICATION("doc")
3838

39-
/** If non-empty, this is a doc on a declaration. Otherwise,
40-
* it's a doc on the whole module. */
4139
name m_decl;
4240
std::string m_doc;
4341

4442
doc_modification() {}
45-
/** A docstring for the entire module. */
46-
doc_modification(std::string const & doc) : m_decl(""), m_doc(doc) {}
4743
/** A docstring for a declaration in the module. */
4844
doc_modification(name const & decl, std::string const & doc) : m_decl(decl), m_doc(doc) {}
4945

5046
void perform(environment & env) const override {
5147
auto ext = get_extension(env);
52-
if (m_decl != "") {
53-
ext.m_doc_string_map.insert(m_decl, m_doc);
54-
}
55-
// Note that we do NOT add anything to `m_module_doc` here, because `perform` is called
56-
// when applying modifications from imported .olean modules whose doc strings are NOT
57-
// part of the current module's documentation.
48+
ext.m_doc_string_map.insert(m_decl, m_doc);
5849
env = update(env, ext);
5950
}
6051

@@ -179,9 +170,13 @@ static std::string process_doc(std::string s) {
179170
environment add_module_doc_string(environment const & env, std::string doc) {
180171
doc = process_doc(doc);
181172
auto ext = get_extension(env);
182-
ext.m_module_doc = cons(doc_entry(doc), ext.m_module_doc);
173+
if (ext.m_module_doc) {
174+
*ext.m_module_doc += "\n" + doc;
175+
} else {
176+
ext.m_module_doc = doc;
177+
}
183178
auto new_env = update(env, ext);
184-
return module::add(new_env, std::make_shared<doc_modification>(doc));
179+
return module::add_doc_string(new_env, doc);
185180
}
186181

187182
environment add_doc_string(environment const & env, name const & n, std::string doc) {
@@ -191,7 +186,6 @@ environment add_doc_string(environment const & env, name const & n, std::string
191186
throw exception(sstream() << "environment already contains a doc string for '" << n << "'");
192187
}
193188
ext.m_doc_string_map.insert(n, doc);
194-
ext.m_module_doc = cons(doc_entry(n, doc), ext.m_module_doc);
195189
auto new_env = update(env, ext);
196190
return module::add(new_env, std::make_shared<doc_modification>(n, doc));
197191
}
@@ -204,10 +198,15 @@ optional<std::string> get_doc_string(environment const & env, name const & n) {
204198
return optional<std::string>();
205199
}
206200

207-
void get_module_doc_strings(environment const & env, buffer<doc_entry> & result) {
201+
void get_module_doc_strings(environment const & env, buffer<mod_doc_entry> & result) {
208202
auto ext = get_extension(env);
209-
to_buffer(ext.m_module_doc, result);
210-
std::reverse(result.begin(), result.end());
203+
auto const & mod_docs = module::get_doc_strings(env);
204+
for (auto const & pr : mod_docs) {
205+
result.push_back({ optional<std::string>{ pr.first }, pr.second });
206+
}
207+
if (ext.m_module_doc) {
208+
result.push_back({ {}, *ext.m_module_doc });
209+
}
211210
}
212211

213212
void initialize_documentation() {

src/library/documentation.h

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,14 @@ Author: Leonardo de Moura
88
#include <string>
99
#include "kernel/environment.h"
1010
namespace lean {
11-
class doc_entry {
12-
optional<name> m_decl_name;
13-
std::string m_doc;
14-
public:
15-
doc_entry(std::string const & doc):m_doc(doc) {}
16-
doc_entry(name const & decl_name, std::string const & doc):m_decl_name(decl_name), m_doc(doc) {}
17-
optional<name> const & get_decl_name() const { return m_decl_name; }
18-
std::string const & get_doc() const { return m_doc; }
11+
struct mod_doc_entry {
12+
optional<std::string> m_mod_name;
13+
std::string m_doc;
1914
};
2015
environment add_module_doc_string(environment const & env, std::string doc);
2116
environment add_doc_string(environment const & env, name const & n, std::string);
2217
optional<std::string> get_doc_string(environment const & env, name const & n);
23-
void get_module_doc_strings(environment const & env, buffer<doc_entry> & result);
18+
void get_module_doc_strings(environment const & env, buffer<mod_doc_entry> & result);
2419
void initialize_documentation();
2520
void finalize_documentation();
2621
}

src/library/module.cpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,11 @@ struct module_ext : public environment_extension {
8686
list<name> m_module_decls;
8787
name_set m_module_defs;
8888
name_set m_imported;
89+
/** Top-level doc strings for modules which have them. Lean doesn't have a notion
90+
* of module different from that of a source file, so we use file names to index
91+
* the docstring map. */
92+
// TODO(Vtec234): lean::rb_map misbehaves here for some reason
93+
std::map<std::string, std::string> m_module_docs;
8994
// Map from declaration name to olean file where it was defined
9095
name_map<std::string> m_decl2olean;
9196
name_map<pos_info> m_decl2pos_info;
@@ -416,6 +421,30 @@ struct quot_modification : public modification {
416421
}
417422
};
418423

424+
struct mod_doc_modification : public modification {
425+
LEAN_MODIFICATION("mod_doc")
426+
427+
std::string m_doc;
428+
429+
mod_doc_modification() {}
430+
/** A docstring for a declaration in the module. */
431+
mod_doc_modification(std::string const & doc) : m_doc(doc) {}
432+
433+
void perform(environment & env) const override {
434+
// No-op. See `import_module` for actual action
435+
}
436+
437+
void serialize(serializer & s) const override {
438+
s << m_doc;
439+
}
440+
441+
static std::shared_ptr<modification const> deserialize(deserializer & d) {
442+
std::string doc;
443+
d >> doc;
444+
return std::make_shared<mod_doc_modification>(doc);
445+
}
446+
};
447+
419448
namespace module {
420449
environment add(environment const & env, std::shared_ptr<modification const> const & modf) {
421450
module_ext ext = get_extension(env);
@@ -506,6 +535,14 @@ environment add(environment const & env, certified_declaration const & d) {
506535
return add_decl_pos_info(new_env, _d.get_name());
507536
}
508537

538+
environment add_doc_string(environment const & env, std::string const & doc) {
539+
return add(env, std::make_shared<mod_doc_modification>(doc));
540+
}
541+
542+
std::map<std::string, std::string> const & get_doc_strings(environment const & env) {
543+
return get_extension(env).m_module_docs;
544+
}
545+
509546
bool is_definition(environment const & env, name const & n) {
510547
module_ext const & ext = get_extension(env);
511548
return ext.m_module_defs.contains(n);
@@ -693,6 +730,14 @@ void import_module(modification_list const & modifications, std::string const &
693730
env = add_decl_olean(env, dm->m_decl.get_name(), file_name);
694731
} else if (auto im = dynamic_cast<inductive_modification const *>(m.get())) {
695732
env = add_decl_olean(env, im->m_decl.get_decl().m_name, file_name);
733+
} else if (auto mdm = dynamic_cast<mod_doc_modification const *>(m.get())) {
734+
auto ext = get_extension(env);
735+
if (ext.m_module_docs.count(file_name) != 0) {
736+
ext.m_module_docs[file_name] += "\n" + mdm->m_doc;
737+
} else {
738+
ext.m_module_docs[file_name] = mdm->m_doc;
739+
}
740+
env = update(env, ext);
696741
}
697742
}
698743
}
@@ -724,13 +769,15 @@ void initialize_module() {
724769
inductive_modification::init();
725770
quot_modification::init();
726771
pos_info_mod::init();
772+
mod_doc_modification::init();
727773
}
728774

729775
void finalize_module() {
730776
quot_modification::finalize();
731777
pos_info_mod::finalize();
732778
inductive_modification::finalize();
733779
decl_modification::finalize();
780+
mod_doc_modification::finalize();
734781
delete g_object_readers;
735782
delete g_ext;
736783
}

src/library/module.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ Author: Leonardo de Moura
99
#include <iostream>
1010
#include <utility>
1111
#include <vector>
12+
#include <map>
1213
#include "util/serializer.h"
1314
#include "util/optional.h"
1415
#include "kernel/pos_info_provider.h"
@@ -143,6 +144,12 @@ environment add_and_perform(environment const & env, std::shared_ptr<modificatio
143144
/** \brief Add the given declaration to the environment, and mark it to be exported. */
144145
environment add(environment const & env, certified_declaration const & d);
145146

147+
/** \brief Adds a module-level doc to the current module. */
148+
environment add_doc_string(environment const & env, std::string const & doc);
149+
150+
/** \brief Returns the map of module-level docs indexed by source file name. */
151+
std::map<std::string, std::string> const & get_doc_strings(environment const & env);
152+
146153
/** \brief Return true iff \c n is a definition added to the current module using #module::add */
147154
bool is_definition(environment const & env, name const & n);
148155

src/library/tactic/tactic_state.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -758,21 +758,21 @@ vm_obj tactic_add_doc_string(vm_obj const & n, vm_obj const & doc, vm_obj const
758758
}
759759
}
760760

761-
/* meta constant module_doc_strings : tactic (list (option name × string)) */
761+
/* meta constant module_doc_strings : tactic (list (option string × string)) */
762762
vm_obj tactic_module_doc_strings(vm_obj const & _s) {
763763
tactic_state const & s = tactic::to_state(_s);
764-
buffer<doc_entry> entries;
764+
buffer<mod_doc_entry> entries;
765765
get_module_doc_strings(s.env(), entries);
766766
unsigned i = entries.size();
767767
vm_obj r = mk_vm_simple(0);
768768
while (i > 0) {
769769
--i;
770770
vm_obj decl_name;
771-
if (auto d = entries[i].get_decl_name())
771+
if (auto d = entries[i].m_mod_name)
772772
decl_name = mk_vm_some(to_obj(*d));
773773
else
774774
decl_name = mk_vm_none();
775-
vm_obj doc = to_obj(entries[i].get_doc());
775+
vm_obj doc = to_obj(entries[i].m_doc);
776776
vm_obj e = mk_vm_pair(decl_name, doc);
777777
r = mk_vm_constructor(1, e, r);
778778
}
Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
Makes foo.
22
Makes foo of foo.
33
Doesn't make foo.
4-
[(none, This module has a doc..),
5-
(none, ..or two.),
6-
((some foo.a), Makes foo.),
7-
((some foo.b), Makes foo of foo.),
8-
((some two), Doesn't make foo.)]
4+
[(none, This module has a doc..
5+
..or two.)]

0 commit comments

Comments
 (0)