1use regex::Regex;
6use seq_map::SeqMap;
7use source_map_cache::SourceMap;
8use source_map_cache::SourceMapWrapper;
9use std::env::current_dir;
10use std::io;
11use std::path::Path;
12use std::path::PathBuf;
13use std::str::FromStr;
14pub use swamp_analyzer::prelude::Program;
15use swamp_analyzer::Analyzer;
16use swamp_core::text::core_text;
17use swamp_dep_loader::{
18 parse_local_modules_and_get_order, parse_single_module_from_text, swamp_registry_path,
19 DependencyParser, ParsedAstModule,
20};
21use swamp_error_report::analyze::show_analyzer_error;
22use swamp_error_report::prelude::Kind;
23use swamp_error_report::{prelude::show_script_resolve_error, ScriptResolveError};
24use swamp_modules::modules::{ModuleRef, Modules};
25use swamp_modules::prelude::Module;
26use swamp_modules::symtbl::{SymbolTable, SymbolTableRef};
27use swamp_pretty_print::{ImplsDisplay, SourceMapDisplay, SymbolTableDisplay};
28use swamp_program_analyzer::analyze_modules_in_order;
29use swamp_semantic::err::Error;
30use swamp_semantic::{formal_module_name, AssociatedImpls, ProgramState};
31use swamp_std::std_text;
32use swamp_types::prelude::print_types;
33use time_dilation::ScopedTimer;
34use tiny_ver::TinyVersion;
35use tracing::{info, trace};
36
37pub const COMPILER_VERSION: &str = "0.0.0";
38pub const CORE_VERSION: &str = "core-0.0.0";
39
40pub fn analyze_ast_module_skip_expression(
43 analyzer: &mut Analyzer,
44 parsed_ast_module: &ParsedAstModule,
45) {
46 for definition in &parsed_ast_module.ast_module.definitions {
47 analyzer.analyze_definition(definition);
48 }
49}
50
51#[must_use]
52pub fn analyze_single_module(
53 state: &mut ProgramState,
54 default_symbol_table: SymbolTable,
55 modules: &Modules,
56 core_symbol_table: SymbolTableRef,
57 parsed_ast_module: &ParsedAstModule,
58 source_map: &SourceMap,
59 versioned_module_path: &[String],
60) -> SymbolTable {
61 let mut analyzer = Analyzer::new(
62 state,
63 modules,
64 core_symbol_table,
65 source_map,
66 versioned_module_path,
67 parsed_ast_module.file_id,
68 );
69
70 analyzer.shared.lookup_table = default_symbol_table;
71
72 analyze_ast_module_skip_expression(&mut analyzer, parsed_ast_module);
75
76 analyzer.shared.definition_table
77}
78
79pub fn create_source_map(registry_path: &Path, local_path: &Path) -> io::Result<SourceMap> {
80 trace!(?registry_path, ?local_path, "mounting source map");
81
82 let mut mounts = SeqMap::new();
83 mounts
84 .insert("crate".to_string(), local_path.to_path_buf())
85 .unwrap();
86
87 mounts
88 .insert("registry".to_string(), registry_path.to_path_buf())
89 .unwrap();
90
91 SourceMap::new(&mounts)
92}
93
94pub fn create_registry_source_map(registry_path: &Path) -> io::Result<SourceMap> {
95 trace!(?registry_path, "mounting registry path source map");
96
97 let mut mounts = SeqMap::new();
98 mounts
99 .insert("registry".to_string(), registry_path.to_path_buf())
100 .unwrap();
101
102 SourceMap::new(&mounts)
103}
104
105#[derive(Debug)]
106pub struct BootstrapResult {
107 pub program: Program,
108 pub core_module_path: Vec<String>,
109}
110
111pub fn bootstrap_modules(
118 source_map: &mut SourceMap,
119) -> Result<BootstrapResult, ScriptResolveError> {
120 let compiler_version = TinyVersion::from_str(COMPILER_VERSION).unwrap();
121 trace!(%compiler_version, "booting up compiler");
122 let mut state = ProgramState::new();
123
124 let mut modules = Modules::new();
125
126 let core_module_with_intrinsics =
127 swamp_core::create_module(&compiler_version, &mut state.types);
128
129 let core_path = core_module_with_intrinsics.symbol_table.module_path();
130 let core_parsed_ast_module =
131 parse_single_module_from_text(source_map, &core_path, &core_text())?;
132
133 let half_completed_core_symbol_table = core_module_with_intrinsics.symbol_table.clone();
134 let default_symbol_table_for_core_with_intrinsics = half_completed_core_symbol_table.clone();
135
136 let mut analyzed_core_symbol_table = analyze_single_module(
137 &mut state,
138 default_symbol_table_for_core_with_intrinsics.clone(),
139 &modules,
140 half_completed_core_symbol_table.clone().into(),
141 &core_parsed_ast_module,
142 source_map,
143 &core_module_with_intrinsics.symbol_table.module_path(),
144 );
145
146 analyzed_core_symbol_table
148 .extend_basic_from(&core_module_with_intrinsics.symbol_table)
149 .expect("couldn't extend core");
150 let mut default_module = swamp_core::create_module_with_name(&[]);
151 default_module
152 .symbol_table
153 .extend_alias_from(&analyzed_core_symbol_table)
154 .expect("extend basic alias and functions from core");
155
156 let core_module = Module::new(analyzed_core_symbol_table, vec![], None);
157 modules.add(ModuleRef::from(core_module));
158
159 let std_path = &["std".to_string()];
162 let std_module_with_intrinsics = swamp_core::create_module_with_name(std_path);
163 let std_ast_module = parse_single_module_from_text(source_map, std_path, &std_text())?;
164 let analyzed_std_symbol_table = analyze_single_module(
165 &mut state,
166 default_symbol_table_for_core_with_intrinsics,
167 &modules,
168 half_completed_core_symbol_table.into(),
169 &std_ast_module,
170 source_map,
171 &std_module_with_intrinsics.symbol_table.module_path(),
172 );
173 default_module
174 .symbol_table
175 .extend_basic_from(&analyzed_std_symbol_table)
176 .expect("extend basics from core");
177
178 let analyzed_std_module = Module::new(analyzed_std_symbol_table, vec![], None);
179
180 modules.add(ModuleRef::from(analyzed_std_module));
181
182 let bootstrap_program = Program::new(state, modules, default_module.symbol_table);
183
184 let result = BootstrapResult {
185 program: bootstrap_program,
186 core_module_path: core_path,
187 };
188
189 Ok(result)
190}
191
192pub fn compile_and_analyze_all_modules(
193 module_path: &[String],
194 resolved_program: &mut Program,
195 source_map: &mut SourceMap,
196 core_symbol_table: SymbolTableRef,
197) -> Result<(), ScriptResolveError> {
198 let mut dependency_parser = DependencyParser::new();
199
200 let module_paths_in_order =
201 parse_local_modules_and_get_order(module_path, &mut dependency_parser, source_map)?;
202
203 analyze_modules_in_order(
204 &mut resolved_program.state,
205 &resolved_program.default_symbol_table,
206 &mut resolved_program.modules,
207 &core_symbol_table,
208 source_map,
209 &module_paths_in_order,
210 &dependency_parser,
211 )?;
212
213 Ok(())
214}
215
216#[must_use]
217pub fn remove_version_from_package_name_regex(package_name_with_version: &str) -> String {
218 let re = Regex::new(
219 r"-(?P<version>[0-9]+(?:\.[0-9]+)*(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?)?(?:\+.*)?$",
220 )
221 .unwrap();
222 re.replace(package_name_with_version, "").to_string()
223}
224
225#[must_use]
226pub fn current_path() -> PathBuf {
227 current_dir().unwrap()
228}
229
230pub struct CompileOptions {
231 pub show_semantic: bool,
232 pub show_modules: bool,
233 pub show_errors: bool,
234 pub show_types: bool,
235}
236
237pub fn bootstrap_and_compile(
242 source_map: &mut SourceMap,
243 root_path: &[String],
244 options: &CompileOptions,
245) -> Result<Program, ScriptResolveError> {
246 let bootstrap_timer = ScopedTimer::new("bootstrap");
247 let bootstrap_result = bootstrap_modules(source_map).inspect_err(|err| {
248 show_script_resolve_error(err, source_map, ¤t_path());
249 })?;
250 drop(bootstrap_timer);
251 let mut program = bootstrap_result.program;
252
253 let core_symbol_table = program
254 .modules
255 .get(&bootstrap_result.core_module_path)
256 .unwrap()
257 .symbol_table
258 .clone();
259
260 let compile_all_modules_timer = ScopedTimer::new("compile all modules");
261 compile_and_analyze_all_modules(
262 root_path,
263 &mut program,
264 source_map,
265 core_symbol_table.into(),
266 )
267 .inspect_err(|err| {
268 show_script_resolve_error(err, source_map, ¤t_path());
269 })?;
270
271 drop(compile_all_modules_timer);
272
273 if options.show_modules {
274 debug_all_modules(&program.modules, source_map);
275 }
276
277 if options.show_semantic {
278 debug_all_impl_functions(&program.state.associated_impls, source_map);
279 }
280
281 if options.show_types {
282 let mut str = String::new();
283 print_types(&mut str, &program.state.types).expect("should work");
284 eprintln!("{str}");
285 }
287
288 if options.show_errors {
289 let source_map_wrapper = SourceMapWrapper {
290 source_map,
291 current_dir: current_dir().unwrap(),
292 };
293 show_errors(&program.state.errors, &source_map_wrapper);
294 show_hints(&program.state.hints, &source_map_wrapper);
295 show_information(&program.state.infos, &source_map_wrapper);
296 }
297
298 Ok(program)
299}
300
301fn show_errors(errors: &[Error], source_map_wrapper: &SourceMapWrapper) {
302 for err in errors {
303 show_analyzer_error(
304 err,
305 Kind::Error,
306 source_map_wrapper.source_map,
307 &source_map_wrapper.current_dir,
308 );
309 }
310}
311
312fn show_hints(errors: &[Error], source_map_wrapper: &SourceMapWrapper) {
313 for err in errors {
314 show_analyzer_error(
315 err,
316 Kind::Warning,
317 source_map_wrapper.source_map,
318 &source_map_wrapper.current_dir,
319 );
320 }
321}
322
323fn show_information(errors: &[Error], source_map_wrapper: &SourceMapWrapper) {
324 for err in errors {
325 show_analyzer_error(
326 err,
327 Kind::Help,
328 source_map_wrapper.source_map,
329 &source_map_wrapper.current_dir,
330 );
331 }
332}
333
334pub fn debug_all_modules(modules: &Modules, source_map: &SourceMap) {
335 for (_name, module) in modules.modules() {
336 debug_module(&module.symbol_table, source_map);
337 }
338}
339pub fn debug_module(symbol_table: &SymbolTable, source_map: &SourceMap) {
340 let source_map_lookup = SourceMapWrapper {
341 source_map,
342 current_dir: current_dir().unwrap(),
343 };
344 let pretty_printer = SourceMapDisplay {
345 source_map: &source_map_lookup,
346 };
347
348 let symbol_table_display = SymbolTableDisplay {
349 symbol_table,
350 source_map_display: &pretty_printer,
351 };
352
353 info!(
354 "module: {}{}",
355 formal_module_name(&symbol_table.module_path()),
356 symbol_table_display
357 );
358}
359
360fn debug_all_impl_functions(all_impls: &AssociatedImpls, source_map: &mut SourceMap) {
361 let source_map_lookup = SourceMapWrapper {
362 source_map,
363 current_dir: current_dir().unwrap(),
364 };
365 let pretty_printer = SourceMapDisplay {
366 source_map: &source_map_lookup,
367 };
368
369 let symbol_table_display = ImplsDisplay {
370 all_impls,
371 source_map: &pretty_printer,
372 };
373
374 info!("impls: {}", symbol_table_display);
375}
376
377#[must_use]
378pub fn compile_string(script: &str) -> (Program, ModuleRef, SourceMap) {
379 let mut source_map = SourceMap::new(&SeqMap::default()).unwrap();
380 let file_id = 0xffff;
381
382 if let Some(swamp_home) = swamp_registry_path() {
383 source_map.add_mount("registry", &swamp_home).unwrap();
384 }
385
386 source_map.add_mount("crate", Path::new("/tmp/")).unwrap();
387 source_map.add_to_cache("crate", Path::new("test.swamp"), script, file_id);
388
389 let resolved_path_str = vec!["crate".to_string(), "test".to_string()];
390 let compile_options = CompileOptions {
391 show_semantic: false,
392 show_modules: false,
393 show_errors: true,
394 show_types: false,
395 };
396 let program =
397 bootstrap_and_compile(&mut source_map, &resolved_path_str, &compile_options).unwrap();
398 let main_module = program.modules.get(&resolved_path_str).unwrap().clone();
399
400 (program, main_module, source_map)
401}