Skip to main content

knave_expand/expand/
module_survey.rs

1use 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}