1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
use super::imports::{ancestor_path, import_path};
use super::in_own_submodule;
use crate::codegen::template::concept::archetype_module::{
code_archetype_module, ArchetypeModuleConfig,
};
use crate::tao::form::{Crate, CrateExtension, Module, ModuleExtension};
use crate::tao::perspective::{BuildInfo, BuildInfoExtension, KnowledgeGraphNode};
use crate::tao::Implement;
use std::rc::Rc;
use zamm_yin::node_wrappers::CommonNodeTrait;
use zamm_yin::tao::archetype::{Archetype, ArchetypeFormTrait};
/// Generate code for a given module. Post-processing still needed.
pub fn code_module(request: Implement, module: Module, parent: Archetype) -> String {
let mut archetype_names = vec![];
let mut public_submodules = vec![];
let mut private_submodules = vec![];
let mut re_exports = vec![];
let parent_node = KnowledgeGraphNode::from(parent.id());
if parent_node.is_newly_defined() {
archetype_names.push(parent.internal_name_str().unwrap());
} else if parent_node.is_imported() {
// Parent is already defined as part of a dependency, we're only creating this crate so
// that we can access the children as well. In which case, we should also re-export the
// concepts defined in the dependency, so that the end consumer does not depend directly on
// the dependency.
//
// However, we shouldn't simply re-export the Yin submodule, because otherwise we will end
// up with duplicate submodules, and that messes up rustdoc generation. So, we should
// re-export only the children that were defined in Yin.
//
// Re-exporting all concepts that aren't newly defined won't work, because this includes a
// lot of the concepts that are loaded on Yang startup. They were newly defined when the
// generating Yang was first built, but now that that version of Yang is built and building
// the next version of Yang in turn, those previously built concepts are no longer newly
// defined. Moreover, they were defined as part of previous Yang, not previous Yin, so
// re-exporting them as part of Yin won't work.
//
// Storing Yin build information during Yin generation, and then loading that back up
// on Yang startup, won't work either because that's previous Yin's build information.
// We're building for a future Yang that might depend on a future Yin, not on the Yin that
// the current Yang depends on, so we can't just rely on the build information stored in
// the Yin dependency.
//
// Instead, this needs to be a re-export of the *currently* imported Yin concepts. Note
// that for this to be successful, the newly defined concepts have to be children of the
// imported concepts, not children of Yang's initialized concepts from a previous build.
if Crate::yang().version_at_least(0, 1, 8) {
re_exports.push(import_path(&parent_node, false));
for child in parent.child_archetypes() {
let child_node = KnowledgeGraphNode::from(child.id());
if child_node.is_imported() && !in_own_submodule(&child) {
re_exports.push(import_path(&child_node, false));
}
}
} else {
// backwards compatible functionality
re_exports.push(format!("zamm_yin::{}::*", ancestor_path(&parent, "::")));
}
}
for child in parent.child_archetypes() {
if in_own_submodule(&child) {
let child_submodule = match BuildInfo::from(child.id()).representative_module() {
Some(existing_module) => existing_module,
None => continue,
};
public_submodules.push(
(*ModuleExtension::implementation_name(&child_submodule).unwrap()).to_owned(),
);
} else if KnowledgeGraphNode::from(child.id()).is_newly_defined() {
archetype_names.push(child.internal_name_str().unwrap());
} // else, if this child doesn't have their own module, and has also been already defined,
// then we will have already set them for re-export earlier
}
for submodule in module.submodules() {
private_submodules.push((*submodule.implementation_name().unwrap()).to_owned());
}
for re_export in module.re_exports() {
re_exports.push((*re_export).to_owned());
}
let doc = request.documentation().map(|rc| Rc::from(rc.as_str()));
code_archetype_module(&ArchetypeModuleConfig {
doc,
archetype_names,
private_submodules,
public_submodules,
re_exports,
})
}