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