use crate::functions::get_timestamp::get_timestamp;
use crate::functions::trace_requires::trace_requires;
use crate::records::file_resolver::FileResolver;
use crate::records::frontend::Frontend;
use crate::records::source_module::SourceModule;
use crate::records::source_node::SourceNode;
use crate::records::type_check_limits::TypeCheckLimits;
use crate::type_aliases::module_name_file_resolver::ModuleName;
use alloc::sync::Arc;
use luaur_common::macros::luau_timetrace_argument::LUAU_TIMETRACE_ARGUMENT;
use luaur_common::macros::luau_timetrace_scope::LUAU_TIMETRACE_SCOPE;
use luaur_config::records::config::Config;
impl Frontend {
pub fn get_source_node(
&mut self,
name: &ModuleName,
limits: &TypeCheckLimits,
) -> (*mut SourceNode, *mut SourceModule) {
let already_present = match self.source_nodes.get(name) {
Some(node) if !node.has_dirty_source_module() => {
let node_ptr = Arc::as_ptr(node) as *mut SourceNode;
if let Some(module) = self.source_modules.get(name) {
return (node_ptr, Arc::as_ptr(module) as *mut SourceModule);
} else {
return (node_ptr, core::ptr::null_mut());
}
}
Some(_) => true,
None => false,
};
LUAU_TIMETRACE_SCOPE!("Frontend::getSourceNode", "Frontend");
LUAU_TIMETRACE_ARGUMENT!("name", name.as_str());
let timestamp = get_timestamp();
let source = unsafe { FileResolver::read_source(self.file_resolver, name) };
let environment_name =
unsafe { FileResolver::get_environment_for_module(self.file_resolver, name) };
self.stats.time_read += get_timestamp() - timestamp;
let source = match source {
Some(source) => source,
None => {
self.source_modules.remove(name);
return (core::ptr::null_mut(), core::ptr::null_mut());
}
};
let mut opts = {
let config: &Config = unsafe {
let get_config = (*self.config_resolver)
.get_config
.expect("ConfigResolver::getConfig is not set");
&*get_config(self.config_resolver, name, limits)
};
config.parse_options.clone()
};
opts.capture_comments = true;
let mut result =
self.parse_module_name_string_view_parse_options(name, &source.source, &opts);
result.r#type = source.r#type;
let require = trace_requires(self.file_resolver, result.root, name.clone(), limits);
self.require_trace.insert(name.clone(), require.clone());
let source_node_arc = self
.source_nodes
.entry(name.clone())
.or_insert_with(|| Arc::new(default_source_node()));
let source_node_ptr = Arc::as_ptr(source_node_arc) as *mut SourceNode;
let source_module_arc = self
.source_modules
.entry(name.clone())
.or_insert_with(|| Arc::new(SourceModule::source_module()));
let source_module_ptr = Arc::as_ptr(source_module_arc) as *mut SourceModule;
unsafe {
*source_module_ptr = result;
(*source_module_ptr).environment_name = environment_name;
(*source_node_ptr).name = (*source_module_ptr).name.clone();
(*source_node_ptr).human_readable_name =
(*source_module_ptr).human_readable_name.clone();
let prior_locations = (*source_node_ptr).require_locations.clone();
let self_name = (*source_node_ptr).name.clone();
for (module_name, _) in prior_locations.iter() {
if let Some(dep) = self.source_nodes.get(module_name) {
let dep_ptr = Arc::as_ptr(dep) as *mut SourceNode;
let retained: alloc::vec::Vec<ModuleName> = (*dep_ptr)
.dependents
.iter()
.filter(|n| **n != self_name)
.cloned()
.collect();
(*dep_ptr).dependents.clear();
for n in retained {
(*dep_ptr).dependents.insert(n);
}
}
}
(*source_node_ptr).require_set.clear();
(*source_node_ptr).require_locations.clear();
(*source_node_ptr).dirty_source_module = false;
if !already_present {
(*source_node_ptr).dirty_module = true;
(*source_node_ptr).dirty_module_for_autocomplete = true;
}
for (module_name, _) in require.require_list.iter() {
(*source_node_ptr).require_set.insert(module_name.clone());
}
(*source_node_ptr).require_locations = require.require_list.clone();
}
(source_node_ptr, source_module_ptr)
}
}
fn default_source_node() -> SourceNode {
use luaur_common::records::dense_hash_set::DenseHashSet;
SourceNode {
name: ModuleName::default(),
human_readable_name: alloc::string::String::new(),
require_set: DenseHashSet::new(ModuleName::default()),
require_locations: alloc::vec::Vec::new(),
dependents: DenseHashSet::new(ModuleName::default()),
dirty_source_module: true,
dirty_module: true,
dirty_module_for_autocomplete: true,
invalid_module_dependency: true,
invalid_module_dependency_for_autocomplete: true,
autocomplete_limits_mult: 1.0,
}
}