knave_expand/expand/
module_survey.rs1use super::recorded_inputs::{BoundName, LoadedModule, RecordedInputs};
2use super::{Expander, Program};
3use crate::core::ModulePath;
4use crate::diagnostic::Diagnostics;
5use crate::source::{SourceId, Span};
6
7pub struct ModuleSurvey {
8 pub program: Result<Program, Diagnostics>,
9 pub names: Vec<Vec<BoundName>>,
10 pub loaded: Vec<LoadedModule>,
11}
12
13impl Expander<'_> {
14 pub fn survey(
15 mut self,
16 path: ModulePath,
17 sources: &[SourceId],
18 inputs: &[Span],
19 ) -> ModuleSurvey {
20 self.recorded_inputs = RecordedInputs::new(inputs.to_vec());
21 let entry = self.load_source_module(path, sources);
22 let recorded = std::mem::take(&mut self.recorded_inputs);
23 ModuleSurvey {
24 names: inputs
25 .iter()
26 .map(|input| recorded.bound_by(*input))
27 .collect(),
28 loaded: recorded.loaded().to_vec(),
29 program: self.into_program(entry),
30 }
31 }
32}
33
34#[cfg(test)]
35mod tests {
36 use std::path::PathBuf;
37
38 use super::*;
39 use crate::modules::ModuleSources;
40 use crate::source::SourceMap;
41
42 struct SurveyFixture;
43
44 impl SurveyFixture {
45 fn survey(texts: &[&str]) -> ModuleSurvey {
46 let mut sources = SourceMap::default();
47 let ids: Vec<SourceId> = texts
48 .iter()
49 .map(|text| sources.add("prompt", *text))
50 .collect();
51 let inputs: Vec<Span> = ids
52 .iter()
53 .zip(texts)
54 .map(|(id, text)| Span::new(*id, 0..text.len()))
55 .collect();
56 Expander::new(
57 &mut sources,
58 ModuleSources::new(PathBuf::new(), PathBuf::new()),
59 )
60 .survey(ModulePath::new("prompt"), &ids, &inputs)
61 }
62
63 fn names(survey: &ModuleSurvey) -> Vec<Vec<String>> {
64 survey
65 .names
66 .iter()
67 .map(|bound| bound.iter().map(|name| name.name.to_string()).collect())
68 .collect()
69 }
70 }
71
72 #[test]
73 fn a_survey_names_each_input_even_when_the_module_has_an_error() {
74 let survey = SurveyFixture::survey(&["(defn twice (x) (* 2 x))", "(defn twice (x) x)"]);
75 assert!(survey.program.is_err());
76 assert_eq!(SurveyFixture::names(&survey), [["twice"], ["twice"]]);
77 }
78
79 #[test]
80 fn a_failed_definer_binds_no_name_of_its_input() {
81 let survey = SurveyFixture::survey(&["(defn area \"doc\" (w) w)", "(area 1)"]);
82 assert!(survey.program.is_err());
83 assert_eq!(
84 SurveyFixture::names(&survey),
85 [Vec::<String>::new(), Vec::new()]
86 );
87 }
88}