mod budget_arena;
mod classified_form;
mod compile_time_check;
mod context;
mod defining_call;
mod documented_terms;
mod enclosing_index;
mod evaluated_forms;
mod expansion_limit;
mod expression;
mod failed_definition;
mod field_keyword;
mod form_budget;
mod generated_entry;
mod globals;
mod host;
mod introduced;
mod macro_call;
mod macro_function;
mod macro_origins;
mod misplaced_definition;
mod module_body;
mod module_loading;
mod module_notes;
mod module_survey;
mod names;
mod prelude_state;
mod problems;
mod recorded_inputs;
mod recur_check;
mod rest_of_body;
mod result_printer;
mod returned_arguments;
mod rust_clauses;
mod rust_type;
mod saved_definitions;
mod saved_index;
mod saved_notes;
mod saved_values;
mod session;
mod shape;
mod sourced_items;
mod spliced_forms;
mod string_view;
mod structural_clause;
mod top_level_form;
mod try_check;
mod type_expr;
mod type_parameters;
use std::rc::Rc;
use rustc_hash::{FxHashMap, FxHashSet};
use crate::core::{
BindingArena, BindingId, BindingKind, CoreModule, ModuleId, ModulePath, References,
};
use crate::diagnostic::{Diagnostic, Diagnostics};
use crate::interpret::{Closure, Value};
use crate::modules::{ModuleRegistry, ModuleSources};
use crate::reader::Form;
use crate::scope::{BindingTable, Phase, Scope, ScopeAllocator};
use crate::source::{SourceId, SourceMap, Span};
use budget_arena::BudgetArena;
pub use classified_form::ClassifiedForm;
use evaluated_forms::EvaluatedForms;
pub use generated_entry::GeneratedEntry;
use globals::{GlobalTable, LoweredGlobals};
pub use macro_call::MacroOrigin;
use macro_call::MacroTable;
pub use macro_origins::MacroOrigins;
use module_notes::ModuleNotes;
pub use module_survey::ModuleSurvey;
pub use prelude_state::{PreludeState, UnreadablePrelude};
pub use problems::{ExpandProblems, SetAsideInput};
use recorded_inputs::RecordedInputs;
pub use recorded_inputs::{BoundName, LoadedModule};
pub use result_printer::{GeneratedFunction, ResultPrinter};
pub use saved_definitions::PendingDefinitions;
use saved_definitions::{DefinitionSaver, SavedDefinitions, SavedTables};
use saved_values::SavedValues;
pub use session::ExpansionSession;
use string_view::StringViewSearch;
pub struct Program {
pub modules: Vec<CoreModule>,
pub entry: ModuleId,
pub entry_function: Option<BindingId>,
pub bindings: BindingArena,
pub macro_origins: Rc<MacroOrigins>,
pub macro_helpers: FxHashSet<BindingId>,
pub string_view: Option<BindingId>,
pub checked_roots: Vec<BindingId>,
pub pending_definitions: PendingDefinitions,
pub warnings: Diagnostics,
pub expansion: ExpansionWork,
}
#[derive(Clone, Copy, Default)]
pub struct ExpansionWork {
pub lowered_forms: usize,
}
impl Program {
pub(super) const WRITTEN_ENTRY_FUNCTION: &str = "main";
pub fn entry_module(&self) -> &CoreModule {
self.modules
.iter()
.find(|module| module.id == self.entry)
.expect("the entry module is expanded")
}
pub fn prelude_macro_helpers(&self) -> FxHashSet<BindingId> {
let prelude: FxHashSet<ModuleId> = self
.modules
.iter()
.filter(|module| ModuleSources::is_prelude(&module.path))
.map(|module| module.id)
.collect();
let is_prelude_global = |binding: BindingId| {
matches!(self.bindings.get(binding).kind(),
BindingKind::Global(module) if prelude.contains(&module))
};
self.macro_helpers
.iter()
.copied()
.filter(|binding| self.bindings.is_saved(*binding) || is_prelude_global(*binding))
.collect()
}
pub fn check_also(&mut self, binding: BindingId) {
self.checked_roots.push(binding);
self.pending_definitions
.restore(&mut self.modules, vec![binding]);
}
fn restore_reached(&mut self) {
let roots = self
.modules
.iter()
.flat_map(CoreModule::definitions)
.flat_map(|(_, value)| References::of(value, &self.bindings).into_globals())
.collect();
self.pending_definitions.restore(&mut self.modules, roots);
}
fn written_entry_function(&self) -> Option<BindingId> {
self.entry_module()
.definitions()
.map(|(binding, _)| binding)
.find(|binding| self.bindings.get(*binding).name() == Self::WRITTEN_ENTRY_FUNCTION)
}
}
#[derive(Clone, serde::Serialize, serde::Deserialize)]
pub struct TraitMethods {
pub rust_name: Rc<str>,
pub self_variable: crate::core::BindingId,
pub associated: Vec<(crate::core::BindingId, Rc<str>)>,
pub methods: Vec<(crate::core::BindingId, crate::core::TypeExpr)>,
pub defaults: rustc_hash::FxHashSet<crate::core::BindingId>,
}
pub struct Expander<'s> {
sources: &'s mut SourceMap,
module_sources: ModuleSources,
modules: ModuleRegistry,
tables: ExpansionTables,
current_module: Option<ModuleId>,
diagnostics: Diagnostics,
warnings: Diagnostics,
reported_hidden_modules: Vec<std::path::PathBuf>,
library_modules: Vec<(ModulePath, Rc<str>)>,
phase: Phase,
expansion_depth: usize,
nesting_depth: usize,
form_budgets: BudgetArena,
recovered_diagnostics: Vec<Diagnostic>,
type_note_shown: bool,
saved_prelude: Option<PreludeState>,
saved_definitions: SavedDefinitions,
saved_macros: SavedValues<Closure>,
saved_globals: SavedValues<Value>,
expansion: ExpansionWork,
evaluated_forms: EvaluatedForms,
recorded_inputs: RecordedInputs,
declared_definitions: Vec<failed_definition::DeclaredName>,
failed_body_definitions: Vec<BindingId>,
introductions: Vec<Scope>,
duplicate_definitions: FxHashSet<(ModuleId, Rc<str>)>,
}
#[derive(Default, serde::Serialize, serde::Deserialize)]
struct ExpansionTables {
scopes: ScopeAllocator,
local_scopes: FxHashSet<Scope>,
use_site_scopes: FxHashSet<Scope>,
table: BindingTable,
bindings: BindingArena,
macros: MacroTable,
macro_origins: MacroOrigins,
introduction_scopes: FxHashSet<Scope>,
global_macros: Vec<(crate::core::BindingId, Form)>,
trait_paths: FxHashMap<crate::core::BindingId, Rc<str>>,
structural_paths: FxHashMap<Rc<str>, (crate::core::BindingId, Span)>,
enum_variants: FxHashMap<crate::core::BindingId, Vec<crate::core::BindingId>>,
variant_fields: FxHashMap<crate::core::BindingId, Vec<Rc<str>>>,
trait_methods: FxHashMap<crate::core::BindingId, TraitMethods>,
globals: GlobalTable,
module_notes: ModuleNotes,
expanded: FxHashMap<ModuleId, CoreModule>,
order: Vec<ModuleId>,
string_view: Option<BindingId>,
}
impl ExpansionTables {
fn forget_locals(&mut self) {
let bindings = &self.bindings;
self.table
.forget(|binding| matches!(bindings.get(binding).kind(), BindingKind::Local));
}
fn find_string_view(&self) -> Option<BindingId> {
let modules = self
.order
.iter()
.filter_map(|id| self.expanded.get(id))
.filter(|module| ModuleSources::is_embedded_prelude(&module.path));
StringViewSearch::in_modules(modules)
}
fn save_definitions(&mut self) -> SavedTables {
let mut saver = DefinitionSaver::new(&self.bindings, self.string_view);
let modules = self.expanded.values_mut();
for module in modules.filter(|module| ModuleSources::is_embedded_prelude(&module.path)) {
saver.take_from(module);
}
saver.finish()
}
fn take_lowered_globals(&mut self) -> LoweredGlobals {
let definitions = self.expanded.values().flat_map(CoreModule::definitions);
self.globals.take_lowered(definitions)
}
fn restore_lowered_globals(&mut self, lowered: &LoweredGlobals) {
let definitions = self.expanded.values().flat_map(CoreModule::definitions);
self.globals.restore_lowered(lowered, definitions);
}
}
impl<'s> Expander<'s> {
pub fn new(sources: &'s mut SourceMap, module_sources: ModuleSources) -> Self {
Self {
sources,
module_sources,
modules: ModuleRegistry::default(),
tables: ExpansionTables::default(),
current_module: None,
diagnostics: Diagnostics::default(),
warnings: Diagnostics::default(),
reported_hidden_modules: Vec::new(),
library_modules: Vec::new(),
phase: Phase::Runtime,
expansion_depth: 0,
nesting_depth: 0,
form_budgets: BudgetArena::default(),
recovered_diagnostics: Vec::new(),
type_note_shown: false,
saved_prelude: None,
saved_definitions: SavedDefinitions::default(),
saved_macros: SavedValues::default(),
saved_globals: SavedValues::default(),
expansion: ExpansionWork::default(),
evaluated_forms: EvaluatedForms::default(),
recorded_inputs: RecordedInputs::default(),
declared_definitions: Vec::new(),
failed_body_definitions: Vec::new(),
introductions: Vec::new(),
duplicate_definitions: FxHashSet::default(),
}
}
pub fn evaluating(self, spans: impl IntoIterator<Item = Span>) -> Self {
Self {
evaluated_forms: EvaluatedForms::new(spans),
..self
}
}
pub fn with_prelude(
sources: &'s mut SourceMap,
module_sources: ModuleSources,
prelude: PreludeState,
) -> Self {
Self {
saved_prelude: Some(prelude),
..Self::new(sources, module_sources)
}
}
#[inline(never)]
pub fn expand(mut self, path: ModulePath, entry: SourceId) -> Result<Program, Diagnostics> {
let entry = self.load_source_module(path, &[entry]);
self.into_program(entry)
}
fn into_program(mut self, entry: ModuleId) -> Result<Program, Diagnostics> {
let diagnostics = self.take_diagnostics();
self.tables.macro_origins.forget_introduced_names();
let string_view = self
.tables
.string_view
.or_else(|| self.tables.find_string_view());
let mut program = Program {
modules: self.take_modules(),
entry,
entry_function: None,
bindings: self.tables.bindings,
macro_helpers: self.tables.globals.macro_helpers(),
string_view,
checked_roots: Vec::new(),
pending_definitions: PendingDefinitions::new(self.saved_definitions),
macro_origins: Rc::new(self.tables.macro_origins),
warnings: self.warnings,
expansion: self.expansion,
};
program.restore_reached();
program.entry_function = program.written_entry_function();
diagnostics.into_result(program)
}
fn take_diagnostics(&mut self) -> Diagnostics {
for diagnostic in std::mem::take(&mut self.recovered_diagnostics) {
self.diagnostics.push(diagnostic);
}
std::mem::take(&mut self.diagnostics)
}
fn fresh_local_scope(&mut self) -> Scope {
let scope = self.tables.scopes.fresh();
self.tables.local_scopes.insert(scope);
scope
}
fn quoted(&self, datum: &Form) -> Form {
let mut quoted = datum.clone();
quoted.retain_scopes(&|scope| {
!self.tables.local_scopes.contains(&scope)
&& !self.tables.use_site_scopes.contains(&scope)
});
quoted
}
fn take_modules(&mut self) -> Vec<CoreModule> {
self.tables
.order
.iter()
.filter_map(|id| self.tables.expanded.remove(id))
.collect()
}
}