1use regex::Regex;
6use seq_map::SeqMap;
7use std::env::current_dir;
8use std::io;
9use std::path::Path;
10use std::path::PathBuf;
11use std::rc::Rc;
12use std::str::FromStr;
13use swamp_script_analyzer::Analyzer;
14use swamp_script_analyzer::prelude::{Error, Program};
15use swamp_script_dep_loader::{
16 DependencyParser, ParsedAstModule, parse_local_modules_and_get_order, parse_single_module,
17 swamp_registry_path,
18};
19use swamp_script_error_report::{ScriptResolveError, prelude::show_script_resolve_error};
20use swamp_script_eval_loader::analyze_modules_in_order;
21use swamp_script_modules::modules::{Module, Modules};
22use swamp_script_modules::symtbl::{SymbolTable, SymbolTableRef};
23use swamp_script_pretty_print::{SourceMapDisplay, SymbolTableDisplay};
24use swamp_script_semantic::ProgramState;
25use swamp_script_source_map::SourceMap;
26use swamp_script_source_map_lookup::SourceMapWrapper;
27use tiny_ver::TinyVersion;
28use tracing::{debug, info, trace};
29
30const COMPILER_VERSION: &str = "0.0.0";
31
32pub fn analyze_ast_module_skip_expression(
35 analyzer: &mut Analyzer,
36 parsed_ast_module: &ParsedAstModule,
37) -> Result<(), Error> {
38 for definition in &parsed_ast_module.ast_module.definitions {
39 analyzer.analyze_definition(definition)?;
40 }
41 Ok(())
42}
43
44pub fn analyze_single_module(
45 state: &mut ProgramState,
46 default_symbol_table: SymbolTable,
47 modules: &Modules,
48 core_symbol_table: SymbolTableRef,
49 parsed_ast_module: &ParsedAstModule,
50 source_map: &SourceMap,
51 versioned_module_path: &[String],
52) -> Result<SymbolTable, Error> {
53 let mut analyzer = Analyzer::new(
54 state,
55 modules,
56 core_symbol_table,
57 source_map,
58 versioned_module_path,
59 parsed_ast_module.file_id,
60 );
61
62 analyzer.shared.lookup_table = default_symbol_table;
63
64 analyze_ast_module_skip_expression(&mut analyzer, parsed_ast_module)?;
67
68 Ok(analyzer.shared.definition_table)
69}
70
71pub fn create_source_map(registry_path: &Path, local_path: &Path) -> io::Result<SourceMap> {
72 trace!(?registry_path, ?local_path, "mounting source map");
73
74 let mut mounts = SeqMap::new();
75 mounts
76 .insert("crate".to_string(), local_path.to_path_buf())
77 .unwrap();
78
79 mounts
80 .insert("registry".to_string(), registry_path.to_path_buf())
81 .unwrap();
82
83 SourceMap::new(&mounts)
84}
85
86pub fn create_registry_source_map(registry_path: &Path) -> io::Result<SourceMap> {
87 trace!(?registry_path, "mounting registry path source map");
88
89 let mut mounts = SeqMap::new();
90 mounts
91 .insert("registry".to_string(), registry_path.to_path_buf())
92 .unwrap();
93
94 SourceMap::new(&mounts)
95}
96
97#[derive(Debug)]
98pub struct BootstrapResult {
99 pub program: Program,
100 pub core_module_path: Vec<String>,
101}
102
103pub fn bootstrap_modules(
110 mut source_map: &mut SourceMap,
111) -> Result<BootstrapResult, ScriptResolveError> {
112 let compiler_version = TinyVersion::from_str(COMPILER_VERSION).unwrap();
113 trace!(%compiler_version, "booting up compiler");
114
115 let mut modules = Modules::new();
116
117 let mut core_module = swamp_script_core::create_module(&compiler_version);
118
119 let mut default_symbol_table = SymbolTable::new(&[]);
120
121 default_symbol_table
125 .extend_basic_from(&core_module.symbol_table)
126 .unwrap();
127
128 let core_ast_module = parse_single_module(source_map, &core_module.symbol_table.module_path())?;
129
130 let mut state = ProgramState::new();
131
132 let core_symbol_table = core_module.symbol_table.clone();
133
134 let mut core_analyzed_symbol_table = analyze_single_module(
135 &mut state,
136 core_symbol_table.clone(),
137 &modules,
138 core_symbol_table.clone().into(),
139 &core_ast_module,
140 source_map,
141 &core_module.symbol_table.module_path(),
142 )?;
143
144 debug!("analyzed core module");
145
146 core_analyzed_symbol_table
147 .extend_intrinsic_functions_from(&core_symbol_table)
148 .unwrap();
149
150 core_module.symbol_table = core_analyzed_symbol_table;
166
167 let core_module_ref = Rc::new(core_module);
169 modules.add(core_module_ref.clone());
170
171 default_symbol_table
173 .add_package_version(swamp_script_core::PACKAGE_NAME, compiler_version)
174 .expect("should work");
175
176 let program = Program::new(state, modules, default_symbol_table);
177
178 let result = BootstrapResult {
179 program,
180 core_module_path: core_module_ref.symbol_table.module_path().clone(),
181 };
182 Ok(result)
183}
184
185pub fn compile_and_analyze_all_modules(
186 module_path: &[String],
187 resolved_program: &mut Program,
188 source_map: &mut SourceMap,
189 core_symbol_table: SymbolTableRef,
190) -> Result<(), ScriptResolveError> {
191 let mut dependency_parser = DependencyParser::new();
192
193 let module_paths_in_order = parse_local_modules_and_get_order(
194 module_path.to_vec(),
195 &mut dependency_parser,
196 source_map,
197 )?;
198
199 analyze_modules_in_order(
200 &mut resolved_program.state,
201 &resolved_program.default_symbol_table,
202 &mut resolved_program.modules,
203 core_symbol_table,
204 source_map,
205 &module_paths_in_order,
206 &dependency_parser,
207 )?;
208
209 Ok(())
210}
211
212pub fn remove_version_from_package_name_regex(package_name_with_version: &str) -> String {
213 let re = Regex::new(
214 r"-(?P<version>[0-9]+(?:\.[0-9]+)*(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?)?(?:\+.*)?$",
215 )
216 .unwrap();
217 re.replace(package_name_with_version, "").to_string()
218}
219
220pub fn compile_analyze_and_link_without_version(
225 root_module_path: &[String],
226 resolved_program: &mut Program,
227 source_map: &mut SourceMap,
228 core_symbol_table: SymbolTableRef,
229) -> Result<(), ScriptResolveError> {
230 let mangrove_render_result = compile_and_analyze(
231 root_module_path,
232 resolved_program,
233 source_map,
234 core_symbol_table,
235 );
236
237 match mangrove_render_result {
238 Ok(..) => {}
239 Err(err) => {
240 show_script_resolve_error(&err, source_map, &Path::new(""));
241 Err(err)?;
242 }
243 }
244 let mangrove_render_module = resolved_program.modules.get(root_module_path).unwrap();
245
246 let first_part = remove_version_from_package_name_regex(&root_module_path[0]);
247 let mut without_version_path: Vec<String> = root_module_path.to_vec();
248 without_version_path[0] = first_part;
249
250 resolved_program
251 .modules
252 .link_module(&without_version_path, mangrove_render_module.clone());
253
254 Ok(())
255}
256
257pub fn compile_and_analyze(
260 root_module_path: &[String],
261 resolved_program: &mut Program,
262 source_map: &mut SourceMap,
263 core_symbol_table: SymbolTableRef,
264) -> Result<(), ScriptResolveError> {
265 compile_and_analyze_all_modules(
266 root_module_path,
267 resolved_program,
268 source_map,
269 core_symbol_table,
270 )
271}
272
273pub fn current_path() -> PathBuf {
274 current_dir().unwrap()
275}
276
277pub fn bootstrap_and_compile(
282 source_map: &mut SourceMap,
283 root_path: &[String],
285) -> Result<Program, ScriptResolveError> {
286 let bootstrap_result = bootstrap_modules(source_map).inspect_err(|err| {
287 show_script_resolve_error(err, source_map, ¤t_path());
288 })?;
289
290 let mut program = bootstrap_result.program;
291
292 let core_symbol_table = program
293 .modules
294 .get(&bootstrap_result.core_module_path)
295 .unwrap()
296 .symbol_table
297 .clone();
298
299 compile_and_analyze_all_modules(
310 root_path,
311 &mut program,
312 source_map,
313 core_symbol_table.into(),
314 )
315 .inspect_err(|err| {
316 show_script_resolve_error(err, source_map, ¤t_path());
317 })?;
318
319 Ok(program)
322}
323
324pub fn debug_all_modules(modules: &Modules, source_map: &SourceMap) {
325 for (_name, module) in modules.modules() {
326 debug_module(&module.symbol_table, source_map)
327 }
328}
329pub fn debug_module(symbol_table: &SymbolTable, source_map: &SourceMap) {
330 let source_map_lookup = SourceMapWrapper { source_map };
331 let pretty_printer = SourceMapDisplay {
332 source_map: &source_map_lookup,
333 };
334
335 let symbol_table_display = SymbolTableDisplay {
336 symbol_table: &symbol_table,
337 source_map_display: &pretty_printer,
338 };
339
340 info!(%symbol_table_display, "{:?}", symbol_table.module_path());
341}