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;
14pub use 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::{ModuleRef, 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 time_dilation::ScopedTimer;
28use tiny_ver::TinyVersion;
29use tracing::{info, trace};
30
31pub const COMPILER_VERSION: &str = "0.0.0";
32pub const CORE_VERSION: &str = "core-0.0.0";
33
34pub fn analyze_ast_module_skip_expression(
37 analyzer: &mut Analyzer,
38 parsed_ast_module: &ParsedAstModule,
39) -> Result<(), Error> {
40 for definition in &parsed_ast_module.ast_module.definitions {
41 analyzer.analyze_definition(definition)?;
42 }
43 Ok(())
44}
45
46pub fn analyze_single_module(
47 state: &mut ProgramState,
48 default_symbol_table: SymbolTable,
49 modules: &Modules,
50 core_symbol_table: SymbolTableRef,
51 parsed_ast_module: &ParsedAstModule,
52 source_map: &SourceMap,
53 versioned_module_path: &[String],
54) -> Result<SymbolTable, Error> {
55 let mut analyzer = Analyzer::new(
56 state,
57 modules,
58 core_symbol_table,
59 source_map,
60 versioned_module_path,
61 parsed_ast_module.file_id,
62 );
63
64 analyzer.shared.lookup_table = default_symbol_table;
65
66 analyze_ast_module_skip_expression(&mut analyzer, parsed_ast_module)?;
69
70 Ok(analyzer.shared.definition_table)
71}
72
73pub fn create_source_map(registry_path: &Path, local_path: &Path) -> io::Result<SourceMap> {
74 trace!(?registry_path, ?local_path, "mounting source map");
75
76 let mut mounts = SeqMap::new();
77 mounts
78 .insert("crate".to_string(), local_path.to_path_buf())
79 .unwrap();
80
81 mounts
82 .insert("registry".to_string(), registry_path.to_path_buf())
83 .unwrap();
84
85 SourceMap::new(&mounts)
86}
87
88pub fn create_registry_source_map(registry_path: &Path) -> io::Result<SourceMap> {
89 trace!(?registry_path, "mounting registry path source map");
90
91 let mut mounts = SeqMap::new();
92 mounts
93 .insert("registry".to_string(), registry_path.to_path_buf())
94 .unwrap();
95
96 SourceMap::new(&mounts)
97}
98
99#[derive(Debug)]
100pub struct BootstrapResult {
101 pub program: Program,
102 pub core_module_path: Vec<String>,
103}
104
105pub fn bootstrap_modules(
112 source_map: &mut SourceMap,
113) -> Result<BootstrapResult, ScriptResolveError> {
114 let compiler_version = TinyVersion::from_str(COMPILER_VERSION).unwrap();
115 trace!(%compiler_version, "booting up compiler");
116
117 let mut modules = Modules::new();
118
119 let mut core_module_with_intrinsics = swamp_script_core::create_module(&compiler_version);
120
121 let core_ast_module = parse_single_module(
122 source_map,
123 &core_module_with_intrinsics.symbol_table.module_path(),
124 )?;
125
126 let mut state = ProgramState::new();
127
128 let half_completed_core_symbol_table = core_module_with_intrinsics.symbol_table.clone();
129 let default_symbol_table_for_core_with_intrinsics = half_completed_core_symbol_table.clone();
130
131 let mut core_analyzed_definition_table = analyze_single_module(
132 &mut state,
133 default_symbol_table_for_core_with_intrinsics.clone(),
134 &modules,
135 half_completed_core_symbol_table.clone().into(),
136 &core_ast_module,
137 source_map,
138 &core_module_with_intrinsics.symbol_table.module_path(),
139 )?;
140 core_analyzed_definition_table
142 .extend_intrinsic_functions_from(&default_symbol_table_for_core_with_intrinsics);
143 core_analyzed_definition_table
144 .extend_basic_from(&default_symbol_table_for_core_with_intrinsics);
145
146 let source_map_lookup = SourceMapWrapper {
147 source_map,
148 current_dir: current_dir().unwrap(),
149 };
150 let pretty_printer = SourceMapDisplay {
151 source_map: &source_map_lookup,
152 };
153
154 let display_core_analyzed_definition_table = SymbolTableDisplay {
155 symbol_table: &core_analyzed_definition_table,
156 source_map_display: &pretty_printer,
157 };
158
159 core_module_with_intrinsics.symbol_table = core_analyzed_definition_table;
162
163 let core_module_ref = Rc::new(core_module_with_intrinsics);
165 modules.add(core_module_ref.clone());
166
167 let mut default_symbol_table_for_others = SymbolTable::new(&[]);
168
169 default_symbol_table_for_others
173 .extend_alias_from(&core_module_ref.symbol_table)
174 .unwrap();
175
176 default_symbol_table_for_others
178 .add_package_version(swamp_script_core::PACKAGE_NAME, compiler_version)
179 .expect("should work");
180
181 let source_map_lookup = SourceMapWrapper {
182 source_map,
183 current_dir: current_dir().unwrap(),
184 };
185 let pretty_printer = SourceMapDisplay {
186 source_map: &source_map_lookup,
187 };
188
189 let symbol_table_display = SymbolTableDisplay {
190 symbol_table: &default_symbol_table_for_others,
191 source_map_display: &pretty_printer,
192 };
193
194 let program = Program::new(state, modules, default_symbol_table_for_others);
195
196 let result = BootstrapResult {
197 program,
198 core_module_path: core_module_ref.symbol_table.module_path().clone(),
199 };
200 Ok(result)
201}
202
203pub fn compile_and_analyze_all_modules(
204 module_path: &[String],
205 resolved_program: &mut Program,
206 source_map: &mut SourceMap,
207 core_symbol_table: SymbolTableRef,
208) -> Result<(), ScriptResolveError> {
209 let mut dependency_parser = DependencyParser::new();
210
211 let module_paths_in_order = parse_local_modules_and_get_order(
212 module_path.to_vec(),
213 &mut dependency_parser,
214 source_map,
215 )?;
216
217 analyze_modules_in_order(
218 &mut resolved_program.state,
219 &resolved_program.default_symbol_table,
220 &mut resolved_program.modules,
221 core_symbol_table,
222 source_map,
223 &module_paths_in_order,
224 &dependency_parser,
225 )?;
226
227 Ok(())
228}
229
230pub fn remove_version_from_package_name_regex(package_name_with_version: &str) -> String {
231 let re = Regex::new(
232 r"-(?P<version>[0-9]+(?:\.[0-9]+)*(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?)?(?:\+.*)?$",
233 )
234 .unwrap();
235 re.replace(package_name_with_version, "").to_string()
236}
237
238pub fn compile_analyze_and_link_without_version(
243 root_module_path: &[String],
244 resolved_program: &mut Program,
245 source_map: &mut SourceMap,
246 core_symbol_table: SymbolTableRef,
247) -> Result<(), ScriptResolveError> {
248 let mangrove_render_result = compile_and_analyze(
249 root_module_path,
250 resolved_program,
251 source_map,
252 core_symbol_table,
253 );
254
255 match mangrove_render_result {
256 Ok(..) => {}
257 Err(err) => {
258 show_script_resolve_error(&err, source_map, Path::new(""));
259 Err(err)?;
260 }
261 }
262 let mangrove_render_module = resolved_program.modules.get(root_module_path).unwrap();
263
264 let first_part = remove_version_from_package_name_regex(&root_module_path[0]);
265 let mut without_version_path: Vec<String> = root_module_path.to_vec();
266 without_version_path[0] = first_part;
267
268 resolved_program
269 .modules
270 .link_module(&without_version_path, mangrove_render_module.clone());
271
272 Ok(())
273}
274
275pub fn compile_and_analyze(
278 root_module_path: &[String],
279 resolved_program: &mut Program,
280 source_map: &mut SourceMap,
281 core_symbol_table: SymbolTableRef,
282) -> Result<(), ScriptResolveError> {
283 compile_and_analyze_all_modules(
284 root_module_path,
285 resolved_program,
286 source_map,
287 core_symbol_table,
288 )
289}
290
291pub fn current_path() -> PathBuf {
292 current_dir().unwrap()
293}
294
295pub fn bootstrap_and_compile(
300 source_map: &mut SourceMap,
301 root_path: &[String],
303) -> Result<Program, ScriptResolveError> {
304 let bootstrap_timer = ScopedTimer::new("bootstrap");
305 let bootstrap_result = bootstrap_modules(source_map).inspect_err(|err| {
306 show_script_resolve_error(err, source_map, ¤t_path());
307 })?;
308 drop(bootstrap_timer);
309
310 let mut program = bootstrap_result.program;
311
312 let core_symbol_table = program
313 .modules
314 .get(&bootstrap_result.core_module_path)
315 .unwrap()
316 .symbol_table
317 .clone();
318
319 let compile_all_modules_timer = ScopedTimer::new("compile all modules");
330 compile_and_analyze_all_modules(
331 root_path,
332 &mut program,
333 source_map,
334 core_symbol_table.into(),
335 )
336 .inspect_err(|err| {
337 show_script_resolve_error(err, source_map, ¤t_path());
338 })?;
339
340 drop(compile_all_modules_timer);
341
342 Ok(program)
345}
346
347pub fn debug_all_modules(modules: &Modules, source_map: &SourceMap) {
348 for (_name, module) in modules.modules() {
349 debug_module(&module.symbol_table, source_map);
350 }
351}
352pub fn debug_module(symbol_table: &SymbolTable, source_map: &SourceMap) {
353 let source_map_lookup = SourceMapWrapper {
354 source_map,
355 current_dir: current_dir().unwrap(),
356 };
357 let pretty_printer = SourceMapDisplay {
358 source_map: &source_map_lookup,
359 };
360
361 let symbol_table_display = SymbolTableDisplay {
362 symbol_table: &symbol_table,
363 source_map_display: &pretty_printer,
364 };
365
366 info!(%symbol_table_display, "{:?}", symbol_table.module_path());
367}
368
369pub fn compile_string(script: &str) -> Result<(Program, ModuleRef, SourceMap), ScriptResolveError> {
370 let mut source_map = SourceMap::new(&SeqMap::default()).unwrap();
371 let file_id = 0xffff;
372
373 source_map
374 .add_mount("registry", &swamp_registry_path().unwrap())
375 .unwrap(); source_map.add_mount("crate", Path::new("/tmp/")).unwrap();
378 source_map.add_to_cache("crate", Path::new("test.swamp"), script, file_id);
379
380 let resolved_path_str = vec!["crate".to_string(), "test".to_string()];
381
382 let program = bootstrap_and_compile(&mut source_map, &resolved_path_str)?;
383 let main_module = program.modules.get(&resolved_path_str).unwrap().clone();
384
385 Ok((program, main_module, source_map))
386}