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_with_intrinsics = swamp_script_core::create_module(&compiler_version);
118
119 let core_ast_module = parse_single_module(
120 source_map,
121 &core_module_with_intrinsics.symbol_table.module_path(),
122 )?;
123
124 let mut state = ProgramState::new();
125
126 let half_completed_core_symbol_table = core_module_with_intrinsics.symbol_table.clone();
127 let default_symbol_table_for_core_with_intrinsics = half_completed_core_symbol_table.clone();
128
129 let mut core_analyzed_definition_table = analyze_single_module(
130 &mut state,
131 default_symbol_table_for_core_with_intrinsics.clone(),
132 &modules,
133 half_completed_core_symbol_table.clone().into(),
134 &core_ast_module,
135 source_map,
136 &core_module_with_intrinsics.symbol_table.module_path(),
137 )?;
138 core_analyzed_definition_table
140 .extend_intrinsic_functions_from(&default_symbol_table_for_core_with_intrinsics);
141 core_analyzed_definition_table
142 .extend_basic_from(&default_symbol_table_for_core_with_intrinsics);
143
144 let source_map_lookup = SourceMapWrapper { source_map };
145 let pretty_printer = SourceMapDisplay {
146 source_map: &source_map_lookup,
147 };
148
149 let display_core_analyzed_definition_table = SymbolTableDisplay {
150 symbol_table: &core_analyzed_definition_table,
151 source_map_display: &pretty_printer,
152 };
153
154 info!(%display_core_analyzed_definition_table, "core analyzed symbol table");
155
156 core_module_with_intrinsics.symbol_table = core_analyzed_definition_table;
157
158 let core_module_ref = Rc::new(core_module_with_intrinsics);
160 modules.add(core_module_ref.clone());
161
162 let mut default_symbol_table_for_others = SymbolTable::new(&[]);
163
164 default_symbol_table_for_others
168 .extend_alias_from(&core_module_ref.symbol_table)
169 .unwrap();
170
171 default_symbol_table_for_others
173 .add_package_version(swamp_script_core::PACKAGE_NAME, compiler_version)
174 .expect("should work");
175
176 let source_map_lookup = SourceMapWrapper { source_map };
177 let pretty_printer = SourceMapDisplay {
178 source_map: &source_map_lookup,
179 };
180
181 let symbol_table_display = SymbolTableDisplay {
182 symbol_table: &default_symbol_table_for_others,
183 source_map_display: &pretty_printer,
184 };
185
186 info!(%symbol_table_display, "default_symbol_table");
187
188 let program = Program::new(state, modules, default_symbol_table_for_others);
189
190 let result = BootstrapResult {
191 program,
192 core_module_path: core_module_ref.symbol_table.module_path().clone(),
193 };
194 Ok(result)
195}
196
197pub fn compile_and_analyze_all_modules(
198 module_path: &[String],
199 resolved_program: &mut Program,
200 source_map: &mut SourceMap,
201 core_symbol_table: SymbolTableRef,
202) -> Result<(), ScriptResolveError> {
203 let mut dependency_parser = DependencyParser::new();
204
205 let module_paths_in_order = parse_local_modules_and_get_order(
206 module_path.to_vec(),
207 &mut dependency_parser,
208 source_map,
209 )?;
210
211 analyze_modules_in_order(
212 &mut resolved_program.state,
213 &resolved_program.default_symbol_table,
214 &mut resolved_program.modules,
215 core_symbol_table,
216 source_map,
217 &module_paths_in_order,
218 &dependency_parser,
219 )?;
220
221 Ok(())
222}
223
224pub fn remove_version_from_package_name_regex(package_name_with_version: &str) -> String {
225 let re = Regex::new(
226 r"-(?P<version>[0-9]+(?:\.[0-9]+)*(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?)?(?:\+.*)?$",
227 )
228 .unwrap();
229 re.replace(package_name_with_version, "").to_string()
230}
231
232pub fn compile_analyze_and_link_without_version(
237 root_module_path: &[String],
238 resolved_program: &mut Program,
239 source_map: &mut SourceMap,
240 core_symbol_table: SymbolTableRef,
241) -> Result<(), ScriptResolveError> {
242 let mangrove_render_result = compile_and_analyze(
243 root_module_path,
244 resolved_program,
245 source_map,
246 core_symbol_table,
247 );
248
249 match mangrove_render_result {
250 Ok(..) => {}
251 Err(err) => {
252 show_script_resolve_error(&err, source_map, &Path::new(""));
253 Err(err)?;
254 }
255 }
256 let mangrove_render_module = resolved_program.modules.get(root_module_path).unwrap();
257
258 let first_part = remove_version_from_package_name_regex(&root_module_path[0]);
259 let mut without_version_path: Vec<String> = root_module_path.to_vec();
260 without_version_path[0] = first_part;
261
262 resolved_program
263 .modules
264 .link_module(&without_version_path, mangrove_render_module.clone());
265
266 Ok(())
267}
268
269pub fn compile_and_analyze(
272 root_module_path: &[String],
273 resolved_program: &mut Program,
274 source_map: &mut SourceMap,
275 core_symbol_table: SymbolTableRef,
276) -> Result<(), ScriptResolveError> {
277 compile_and_analyze_all_modules(
278 root_module_path,
279 resolved_program,
280 source_map,
281 core_symbol_table,
282 )
283}
284
285pub fn current_path() -> PathBuf {
286 current_dir().unwrap()
287}
288
289pub fn bootstrap_and_compile(
294 source_map: &mut SourceMap,
295 root_path: &[String],
297) -> Result<Program, ScriptResolveError> {
298 let bootstrap_result = bootstrap_modules(source_map).inspect_err(|err| {
299 show_script_resolve_error(err, source_map, ¤t_path());
300 })?;
301
302 let mut program = bootstrap_result.program;
303
304 let core_symbol_table = program
305 .modules
306 .get(&bootstrap_result.core_module_path)
307 .unwrap()
308 .symbol_table
309 .clone();
310
311 compile_and_analyze_all_modules(
322 root_path,
323 &mut program,
324 source_map,
325 core_symbol_table.into(),
326 )
327 .inspect_err(|err| {
328 show_script_resolve_error(err, source_map, ¤t_path());
329 })?;
330
331 Ok(program)
334}
335
336pub fn debug_all_modules(modules: &Modules, source_map: &SourceMap) {
337 for (_name, module) in modules.modules() {
338 debug_module(&module.symbol_table, source_map)
339 }
340}
341pub fn debug_module(symbol_table: &SymbolTable, source_map: &SourceMap) {
342 let source_map_lookup = SourceMapWrapper { source_map };
343 let pretty_printer = SourceMapDisplay {
344 source_map: &source_map_lookup,
345 };
346
347 let symbol_table_display = SymbolTableDisplay {
348 symbol_table: &symbol_table,
349 source_map_display: &pretty_printer,
350 };
351
352 info!(%symbol_table_display, "{:?}", symbol_table.module_path());
353}