Skip to main content

knave_expand/expand/
mod.rs

1mod budget_arena;
2mod classified_form;
3mod compile_time_check;
4mod context;
5mod defining_call;
6mod documented_terms;
7mod evaluated_forms;
8mod expression;
9mod failed_definition;
10mod field_keyword;
11mod form_budget;
12mod generated_entry;
13mod globals;
14mod host;
15mod introduced;
16mod macro_call;
17mod macro_function;
18mod macro_origins;
19mod misplaced_definition;
20mod module_body;
21mod module_loading;
22mod module_notes;
23mod module_survey;
24mod names;
25mod prelude_state;
26mod problems;
27mod recorded_inputs;
28mod recur_check;
29mod rest_of_body;
30mod result_printer;
31mod returned_arguments;
32mod rust_clauses;
33mod rust_type;
34mod saved_definitions;
35mod saved_index;
36mod saved_notes;
37mod saved_values;
38mod session;
39mod shape;
40mod sourced_items;
41mod spliced_forms;
42mod string_view;
43mod structural_clause;
44mod top_level_form;
45mod try_check;
46mod type_expr;
47mod type_parameters;
48
49use std::rc::Rc;
50
51use rustc_hash::{FxHashMap, FxHashSet};
52
53use crate::core::{
54    BindingArena, BindingId, BindingKind, CoreModule, ModuleId, ModulePath, References,
55};
56use crate::diagnostic::{Diagnostic, Diagnostics};
57use crate::interpret::{Closure, Value};
58use crate::modules::{ModuleRegistry, ModuleSources};
59use crate::reader::Form;
60use crate::scope::{BindingTable, Phase, Scope, ScopeAllocator};
61use crate::source::{SourceId, SourceMap, Span};
62use budget_arena::BudgetArena;
63pub use classified_form::ClassifiedForm;
64use evaluated_forms::EvaluatedForms;
65pub use generated_entry::GeneratedEntry;
66use globals::{GlobalTable, LoweredGlobals};
67pub use macro_call::MacroOrigin;
68use macro_call::MacroTable;
69pub use macro_origins::MacroOrigins;
70use module_notes::ModuleNotes;
71pub use module_survey::ModuleSurvey;
72pub use prelude_state::{PreludeState, UnreadablePrelude};
73pub use problems::{ExpandProblems, SetAsideInput};
74use recorded_inputs::RecordedInputs;
75pub use recorded_inputs::{BoundName, LoadedModule};
76pub use result_printer::{GeneratedFunction, ResultPrinter};
77pub use saved_definitions::PendingDefinitions;
78use saved_definitions::{DefinitionSaver, SavedDefinitions, SavedTables};
79use saved_values::SavedValues;
80pub use session::ExpansionSession;
81use string_view::StringViewSearch;
82
83pub struct Program {
84    pub modules: Vec<CoreModule>,
85    pub entry: ModuleId,
86    pub entry_function: Option<BindingId>,
87    pub bindings: BindingArena,
88    pub macro_origins: Rc<MacroOrigins>,
89    pub macro_helpers: FxHashSet<BindingId>,
90    pub string_view: Option<BindingId>,
91    pub checked_roots: Vec<BindingId>,
92    pub pending_definitions: PendingDefinitions,
93    pub warnings: Diagnostics,
94    pub expansion: ExpansionWork,
95}
96
97#[derive(Clone, Copy, Default)]
98pub struct ExpansionWork {
99    pub lowered_forms: usize,
100}
101
102impl Program {
103    pub(super) const WRITTEN_ENTRY_FUNCTION: &str = "main";
104
105    pub fn entry_module(&self) -> &CoreModule {
106        self.modules
107            .iter()
108            .find(|module| module.id == self.entry)
109            .expect("the entry module is expanded")
110    }
111
112    pub fn prelude_macro_helpers(&self) -> FxHashSet<BindingId> {
113        let prelude: FxHashSet<ModuleId> = self
114            .modules
115            .iter()
116            .filter(|module| ModuleSources::is_prelude(&module.path))
117            .map(|module| module.id)
118            .collect();
119        let is_prelude_global = |binding: BindingId| {
120            matches!(self.bindings.get(binding).kind(),
121                BindingKind::Global(module) if prelude.contains(&module))
122        };
123        self.macro_helpers
124            .iter()
125            .copied()
126            .filter(|binding| self.bindings.is_saved(*binding) || is_prelude_global(*binding))
127            .collect()
128    }
129
130    pub fn check_also(&mut self, binding: BindingId) {
131        self.checked_roots.push(binding);
132        self.pending_definitions
133            .restore(&mut self.modules, vec![binding]);
134    }
135
136    fn restore_reached(&mut self) {
137        let roots = self
138            .modules
139            .iter()
140            .flat_map(CoreModule::definitions)
141            .flat_map(|(_, value)| References::of(value, &self.bindings).into_globals())
142            .collect();
143        self.pending_definitions.restore(&mut self.modules, roots);
144    }
145
146    fn written_entry_function(&self) -> Option<BindingId> {
147        self.entry_module()
148            .definitions()
149            .map(|(binding, _)| binding)
150            .find(|binding| self.bindings.get(*binding).name() == Self::WRITTEN_ENTRY_FUNCTION)
151    }
152}
153
154#[derive(Clone, serde::Serialize, serde::Deserialize)]
155pub struct TraitMethods {
156    pub rust_name: Rc<str>,
157    pub self_variable: crate::core::BindingId,
158    pub associated: Vec<(crate::core::BindingId, Rc<str>)>,
159    pub methods: Vec<(crate::core::BindingId, crate::core::TypeExpr)>,
160    pub defaults: rustc_hash::FxHashSet<crate::core::BindingId>,
161}
162
163pub struct Expander<'s> {
164    sources: &'s mut SourceMap,
165    module_sources: ModuleSources,
166    modules: ModuleRegistry,
167    tables: ExpansionTables,
168    current_module: Option<ModuleId>,
169    diagnostics: Diagnostics,
170    warnings: Diagnostics,
171    reported_hidden_modules: Vec<std::path::PathBuf>,
172    library_modules: Vec<(ModulePath, Rc<str>)>,
173    phase: Phase,
174    expansion_depth: usize,
175    nesting_depth: usize,
176    form_budgets: BudgetArena,
177    recovered_diagnostics: Vec<Diagnostic>,
178    type_note_shown: bool,
179    saved_prelude: Option<PreludeState>,
180    saved_definitions: SavedDefinitions,
181    saved_macros: SavedValues<Closure>,
182    saved_globals: SavedValues<Value>,
183    expansion: ExpansionWork,
184    evaluated_forms: EvaluatedForms,
185    recorded_inputs: RecordedInputs,
186    declared_definitions: Vec<failed_definition::DeclaredName>,
187    failed_body_definitions: Vec<BindingId>,
188    introductions: Vec<Scope>,
189    duplicate_definitions: FxHashSet<(ModuleId, Rc<str>)>,
190}
191
192#[derive(Default, serde::Serialize, serde::Deserialize)]
193struct ExpansionTables {
194    scopes: ScopeAllocator,
195    local_scopes: FxHashSet<Scope>,
196    use_site_scopes: FxHashSet<Scope>,
197    table: BindingTable,
198    bindings: BindingArena,
199    macros: MacroTable,
200    macro_origins: MacroOrigins,
201    introduction_scopes: FxHashSet<Scope>,
202    global_macros: Vec<(crate::core::BindingId, Form)>,
203    trait_paths: FxHashMap<crate::core::BindingId, Rc<str>>,
204    structural_paths: FxHashMap<Rc<str>, (crate::core::BindingId, Span)>,
205    enum_variants: FxHashMap<crate::core::BindingId, Vec<crate::core::BindingId>>,
206    variant_fields: FxHashMap<crate::core::BindingId, Vec<Rc<str>>>,
207    trait_methods: FxHashMap<crate::core::BindingId, TraitMethods>,
208    globals: GlobalTable,
209    module_notes: ModuleNotes,
210    expanded: FxHashMap<ModuleId, CoreModule>,
211    order: Vec<ModuleId>,
212    string_view: Option<BindingId>,
213}
214
215impl ExpansionTables {
216    fn forget_locals(&mut self) {
217        let bindings = &self.bindings;
218        self.table
219            .forget(|binding| matches!(bindings.get(binding).kind(), BindingKind::Local));
220    }
221
222    fn find_string_view(&self) -> Option<BindingId> {
223        let modules = self
224            .order
225            .iter()
226            .filter_map(|id| self.expanded.get(id))
227            .filter(|module| ModuleSources::is_embedded_prelude(&module.path));
228        StringViewSearch::in_modules(modules)
229    }
230
231    fn save_definitions(&mut self) -> SavedTables {
232        let mut saver = DefinitionSaver::new(&self.bindings, self.string_view);
233        let modules = self.expanded.values_mut();
234        for module in modules.filter(|module| ModuleSources::is_embedded_prelude(&module.path)) {
235            saver.take_from(module);
236        }
237        saver.finish()
238    }
239
240    fn take_lowered_globals(&mut self) -> LoweredGlobals {
241        let definitions = self.expanded.values().flat_map(CoreModule::definitions);
242        self.globals.take_lowered(definitions)
243    }
244
245    fn restore_lowered_globals(&mut self, lowered: &LoweredGlobals) {
246        let definitions = self.expanded.values().flat_map(CoreModule::definitions);
247        self.globals.restore_lowered(lowered, definitions);
248    }
249}
250
251impl<'s> Expander<'s> {
252    pub fn new(sources: &'s mut SourceMap, module_sources: ModuleSources) -> Self {
253        Self {
254            sources,
255            module_sources,
256            modules: ModuleRegistry::default(),
257            tables: ExpansionTables::default(),
258            current_module: None,
259            diagnostics: Diagnostics::default(),
260            warnings: Diagnostics::default(),
261            reported_hidden_modules: Vec::new(),
262            library_modules: Vec::new(),
263            phase: Phase::Runtime,
264            expansion_depth: 0,
265            nesting_depth: 0,
266            form_budgets: BudgetArena::default(),
267            recovered_diagnostics: Vec::new(),
268            type_note_shown: false,
269            saved_prelude: None,
270            saved_definitions: SavedDefinitions::default(),
271            saved_macros: SavedValues::default(),
272            saved_globals: SavedValues::default(),
273            expansion: ExpansionWork::default(),
274            evaluated_forms: EvaluatedForms::default(),
275            recorded_inputs: RecordedInputs::default(),
276            declared_definitions: Vec::new(),
277            failed_body_definitions: Vec::new(),
278            introductions: Vec::new(),
279            duplicate_definitions: FxHashSet::default(),
280        }
281    }
282
283    pub fn evaluating(self, spans: impl IntoIterator<Item = Span>) -> Self {
284        Self {
285            evaluated_forms: EvaluatedForms::new(spans),
286            ..self
287        }
288    }
289
290    pub fn with_prelude(
291        sources: &'s mut SourceMap,
292        module_sources: ModuleSources,
293        prelude: PreludeState,
294    ) -> Self {
295        Self {
296            saved_prelude: Some(prelude),
297            ..Self::new(sources, module_sources)
298        }
299    }
300
301    #[inline(never)]
302    pub fn expand(mut self, path: ModulePath, entry: SourceId) -> Result<Program, Diagnostics> {
303        let entry = self.load_source_module(path, &[entry]);
304        self.into_program(entry)
305    }
306
307    fn into_program(mut self, entry: ModuleId) -> Result<Program, Diagnostics> {
308        let diagnostics = self.take_diagnostics();
309        self.tables.macro_origins.forget_introduced_names();
310        let string_view = self
311            .tables
312            .string_view
313            .or_else(|| self.tables.find_string_view());
314        let mut program = Program {
315            modules: self.take_modules(),
316            entry,
317            entry_function: None,
318            bindings: self.tables.bindings,
319            macro_helpers: self.tables.globals.macro_helpers(),
320            string_view,
321            checked_roots: Vec::new(),
322            pending_definitions: PendingDefinitions::new(self.saved_definitions),
323            macro_origins: Rc::new(self.tables.macro_origins),
324            warnings: self.warnings,
325            expansion: self.expansion,
326        };
327        program.restore_reached();
328        program.entry_function = program.written_entry_function();
329        diagnostics.into_result(program)
330    }
331
332    fn take_diagnostics(&mut self) -> Diagnostics {
333        for diagnostic in std::mem::take(&mut self.recovered_diagnostics) {
334            self.diagnostics.push(diagnostic);
335        }
336        std::mem::take(&mut self.diagnostics)
337    }
338
339    fn fresh_local_scope(&mut self) -> Scope {
340        let scope = self.tables.scopes.fresh();
341        self.tables.local_scopes.insert(scope);
342        scope
343    }
344
345    fn quoted(&self, datum: &Form) -> Form {
346        let mut quoted = datum.clone();
347        quoted.retain_scopes(&|scope| {
348            !self.tables.local_scopes.contains(&scope)
349                && !self.tables.use_site_scopes.contains(&scope)
350        });
351        quoted
352    }
353
354    fn take_modules(&mut self) -> Vec<CoreModule> {
355        self.tables
356            .order
357            .iter()
358            .filter_map(|id| self.tables.expanded.remove(id))
359            .collect()
360    }
361}