Fork of daniellemaywood.uk/gleam — Wasm codegen work
54 kB
1859 lines
1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: 2022 The Gleam contributors
3
4#[cfg(test)]
5mod tests;
6
7use std::{
8 collections::{HashMap, HashSet},
9 sync::OnceLock,
10 time::{Duration, SystemTime},
11};
12
13use camino::{Utf8Path, Utf8PathBuf};
14
15// TODO: emit warnings for cached modules even if they are not compiled again.
16
17use ecow::EcoString;
18use itertools::Itertools;
19use regex::Regex;
20use vec1::Vec1;
21
22use crate::{
23 Error, Result,
24 ast::SrcSpan,
25 build::{Module, Origin, module_loader::ModuleLoader},
26 config::PackageConfig,
27 dep_tree,
28 error::{DefinedModuleOrigin, FileIoAction, FileKind, ImportCycleLocationDetails},
29 io::{self, CommandExecutor, FileSystemReader, FileSystemWriter, files_with_extension},
30 metadata,
31 paths::ProjectPaths,
32 type_,
33 uid::UniqueIdGenerator,
34 warning::WarningEmitter,
35};
36
37use super::{
38 Mode, Target,
39 module_loader::read_source,
40 package_compiler::{
41 CacheMetadata, CachedModule, CachedWarnings, Input, Loaded, UncompiledModule,
42 },
43};
44
45#[derive(Debug, Clone, Copy, PartialEq, Eq)]
46pub enum CodegenRequired {
47 Yes,
48 No,
49}
50
51impl CodegenRequired {
52 /// Returns `true` if the codegen required is [`Yes`].
53 ///
54 /// [`Yes`]: CodegenRequired::Yes
55 #[must_use]
56 pub fn is_required(&self) -> bool {
57 matches!(self, Self::Yes)
58 }
59}
60
61#[derive(Debug)]
62pub struct PackageLoader<'a, IO> {
63 io: IO,
64 ids: UniqueIdGenerator,
65 mode: Mode,
66 paths: ProjectPaths,
67 warnings: &'a WarningEmitter,
68 codegen: CodegenRequired,
69 artefact_directory: &'a Utf8Path,
70 package_name: &'a EcoString,
71 target: Target,
72 stale_modules: &'a mut StaleTracker,
73 already_defined_modules: &'a mut im::HashMap<EcoString, DefinedModuleOrigin>,
74 incomplete_modules: &'a HashSet<EcoString>,
75 cached_warnings: CachedWarnings,
76}
77
78impl<'a, IO> PackageLoader<'a, IO>
79where
80 IO: FileSystemWriter + FileSystemReader + CommandExecutor + Clone,
81{
82 pub(crate) fn new(
83 io: IO,
84 ids: UniqueIdGenerator,
85 mode: Mode,
86 root: &'a Utf8Path,
87 cached_warnings: CachedWarnings,
88 warnings: &'a WarningEmitter,
89 codegen: CodegenRequired,
90 artefact_directory: &'a Utf8Path,
91 target: Target,
92 package_name: &'a EcoString,
93 stale_modules: &'a mut StaleTracker,
94 already_defined_modules: &'a mut im::HashMap<EcoString, DefinedModuleOrigin>,
95 incomplete_modules: &'a HashSet<EcoString>,
96 ) -> Self {
97 Self {
98 io,
99 ids,
100 mode,
101 paths: ProjectPaths::new(root.into()),
102 warnings,
103 codegen,
104 target,
105 package_name,
106 cached_warnings,
107 artefact_directory,
108 stale_modules,
109 already_defined_modules,
110 incomplete_modules,
111 }
112 }
113
114 pub(crate) fn run(mut self) -> Result<Loaded> {
115 // First read the source files. This will use the `ModuleLoader`, which
116 // will check the mtimes and hashes of sources and caches to determine
117 // which should be loaded.
118 let mut inputs = self.read_sources_and_caches()?;
119
120 // Check for any removed modules, by looking at cache files that don't exist in inputs.
121 // Delete the cache files for removed modules and mark them as stale
122 // to trigger refreshing dependent modules.
123 for module in CacheFiles::modules_with_meta_files(&self.io, &self.artefact_directory) {
124 if (!inputs.contains_key(&module)) {
125 tracing::debug!(%module, "module_removed");
126 CacheFiles::new(&self.artefact_directory, &module).delete(&self.io)?;
127 self.stale_modules.add(module);
128 }
129 }
130
131 // Determine order in which modules are to be processed
132 let mut dep_location_map = HashMap::new();
133 let deps = inputs
134 .values()
135 .map(|(_, module)| {
136 let name = module.name().clone();
137 let _ = dep_location_map.insert(name.clone(), module);
138 (name, module.dependencies())
139 })
140 // Making sure that the module order is deterministic, to prevent different
141 // compilations of the same project compiling in different orders. This could impact
142 // any bugged outcomes, though not any where the compiler is working correctly, so it's
143 // mostly to aid debugging.
144 .sorted_by(|(a, _), (b, _)| a.cmp(b))
145 .collect();
146 let sequence = dep_tree::toposort_deps(deps)
147 .map_err(|error| self.convert_deps_tree_error(error, dep_location_map))?;
148
149 // Now that we have loaded sources and caches we check to see if any of
150 // the caches need to be invalidated because their dependencies have
151 // changed.
152 let mut loaded = Loaded::default();
153 for name in sequence {
154 let (_, input) = inputs
155 .remove(&name)
156 .expect("Getting parsed module for name");
157
158 match input {
159 // A new uncached module is to be compiled
160 Input::New(module) => {
161 tracing::debug!(module = %module.name, "new_module_to_be_compiled");
162 self.stale_modules.add(module.name.clone());
163 loaded.to_compile.push(module);
164 }
165
166 // A cached module with dependencies that are stale must be
167 // recompiled as the changes in the dependencies may have affect
168 // the output, making the cache invalid.
169 Input::Cached(info) if self.stale_modules.includes_any(&info.dependencies) => {
170 tracing::debug!(module = %info.name, "stale_module_to_be_compiled");
171 self.stale_modules.add(info.name.clone());
172 let module = self.load_stale_module(info)?;
173 loaded.to_compile.push(module);
174 }
175
176 // A cached module with no stale dependencies can be used as-is
177 // and does not need to be recompiled.
178 Input::Cached(info) => {
179 tracing::debug!(module = %info.name, "module_to_load_from_cache");
180 let module = self.load_cached_module(info)?;
181 loaded.cached.push(module);
182 }
183 }
184 }
185
186 Ok(loaded)
187 }
188
189 fn load_cached_module(&self, info: CachedModule) -> Result<type_::ModuleInterface, Error> {
190 let cache_files = CacheFiles::new(&self.artefact_directory, &info.name);
191 let bytes = self.io.read_bytes(&cache_files.cache_path)?;
192 let mut module = match metadata::decode(bytes.as_slice(), self.ids.clone()) {
193 Ok(module) => module,
194 Err(e) => {
195 return Err(Error::FileIo {
196 kind: FileKind::File,
197 action: FileIoAction::Parse,
198 path: cache_files.cache_path,
199 err: Some(e.to_string()),
200 });
201 }
202 };
203
204 // Discard warnings if they should not be cached
205 if !self.cached_warnings.should_use() {
206 module.warnings.clear();
207 }
208
209 Ok(module)
210 }
211
212 fn read_sources_and_caches(
213 &mut self,
214 ) -> Result<HashMap<EcoString, (DefinedModuleOrigin, Input)>> {
215 let span = tracing::info_span!("load");
216 let _enter = span.enter();
217
218 let mut inputs = Inputs::new(self.package_name.clone(), self.already_defined_modules);
219
220 let src = self.paths.src_directory();
221 let mut loader = ModuleLoader {
222 io: self.io.clone(),
223 warnings: self.warnings,
224 mode: self.mode,
225 target: self.target,
226 codegen: self.codegen,
227 package_name: self.package_name,
228 artefact_directory: self.artefact_directory,
229 origin: Origin::Src,
230 incomplete_modules: self.incomplete_modules,
231 };
232
233 // Src
234 for file in GleamFile::iterate_files_in_directory(&self.io, &src) {
235 match file {
236 Ok(file) => {
237 let input = loader.load(file)?;
238 inputs.insert(input)?;
239 }
240 Err(warning) => self.warnings.emit(warning),
241 }
242 }
243
244 // Test and dev
245 if self.mode.includes_dev_code() {
246 let test = self.paths.test_directory();
247 loader.origin = Origin::Test;
248
249 for file in GleamFile::iterate_files_in_directory(&self.io, &test) {
250 match file {
251 Ok(file) => {
252 let input = loader.load(file)?;
253 inputs.insert(input)?;
254 }
255 Err(warning) => self.warnings.emit(warning),
256 }
257 }
258
259 let dev = self.paths.dev_directory();
260 loader.origin = Origin::Dev;
261
262 for file in GleamFile::iterate_files_in_directory(&self.io, &dev) {
263 match file {
264 Ok(file) => {
265 let input = loader.load(file)?;
266 inputs.insert(input)?;
267 }
268 Err(warning) => self.warnings.emit(warning),
269 }
270 }
271 }
272
273 // If we are compiling for Erlang then modules all live in a single
274 // namespace. If we were to name a module the same as a module that
275 // is included in the standard Erlang distribution then this new
276 // Gleam module would overwrite the existing Erlang one, likely
277 // resulting in cryptic errors.
278 // This would most commonly happen for modules like "user" and
279 // "code". Emit an error so this never happens.
280 if self.target.is_erlang() {
281 for (_, input) in inputs.collection.values() {
282 ensure_gleam_module_does_not_overwrite_standard_erlang_module(&input)?;
283 }
284 }
285
286 Ok(inputs.collection)
287 }
288
289 fn load_stale_module(&self, cached: CachedModule) -> Result<UncompiledModule> {
290 let mtime = self.io.modification_time(&cached.source_path)?;
291
292 // We need to delete any existing cache files for this module.
293 // While we figured it out this time because the module has stale dependencies,
294 // next time the dependencies might no longer be stale, but we still need to be able to tell
295 // that this module needs to be recompiled until it successfully compiles at least once.
296 // This can happen if the stale dependency includes breaking changes.
297 CacheFiles::new(&self.artefact_directory, &cached.name).delete(&self.io)?;
298
299 read_source(
300 self.io.clone(),
301 self.target,
302 cached.origin,
303 cached.source_path,
304 cached.name,
305 self.package_name.clone(),
306 mtime,
307 self.warnings.clone(),
308 )
309 }
310
311 fn convert_deps_tree_error(
312 &self,
313 e: dep_tree::Error,
314 dep_location_map: HashMap<EcoString, &Input>,
315 ) -> Error {
316 match e {
317 dep_tree::Error::Cycle(modules) => {
318 let modules = modules
319 .iter()
320 .enumerate()
321 .map(|(i, module)| {
322 // cycles are in order of reference so get next in list or loop back to first
323 let index_of_imported = if i == 0 { modules.len() - 1 } else { i - 1 };
324 let imported_module = modules
325 .get(index_of_imported)
326 .expect("importing module must exist");
327 let input = dep_location_map.get(module).expect("dependency must exist");
328 let location = match input {
329 Input::New(module) => {
330 let (_, location) = module
331 .dependencies
332 .iter()
333 .find(|d| &d.0 == imported_module)
334 .expect("import must exist for there to be a cycle");
335 ImportCycleLocationDetails {
336 location: *location,
337 path: module.path.clone(),
338 src: module.code.clone(),
339 }
340 }
341 Input::Cached(cached_module) => {
342 let (_, location) = cached_module
343 .dependencies
344 .iter()
345 .find(|d| &d.0 == imported_module)
346 .expect("import must exist for there to be a cycle");
347 let src = self
348 .io
349 .read(&cached_module.source_path)
350 .expect("failed to read source")
351 .into();
352 ImportCycleLocationDetails {
353 location: *location,
354 path: cached_module.source_path.clone(),
355 src,
356 }
357 }
358 };
359 (module.clone(), location)
360 })
361 .collect_vec();
362 Error::ImportCycle {
363 modules: Vec1::try_from(modules)
364 .expect("at least 1 module must exist in cycle"),
365 }
366 }
367 }
368 }
369}
370
371fn ensure_gleam_module_does_not_overwrite_standard_erlang_module(input: &Input) -> Result<()> {
372 // We only need to check uncached modules as it's not possible for these
373 // to have compiled successfully.
374 let Input::New(input) = input else {
375 return Ok(());
376 };
377
378 // These names were got with this Erlang
379 //
380 // ```erl
381 // file:write_file("names.txt", lists:join("\n",lists:map(fun(T) -> erlang:element(1, T) end, code:all_available()))).
382 // ```
383 //
384 match input.name.as_str() {
385 "alarm_handler"
386 | "application"
387 | "application_controller"
388 | "application_master"
389 | "application_starter"
390 | "appmon_info"
391 | "argparse"
392 | "array"
393 | "asn1_db"
394 | "asn1ct"
395 | "asn1ct_check"
396 | "asn1ct_constructed_ber_bin_v2"
397 | "asn1ct_constructed_per"
398 | "asn1ct_eval_ext"
399 | "asn1ct_func"
400 | "asn1ct_gen"
401 | "asn1ct_gen_ber_bin_v2"
402 | "asn1ct_gen_check"
403 | "asn1ct_gen_jer"
404 | "asn1ct_gen_per"
405 | "asn1ct_imm"
406 | "asn1ct_name"
407 | "asn1ct_parser2"
408 | "asn1ct_pretty_format"
409 | "asn1ct_rtt"
410 | "asn1ct_table"
411 | "asn1ct_tok"
412 | "asn1ct_value"
413 | "asn1rt_nif"
414 | "atomics"
415 | "auth"
416 | "base64"
417 | "beam_a"
418 | "beam_asm"
419 | "beam_block"
420 | "beam_bounds"
421 | "beam_call_types"
422 | "beam_clean"
423 | "beam_dict"
424 | "beam_digraph"
425 | "beam_disasm"
426 | "beam_flatten"
427 | "beam_jump"
428 | "beam_kernel_to_ssa"
429 | "beam_lib"
430 | "beam_listing"
431 | "beam_opcodes"
432 | "beam_ssa"
433 | "beam_ssa_alias"
434 | "beam_ssa_bc_size"
435 | "beam_ssa_bool"
436 | "beam_ssa_bsm"
437 | "beam_ssa_check"
438 | "beam_ssa_codegen"
439 | "beam_ssa_dead"
440 | "beam_ssa_lint"
441 | "beam_ssa_opt"
442 | "beam_ssa_pp"
443 | "beam_ssa_pre_codegen"
444 | "beam_ssa_private_append"
445 | "beam_ssa_recv"
446 | "beam_ssa_share"
447 | "beam_ssa_throw"
448 | "beam_ssa_type"
449 | "beam_trim"
450 | "beam_types"
451 | "beam_utils"
452 | "beam_validator"
453 | "beam_z"
454 | "binary"
455 | "c"
456 | "calendar"
457 | "cdv_atom_cb"
458 | "cdv_bin_cb"
459 | "cdv_detail_wx"
460 | "cdv_dist_cb"
461 | "cdv_ets_cb"
462 | "cdv_fun_cb"
463 | "cdv_gen_cb"
464 | "cdv_html_wx"
465 | "cdv_info_wx"
466 | "cdv_int_tab_cb"
467 | "cdv_mem_cb"
468 | "cdv_mod_cb"
469 | "cdv_multi_wx"
470 | "cdv_persistent_cb"
471 | "cdv_port_cb"
472 | "cdv_proc_cb"
473 | "cdv_sched_cb"
474 | "cdv_table_wx"
475 | "cdv_term_cb"
476 | "cdv_timer_cb"
477 | "cdv_virtual_list_wx"
478 | "cdv_wx"
479 | "cerl"
480 | "cerl_clauses"
481 | "cerl_inline"
482 | "cerl_prettypr"
483 | "cerl_trees"
484 | "code"
485 | "code_server"
486 | "compile"
487 | "core_lib"
488 | "core_lint"
489 | "core_parse"
490 | "core_pp"
491 | "core_scan"
492 | "counters"
493 | "cover"
494 | "cprof"
495 | "cpu_sup"
496 | "crashdump_viewer"
497 | "crypto"
498 | "crypto_ec_curves"
499 | "ct"
500 | "ct_config"
501 | "ct_config_plain"
502 | "ct_config_xml"
503 | "ct_conn_log_h"
504 | "ct_cover"
505 | "ct_default_gl"
506 | "ct_event"
507 | "ct_framework"
508 | "ct_ftp"
509 | "ct_gen_conn"
510 | "ct_groups"
511 | "ct_hooks"
512 | "ct_hooks_lock"
513 | "ct_logs"
514 | "ct_make"
515 | "ct_master"
516 | "ct_master_event"
517 | "ct_master_logs"
518 | "ct_master_status"
519 | "ct_netconfc"
520 | "ct_property_test"
521 | "ct_release_test"
522 | "ct_repeat"
523 | "ct_rpc"
524 | "ct_run"
525 | "ct_slave"
526 | "ct_snmp"
527 | "ct_ssh"
528 | "ct_suite"
529 | "ct_telnet"
530 | "ct_telnet_client"
531 | "ct_testspec"
532 | "ct_util"
533 | "cth_conn_log"
534 | "cth_log_redirect"
535 | "cth_surefire"
536 | "dbg"
537 | "dbg_debugged"
538 | "dbg_icmd"
539 | "dbg_idb"
540 | "dbg_ieval"
541 | "dbg_iload"
542 | "dbg_iserver"
543 | "dbg_istk"
544 | "dbg_wx_break"
545 | "dbg_wx_break_win"
546 | "dbg_wx_code"
547 | "dbg_wx_filedialog_win"
548 | "dbg_wx_interpret"
549 | "dbg_wx_mon"
550 | "dbg_wx_mon_win"
551 | "dbg_wx_settings"
552 | "dbg_wx_src_view"
553 | "dbg_wx_trace"
554 | "dbg_wx_trace_win"
555 | "dbg_wx_view"
556 | "dbg_wx_win"
557 | "dbg_wx_winman"
558 | "debugger"
559 | "dets"
560 | "dets_server"
561 | "dets_sup"
562 | "dets_utils"
563 | "dets_v9"
564 | "dialyzer"
565 | "dialyzer_analysis_callgraph"
566 | "dialyzer_behaviours"
567 | "dialyzer_callgraph"
568 | "dialyzer_cl"
569 | "dialyzer_cl_parse"
570 | "dialyzer_clean_core"
571 | "dialyzer_codeserver"
572 | "dialyzer_contracts"
573 | "dialyzer_coordinator"
574 | "dialyzer_cplt"
575 | "dialyzer_dataflow"
576 | "dialyzer_dep"
577 | "dialyzer_dot"
578 | "dialyzer_explanation"
579 | "dialyzer_gui_wx"
580 | "dialyzer_incremental"
581 | "dialyzer_iplt"
582 | "dialyzer_options"
583 | "dialyzer_plt"
584 | "dialyzer_succ_typings"
585 | "dialyzer_timing"
586 | "dialyzer_typegraph"
587 | "dialyzer_typesig"
588 | "dialyzer_utils"
589 | "dialyzer_worker"
590 | "diameter"
591 | "diameter_app"
592 | "diameter_callback"
593 | "diameter_capx"
594 | "diameter_codec"
595 | "diameter_codegen"
596 | "diameter_config"
597 | "diameter_config_sup"
598 | "diameter_dbg"
599 | "diameter_dict_parser"
600 | "diameter_dict_scanner"
601 | "diameter_dict_util"
602 | "diameter_dist"
603 | "diameter_etcp"
604 | "diameter_etcp_sup"
605 | "diameter_exprecs"
606 | "diameter_gen"
607 | "diameter_gen_acct_rfc6733"
608 | "diameter_gen_base_accounting"
609 | "diameter_gen_base_rfc3588"
610 | "diameter_gen_base_rfc6733"
611 | "diameter_gen_doic_rfc7683"
612 | "diameter_gen_relay"
613 | "diameter_info"
614 | "diameter_lib"
615 | "diameter_make"
616 | "diameter_misc_sup"
617 | "diameter_peer"
618 | "diameter_peer_fsm"
619 | "diameter_peer_fsm_sup"
620 | "diameter_reg"
621 | "diameter_sctp"
622 | "diameter_sctp_sup"
623 | "diameter_service"
624 | "diameter_service_sup"
625 | "diameter_session"
626 | "diameter_stats"
627 | "diameter_sup"
628 | "diameter_sync"
629 | "diameter_tcp"
630 | "diameter_tcp_sup"
631 | "diameter_traffic"
632 | "diameter_transport"
633 | "diameter_transport_sup"
634 | "diameter_types"
635 | "diameter_watchdog"
636 | "diameter_watchdog_sup"
637 | "dict"
638 | "digraph"
639 | "digraph_utils"
640 | "disk_log"
641 | "disk_log_1"
642 | "disk_log_server"
643 | "disk_log_sup"
644 | "disksup"
645 | "dist_ac"
646 | "dist_util"
647 | "docgen_edoc_xml_cb"
648 | "docgen_otp_specs"
649 | "docgen_xmerl_xml_cb"
650 | "docgen_xml_to_chunk"
651 | "dtls_connection"
652 | "dtls_connection_sup"
653 | "dtls_gen_connection"
654 | "dtls_handshake"
655 | "dtls_listener_sup"
656 | "dtls_packet_demux"
657 | "dtls_record"
658 | "dtls_server_session_cache_sup"
659 | "dtls_server_sup"
660 | "dtls_socket"
661 | "dtls_sup"
662 | "dtls_v1"
663 | "dyntrace"
664 | "edlin"
665 | "edlin_context"
666 | "edlin_expand"
667 | "edlin_key"
668 | "edlin_type_suggestion"
669 | "edoc"
670 | "edoc_cli"
671 | "edoc_data"
672 | "edoc_doclet"
673 | "edoc_doclet_chunks"
674 | "edoc_extract"
675 | "edoc_layout"
676 | "edoc_layout_chunks"
677 | "edoc_lib"
678 | "edoc_macros"
679 | "edoc_parser"
680 | "edoc_refs"
681 | "edoc_report"
682 | "edoc_run"
683 | "edoc_scanner"
684 | "edoc_specs"
685 | "edoc_tags"
686 | "edoc_types"
687 | "edoc_wiki"
688 | "eldap"
689 | "epp"
690 | "epp_dodger"
691 | "eprof"
692 | "erl2html2"
693 | "erl_abstract_code"
694 | "erl_anno"
695 | "erl_bif_types"
696 | "erl_bifs"
697 | "erl_bits"
698 | "erl_boot_server"
699 | "erl_comment_scan"
700 | "erl_compile"
701 | "erl_compile_server"
702 | "erl_ddll"
703 | "erl_distribution"
704 | "erl_epmd"
705 | "erl_error"
706 | "erl_erts_errors"
707 | "erl_eval"
708 | "erl_expand_records"
709 | "erl_features"
710 | "erl_init"
711 | "erl_internal"
712 | "erl_kernel_errors"
713 | "erl_lint"
714 | "erl_parse"
715 | "erl_posix_msg"
716 | "erl_pp"
717 | "erl_prettypr"
718 | "erl_prim_loader"
719 | "erl_recomment"
720 | "erl_reply"
721 | "erl_scan"
722 | "erl_signal_handler"
723 | "erl_stdlib_errors"
724 | "erl_syntax"
725 | "erl_syntax_lib"
726 | "erl_tar"
727 | "erl_tracer"
728 | "erl_types"
729 | "erlang"
730 | "erlsrv"
731 | "erpc"
732 | "error_handler"
733 | "error_logger"
734 | "error_logger_file_h"
735 | "error_logger_tty_h"
736 | "erts_alloc_config"
737 | "erts_code_purger"
738 | "erts_debug"
739 | "erts_dirty_process_signal_handler"
740 | "erts_internal"
741 | "erts_literal_area_collector"
742 | "escript"
743 | "et"
744 | "et_collector"
745 | "et_selector"
746 | "et_viewer"
747 | "et_wx_contents_viewer"
748 | "et_wx_viewer"
749 | "etop"
750 | "etop_tr"
751 | "etop_txt"
752 | "ets"
753 | "eunit"
754 | "eunit_autoexport"
755 | "eunit_data"
756 | "eunit_lib"
757 | "eunit_listener"
758 | "eunit_proc"
759 | "eunit_serial"
760 | "eunit_server"
761 | "eunit_striptests"
762 | "eunit_surefire"
763 | "eunit_test"
764 | "eunit_tests"
765 | "eunit_tty"
766 | "eval_bits"
767 | "file"
768 | "file_io_server"
769 | "file_server"
770 | "file_sorter"
771 | "filelib"
772 | "filename"
773 | "format_lib_supp"
774 | "fprof"
775 | "ftp"
776 | "ftp_app"
777 | "ftp_internal"
778 | "ftp_progress"
779 | "ftp_response"
780 | "ftp_sup"
781 | "gb_sets"
782 | "gb_trees"
783 | "gen"
784 | "gen_event"
785 | "gen_fsm"
786 | "gen_sctp"
787 | "gen_server"
788 | "gen_statem"
789 | "gen_tcp"
790 | "gen_tcp_socket"
791 | "gen_udp"
792 | "gen_udp_socket"
793 | "gl"
794 | "global"
795 | "global_group"
796 | "global_search"
797 | "glu"
798 | "group"
799 | "group_history"
800 | "heart"
801 | "http_chunk"
802 | "http_request"
803 | "http_response"
804 | "http_transport"
805 | "http_uri"
806 | "http_util"
807 | "httpc"
808 | "httpc_cookie"
809 | "httpc_handler"
810 | "httpc_handler_sup"
811 | "httpc_manager"
812 | "httpc_profile_sup"
813 | "httpc_request"
814 | "httpc_response"
815 | "httpc_sup"
816 | "httpd"
817 | "httpd_acceptor"
818 | "httpd_acceptor_sup"
819 | "httpd_cgi"
820 | "httpd_conf"
821 | "httpd_connection_sup"
822 | "httpd_custom"
823 | "httpd_custom_api"
824 | "httpd_esi"
825 | "httpd_example"
826 | "httpd_file"
827 | "httpd_instance_sup"
828 | "httpd_log"
829 | "httpd_logger"
830 | "httpd_manager"
831 | "httpd_misc_sup"
832 | "httpd_request"
833 | "httpd_request_handler"
834 | "httpd_response"
835 | "httpd_script_env"
836 | "httpd_socket"
837 | "httpd_sup"
838 | "httpd_util"
839 | "i"
840 | "inet"
841 | "inet6_sctp"
842 | "inet6_tcp"
843 | "inet6_tcp_dist"
844 | "inet6_tls_dist"
845 | "inet6_udp"
846 | "inet_config"
847 | "inet_db"
848 | "inet_dns"
849 | "inet_epmd_dist"
850 | "inet_epmd_socket"
851 | "inet_gethost_native"
852 | "inet_hosts"
853 | "inet_parse"
854 | "inet_res"
855 | "inet_sctp"
856 | "inet_tcp"
857 | "inet_tcp_dist"
858 | "inet_tls_dist"
859 | "inet_udp"
860 | "inets"
861 | "inets_app"
862 | "inets_lib"
863 | "inets_service"
864 | "inets_sup"
865 | "inets_trace"
866 | "init"
867 | "instrument"
868 | "int"
869 | "io"
870 | "io_lib"
871 | "io_lib_format"
872 | "io_lib_fread"
873 | "io_lib_pretty"
874 | "json"
875 | "kernel"
876 | "kernel_config"
877 | "kernel_refc"
878 | "lcnt"
879 | "leex"
880 | "lists"
881 | "local_tcp"
882 | "local_udp"
883 | "log_mf_h"
884 | "logger"
885 | "logger_backend"
886 | "logger_config"
887 | "logger_disk_log_h"
888 | "logger_filters"
889 | "logger_formatter"
890 | "logger_h_common"
891 | "logger_handler_watcher"
892 | "logger_olp"
893 | "logger_proxy"
894 | "logger_server"
895 | "logger_simple_h"
896 | "logger_std_h"
897 | "logger_sup"
898 | "make"
899 | "maps"
900 | "math"
901 | "megaco"
902 | "megaco_ber_encoder"
903 | "megaco_ber_media_gateway_control_v1"
904 | "megaco_ber_media_gateway_control_v2"
905 | "megaco_ber_media_gateway_control_v3"
906 | "megaco_binary_encoder"
907 | "megaco_binary_encoder_lib"
908 | "megaco_binary_name_resolver_v1"
909 | "megaco_binary_name_resolver_v2"
910 | "megaco_binary_name_resolver_v3"
911 | "megaco_binary_term_id"
912 | "megaco_binary_term_id_gen"
913 | "megaco_binary_transformer_v1"
914 | "megaco_binary_transformer_v2"
915 | "megaco_binary_transformer_v3"
916 | "megaco_compact_text_encoder"
917 | "megaco_compact_text_encoder_v1"
918 | "megaco_compact_text_encoder_v2"
919 | "megaco_compact_text_encoder_v3"
920 | "megaco_config"
921 | "megaco_config_misc"
922 | "megaco_digit_map"
923 | "megaco_edist_compress"
924 | "megaco_encoder"
925 | "megaco_erl_dist_encoder"
926 | "megaco_erl_dist_encoder_mc"
927 | "megaco_filter"
928 | "megaco_flex_scanner"
929 | "megaco_flex_scanner_handler"
930 | "megaco_messenger"
931 | "megaco_messenger_misc"
932 | "megaco_misc_sup"
933 | "megaco_monitor"
934 | "megaco_per_encoder"
935 | "megaco_per_media_gateway_control_v1"
936 | "megaco_per_media_gateway_control_v2"
937 | "megaco_per_media_gateway_control_v3"
938 | "megaco_pretty_text_encoder"
939 | "megaco_pretty_text_encoder_v1"
940 | "megaco_pretty_text_encoder_v2"
941 | "megaco_pretty_text_encoder_v3"
942 | "megaco_sdp"
943 | "megaco_stats"
944 | "megaco_sup"
945 | "megaco_tcp"
946 | "megaco_tcp_accept"
947 | "megaco_tcp_accept_sup"
948 | "megaco_tcp_connection"
949 | "megaco_tcp_connection_sup"
950 | "megaco_tcp_sup"
951 | "megaco_text_mini_decoder"
952 | "megaco_text_mini_parser"
953 | "megaco_text_parser_v1"
954 | "megaco_text_parser_v2"
955 | "megaco_text_parser_v3"
956 | "megaco_text_scanner"
957 | "megaco_timer"
958 | "megaco_trans_sender"
959 | "megaco_trans_sup"
960 | "megaco_transport"
961 | "megaco_udp"
962 | "megaco_udp_server"
963 | "megaco_udp_sup"
964 | "megaco_user"
965 | "megaco_user_default"
966 | "memsup"
967 | "merl"
968 | "merl_transform"
969 | "misc_supp"
970 | "mnesia"
971 | "mnesia_app"
972 | "mnesia_backend_type"
973 | "mnesia_backup"
974 | "mnesia_bup"
975 | "mnesia_checkpoint"
976 | "mnesia_checkpoint_sup"
977 | "mnesia_controller"
978 | "mnesia_dumper"
979 | "mnesia_event"
980 | "mnesia_ext_sup"
981 | "mnesia_frag"
982 | "mnesia_frag_hash"
983 | "mnesia_index"
984 | "mnesia_kernel_sup"
985 | "mnesia_late_loader"
986 | "mnesia_lib"
987 | "mnesia_loader"
988 | "mnesia_locker"
989 | "mnesia_log"
990 | "mnesia_monitor"
991 | "mnesia_recover"
992 | "mnesia_registry"
993 | "mnesia_rpc"
994 | "mnesia_schema"
995 | "mnesia_snmp_hook"
996 | "mnesia_sp"
997 | "mnesia_subscr"
998 | "mnesia_sup"
999 | "mnesia_text"
1000 | "mnesia_tm"
1001 | "mod_actions"
1002 | "mod_alias"
1003 | "mod_auth"
1004 | "mod_auth_dets"
1005 | "mod_auth_mnesia"
1006 | "mod_auth_plain"
1007 | "mod_auth_server"
1008 | "mod_cgi"
1009 | "mod_dir"
1010 | "mod_disk_log"
1011 | "mod_esi"
1012 | "mod_get"
1013 | "mod_head"
1014 | "mod_log"
1015 | "mod_range"
1016 | "mod_responsecontrol"
1017 | "mod_security"
1018 | "mod_security_server"
1019 | "mod_trace"
1020 | "ms_transform"
1021 | "msacc"
1022 | "net"
1023 | "net_adm"
1024 | "net_kernel"
1025 | "nteventlog"
1026 | "observer"
1027 | "observer_alloc_wx"
1028 | "observer_app_wx"
1029 | "observer_backend"
1030 | "observer_html_lib"
1031 | "observer_lib"
1032 | "observer_perf_wx"
1033 | "observer_port_wx"
1034 | "observer_pro_wx"
1035 | "observer_procinfo"
1036 | "observer_sock_wx"
1037 | "observer_sys_wx"
1038 | "observer_trace_wx"
1039 | "observer_traceoptions_wx"
1040 | "observer_tv_table"
1041 | "observer_tv_wx"
1042 | "observer_wx"
1043 | "orddict"
1044 | "ordsets"
1045 | "os"
1046 | "os_mon"
1047 | "os_mon_mib"
1048 | "os_mon_sysinfo"
1049 | "os_sup"
1050 | "otp_internal"
1051 | "peer"
1052 | "persistent_term"
1053 | "pg"
1054 | "pg2"
1055 | "pool"
1056 | "prettypr"
1057 | "prim_buffer"
1058 | "prim_eval"
1059 | "prim_file"
1060 | "prim_inet"
1061 | "prim_net"
1062 | "prim_socket"
1063 | "prim_tty"
1064 | "prim_zip"
1065 | "proc_lib"
1066 | "proplists"
1067 | "pubkey_cert"
1068 | "pubkey_cert_records"
1069 | "pubkey_crl"
1070 | "pubkey_ocsp"
1071 | "pubkey_os_cacerts"
1072 | "pubkey_pbe"
1073 | "pubkey_pem"
1074 | "pubkey_policy_tree"
1075 | "pubkey_ssh"
1076 | "public_key"
1077 | "qlc"
1078 | "qlc_pt"
1079 | "queue"
1080 | "ram_file"
1081 | "rand"
1082 | "random"
1083 | "raw_file_io"
1084 | "raw_file_io_compressed"
1085 | "raw_file_io_deflate"
1086 | "raw_file_io_delayed"
1087 | "raw_file_io_inflate"
1088 | "raw_file_io_list"
1089 | "rb"
1090 | "rb_format_supp"
1091 | "re"
1092 | "rec_env"
1093 | "release_handler"
1094 | "release_handler_1"
1095 | "reltool"
1096 | "reltool_app_win"
1097 | "reltool_fgraph"
1098 | "reltool_fgraph_win"
1099 | "reltool_mod_win"
1100 | "reltool_server"
1101 | "reltool_sys_win"
1102 | "reltool_target"
1103 | "reltool_utils"
1104 | "rpc"
1105 | "runtime_tools"
1106 | "runtime_tools_sup"
1107 | "sasl"
1108 | "sasl_report"
1109 | "sasl_report_file_h"
1110 | "sasl_report_tty_h"
1111 | "scheduler"
1112 | "seq_trace"
1113 | "sets"
1114 | "shell"
1115 | "shell_default"
1116 | "shell_docs"
1117 | "slave"
1118 | "snmp"
1119 | "snmp_app"
1120 | "snmp_app_sup"
1121 | "snmp_community_mib"
1122 | "snmp_conf"
1123 | "snmp_config"
1124 | "snmp_framework_mib"
1125 | "snmp_generic"
1126 | "snmp_generic_mnesia"
1127 | "snmp_index"
1128 | "snmp_log"
1129 | "snmp_mini_mib"
1130 | "snmp_misc"
1131 | "snmp_note_store"
1132 | "snmp_notification_mib"
1133 | "snmp_pdus"
1134 | "snmp_shadow_table"
1135 | "snmp_standard_mib"
1136 | "snmp_target_mib"
1137 | "snmp_user_based_sm_mib"
1138 | "snmp_usm"
1139 | "snmp_verbosity"
1140 | "snmp_view_based_acm_mib"
1141 | "snmpa"
1142 | "snmpa_acm"
1143 | "snmpa_agent"
1144 | "snmpa_agent_sup"
1145 | "snmpa_app"
1146 | "snmpa_authentication_service"
1147 | "snmpa_conf"
1148 | "snmpa_discovery_handler"
1149 | "snmpa_discovery_handler_default"
1150 | "snmpa_error"
1151 | "snmpa_error_io"
1152 | "snmpa_error_logger"
1153 | "snmpa_error_report"
1154 | "snmpa_get"
1155 | "snmpa_get_lib"
1156 | "snmpa_get_mechanism"
1157 | "snmpa_local_db"
1158 | "snmpa_mib"
1159 | "snmpa_mib_data"
1160 | "snmpa_mib_data_tttn"
1161 | "snmpa_mib_lib"
1162 | "snmpa_mib_storage"
1163 | "snmpa_mib_storage_dets"
1164 | "snmpa_mib_storage_ets"
1165 | "snmpa_mib_storage_mnesia"
1166 | "snmpa_misc_sup"
1167 | "snmpa_mpd"
1168 | "snmpa_net_if"
1169 | "snmpa_net_if_filter"
1170 | "snmpa_network_interface"
1171 | "snmpa_network_interface_filter"
1172 | "snmpa_notification_delivery_info_receiver"
1173 | "snmpa_notification_filter"
1174 | "snmpa_set"
1175 | "snmpa_set_lib"
1176 | "snmpa_set_mechanism"
1177 | "snmpa_supervisor"
1178 | "snmpa_svbl"
1179 | "snmpa_symbolic_store"
1180 | "snmpa_target_cache"
1181 | "snmpa_trap"
1182 | "snmpa_usm"
1183 | "snmpa_vacm"
1184 | "snmpc"
1185 | "snmpc_lib"
1186 | "snmpc_mib_gram"
1187 | "snmpc_mib_to_hrl"
1188 | "snmpc_misc"
1189 | "snmpc_tok"
1190 | "snmpm"
1191 | "snmpm_conf"
1192 | "snmpm_config"
1193 | "snmpm_misc_sup"
1194 | "snmpm_mpd"
1195 | "snmpm_net_if"
1196 | "snmpm_net_if_filter"
1197 | "snmpm_net_if_mt"
1198 | "snmpm_network_interface"
1199 | "snmpm_network_interface_filter"
1200 | "snmpm_server"
1201 | "snmpm_server_sup"
1202 | "snmpm_supervisor"
1203 | "snmpm_user"
1204 | "snmpm_user_default"
1205 | "snmpm_user_old"
1206 | "snmpm_usm"
1207 | "socket"
1208 | "socket_registry"
1209 | "sofs"
1210 | "ssh"
1211 | "ssh_acceptor"
1212 | "ssh_acceptor_sup"
1213 | "ssh_agent"
1214 | "ssh_app"
1215 | "ssh_auth"
1216 | "ssh_bits"
1217 | "ssh_channel"
1218 | "ssh_channel_sup"
1219 | "ssh_cli"
1220 | "ssh_client_channel"
1221 | "ssh_client_key_api"
1222 | "ssh_connection"
1223 | "ssh_connection_handler"
1224 | "ssh_daemon_channel"
1225 | "ssh_dbg"
1226 | "ssh_file"
1227 | "ssh_fsm_kexinit"
1228 | "ssh_fsm_userauth_client"
1229 | "ssh_fsm_userauth_server"
1230 | "ssh_info"
1231 | "ssh_io"
1232 | "ssh_lib"
1233 | "ssh_message"
1234 | "ssh_no_io"
1235 | "ssh_options"
1236 | "ssh_server_channel"
1237 | "ssh_server_key_api"
1238 | "ssh_sftp"
1239 | "ssh_sftpd"
1240 | "ssh_sftpd_file"
1241 | "ssh_sftpd_file_api"
1242 | "ssh_shell"
1243 | "ssh_subsystem_sup"
1244 | "ssh_system_sup"
1245 | "ssh_tcpip_forward_acceptor"
1246 | "ssh_tcpip_forward_acceptor_sup"
1247 | "ssh_tcpip_forward_client"
1248 | "ssh_tcpip_forward_srv"
1249 | "ssh_transport"
1250 | "ssh_xfer"
1251 | "ssl"
1252 | "ssl_admin_sup"
1253 | "ssl_alert"
1254 | "ssl_app"
1255 | "ssl_certificate"
1256 | "ssl_cipher"
1257 | "ssl_cipher_format"
1258 | "ssl_client_session_cache_db"
1259 | "ssl_config"
1260 | "ssl_connection_sup"
1261 | "ssl_crl"
1262 | "ssl_crl_cache"
1263 | "ssl_crl_cache_api"
1264 | "ssl_crl_hash_dir"
1265 | "ssl_dh_groups"
1266 | "ssl_dist_admin_sup"
1267 | "ssl_dist_connection_sup"
1268 | "ssl_dist_sup"
1269 | "ssl_gen_statem"
1270 | "ssl_handshake"
1271 | "ssl_listen_tracker_sup"
1272 | "ssl_logger"
1273 | "ssl_manager"
1274 | "ssl_pem_cache"
1275 | "ssl_pkix_db"
1276 | "ssl_record"
1277 | "ssl_server_session_cache"
1278 | "ssl_server_session_cache_db"
1279 | "ssl_server_session_cache_sup"
1280 | "ssl_session"
1281 | "ssl_session_cache_api"
1282 | "ssl_srp_primes"
1283 | "ssl_sup"
1284 | "ssl_trace"
1285 | "ssl_upgrade_server_session_cache_sup"
1286 | "standard_error"
1287 | "string"
1288 | "supervisor"
1289 | "supervisor_bridge"
1290 | "sys"
1291 | "sys_core_alias"
1292 | "sys_core_bsm"
1293 | "sys_core_fold"
1294 | "sys_core_fold_lists"
1295 | "sys_core_inline"
1296 | "sys_core_prepare"
1297 | "sys_messages"
1298 | "sys_pre_attributes"
1299 | "system_information"
1300 | "systools"
1301 | "systools_lib"
1302 | "systools_make"
1303 | "systools_rc"
1304 | "systools_relup"
1305 | "tags"
1306 | "test_server"
1307 | "test_server_ctrl"
1308 | "test_server_gl"
1309 | "test_server_io"
1310 | "test_server_node"
1311 | "test_server_sup"
1312 | "tftp"
1313 | "tftp_app"
1314 | "tftp_binary"
1315 | "tftp_engine"
1316 | "tftp_file"
1317 | "tftp_lib"
1318 | "tftp_logger"
1319 | "tftp_sup"
1320 | "timer"
1321 | "tls_bloom_filter"
1322 | "tls_client_connection_1_3"
1323 | "tls_client_ticket_store"
1324 | "tls_connection"
1325 | "tls_connection_sup"
1326 | "tls_dist_server_sup"
1327 | "tls_dist_sup"
1328 | "tls_dtls_connection"
1329 | "tls_dyn_connection_sup"
1330 | "tls_gen_connection"
1331 | "tls_gen_connection_1_3"
1332 | "tls_handshake"
1333 | "tls_handshake_1_3"
1334 | "tls_record"
1335 | "tls_record_1_3"
1336 | "tls_sender"
1337 | "tls_server_connection_1_3"
1338 | "tls_server_session_ticket"
1339 | "tls_server_session_ticket_sup"
1340 | "tls_server_sup"
1341 | "tls_socket"
1342 | "tls_sup"
1343 | "tls_v1"
1344 | "ttb"
1345 | "ttb_autostart"
1346 | "ttb_et"
1347 | "typer"
1348 | "typer_core"
1349 | "unicode"
1350 | "unicode_util"
1351 | "unix_telnet"
1352 | "uri_string"
1353 | "user_drv"
1354 | "user_sup"
1355 | "v3_core"
1356 | "v3_kernel"
1357 | "v3_kernel_pp"
1358 | "win32reg"
1359 | "wrap_log_reader"
1360 | "wx"
1361 | "wxAcceleratorEntry"
1362 | "wxAcceleratorTable"
1363 | "wxActivateEvent"
1364 | "wxArtProvider"
1365 | "wxAuiDockArt"
1366 | "wxAuiManager"
1367 | "wxAuiManagerEvent"
1368 | "wxAuiNotebook"
1369 | "wxAuiNotebookEvent"
1370 | "wxAuiPaneInfo"
1371 | "wxAuiSimpleTabArt"
1372 | "wxAuiTabArt"
1373 | "wxBitmap"
1374 | "wxBitmapButton"
1375 | "wxBitmapDataObject"
1376 | "wxBookCtrlBase"
1377 | "wxBookCtrlEvent"
1378 | "wxBoxSizer"
1379 | "wxBrush"
1380 | "wxBufferedDC"
1381 | "wxBufferedPaintDC"
1382 | "wxButton"
1383 | "wxCalendarCtrl"
1384 | "wxCalendarDateAttr"
1385 | "wxCalendarEvent"
1386 | "wxCaret"
1387 | "wxCheckBox"
1388 | "wxCheckListBox"
1389 | "wxChildFocusEvent"
1390 | "wxChoice"
1391 | "wxChoicebook"
1392 | "wxClientDC"
1393 | "wxClipboard"
1394 | "wxClipboardTextEvent"
1395 | "wxCloseEvent"
1396 | "wxColourData"
1397 | "wxColourDialog"
1398 | "wxColourPickerCtrl"
1399 | "wxColourPickerEvent"
1400 | "wxComboBox"
1401 | "wxCommandEvent"
1402 | "wxContextMenuEvent"
1403 | "wxControl"
1404 | "wxControlWithItems"
1405 | "wxCursor"
1406 | "wxDC"
1407 | "wxDCOverlay"
1408 | "wxDataObject"
1409 | "wxDateEvent"
1410 | "wxDatePickerCtrl"
1411 | "wxDialog"
1412 | "wxDirDialog"
1413 | "wxDirPickerCtrl"
1414 | "wxDisplay"
1415 | "wxDisplayChangedEvent"
1416 | "wxDropFilesEvent"
1417 | "wxEraseEvent"
1418 | "wxEvent"
1419 | "wxEvtHandler"
1420 | "wxFileDataObject"
1421 | "wxFileDialog"
1422 | "wxFileDirPickerEvent"
1423 | "wxFilePickerCtrl"
1424 | "wxFindReplaceData"
1425 | "wxFindReplaceDialog"
1426 | "wxFlexGridSizer"
1427 | "wxFocusEvent"
1428 | "wxFont"
1429 | "wxFontData"
1430 | "wxFontDialog"
1431 | "wxFontPickerCtrl"
1432 | "wxFontPickerEvent"
1433 | "wxFrame"
1434 | "wxGBSizerItem"
1435 | "wxGCDC"
1436 | "wxGLCanvas"
1437 | "wxGLContext"
1438 | "wxGauge"
1439 | "wxGenericDirCtrl"
1440 | "wxGraphicsBrush"
1441 | "wxGraphicsContext"
1442 | "wxGraphicsFont"
1443 | "wxGraphicsGradientStops"
1444 | "wxGraphicsMatrix"
1445 | "wxGraphicsObject"
1446 | "wxGraphicsPath"
1447 | "wxGraphicsPen"
1448 | "wxGraphicsRenderer"
1449 | "wxGrid"
1450 | "wxGridBagSizer"
1451 | "wxGridCellAttr"
1452 | "wxGridCellBoolEditor"
1453 | "wxGridCellBoolRenderer"
1454 | "wxGridCellChoiceEditor"
1455 | "wxGridCellEditor"
1456 | "wxGridCellFloatEditor"
1457 | "wxGridCellFloatRenderer"
1458 | "wxGridCellNumberEditor"
1459 | "wxGridCellNumberRenderer"
1460 | "wxGridCellRenderer"
1461 | "wxGridCellStringRenderer"
1462 | "wxGridCellTextEditor"
1463 | "wxGridEvent"
1464 | "wxGridSizer"
1465 | "wxHelpEvent"
1466 | "wxHtmlEasyPrinting"
1467 | "wxHtmlLinkEvent"
1468 | "wxHtmlWindow"
1469 | "wxIcon"
1470 | "wxIconBundle"
1471 | "wxIconizeEvent"
1472 | "wxIdleEvent"
1473 | "wxImage"
1474 | "wxImageList"
1475 | "wxInitDialogEvent"
1476 | "wxJoystickEvent"
1477 | "wxKeyEvent"
1478 | "wxLayoutAlgorithm"
1479 | "wxListBox"
1480 | "wxListCtrl"
1481 | "wxListEvent"
1482 | "wxListItem"
1483 | "wxListItemAttr"
1484 | "wxListView"
1485 | "wxListbook"
1486 | "wxLocale"
1487 | "wxLogNull"
1488 | "wxMDIChildFrame"
1489 | "wxMDIClientWindow"
1490 | "wxMDIParentFrame"
1491 | "wxMask"
1492 | "wxMaximizeEvent"
1493 | "wxMemoryDC"
1494 | "wxMenu"
1495 | "wxMenuBar"
1496 | "wxMenuEvent"
1497 | "wxMenuItem"
1498 | "wxMessageDialog"
1499 | "wxMiniFrame"
1500 | "wxMirrorDC"
1501 | "wxMouseCaptureChangedEvent"
1502 | "wxMouseCaptureLostEvent"
1503 | "wxMouseEvent"
1504 | "wxMoveEvent"
1505 | "wxMultiChoiceDialog"
1506 | "wxNavigationKeyEvent"
1507 | "wxNotebook"
1508 | "wxNotificationMessage"
1509 | "wxNotifyEvent"
1510 | "wxOverlay"
1511 | "wxPageSetupDialog"
1512 | "wxPageSetupDialogData"
1513 | "wxPaintDC"
1514 | "wxPaintEvent"
1515 | "wxPalette"
1516 | "wxPaletteChangedEvent"
1517 | "wxPanel"
1518 | "wxPasswordEntryDialog"
1519 | "wxPen"
1520 | "wxPickerBase"
1521 | "wxPopupTransientWindow"
1522 | "wxPopupWindow"
1523 | "wxPostScriptDC"
1524 | "wxPreviewCanvas"
1525 | "wxPreviewControlBar"
1526 | "wxPreviewFrame"
1527 | "wxPrintData"
1528 | "wxPrintDialog"
1529 | "wxPrintDialogData"
1530 | "wxPrintPreview"
1531 | "wxPrinter"
1532 | "wxPrintout"
1533 | "wxProgressDialog"
1534 | "wxQueryNewPaletteEvent"
1535 | "wxRadioBox"
1536 | "wxRadioButton"
1537 | "wxRegion"
1538 | "wxSashEvent"
1539 | "wxSashLayoutWindow"
1540 | "wxSashWindow"
1541 | "wxScreenDC"
1542 | "wxScrollBar"
1543 | "wxScrollEvent"
1544 | "wxScrollWinEvent"
1545 | "wxScrolledWindow"
1546 | "wxSetCursorEvent"
1547 | "wxShowEvent"
1548 | "wxSingleChoiceDialog"
1549 | "wxSizeEvent"
1550 | "wxSizer"
1551 | "wxSizerFlags"
1552 | "wxSizerItem"
1553 | "wxSlider"
1554 | "wxSpinButton"
1555 | "wxSpinCtrl"
1556 | "wxSpinEvent"
1557 | "wxSplashScreen"
1558 | "wxSplitterEvent"
1559 | "wxSplitterWindow"
1560 | "wxStaticBitmap"
1561 | "wxStaticBox"
1562 | "wxStaticBoxSizer"
1563 | "wxStaticLine"
1564 | "wxStaticText"
1565 | "wxStatusBar"
1566 | "wxStdDialogButtonSizer"
1567 | "wxStyledTextCtrl"
1568 | "wxStyledTextEvent"
1569 | "wxSysColourChangedEvent"
1570 | "wxSystemOptions"
1571 | "wxSystemSettings"
1572 | "wxTaskBarIcon"
1573 | "wxTaskBarIconEvent"
1574 | "wxTextAttr"
1575 | "wxTextCtrl"
1576 | "wxTextDataObject"
1577 | "wxTextEntryDialog"
1578 | "wxToggleButton"
1579 | "wxToolBar"
1580 | "wxToolTip"
1581 | "wxToolbook"
1582 | "wxTopLevelWindow"
1583 | "wxTreeCtrl"
1584 | "wxTreeEvent"
1585 | "wxTreebook"
1586 | "wxUpdateUIEvent"
1587 | "wxWebView"
1588 | "wxWebViewEvent"
1589 | "wxWindow"
1590 | "wxWindowCreateEvent"
1591 | "wxWindowDC"
1592 | "wxWindowDestroyEvent"
1593 | "wxXmlResource"
1594 | "wx_misc"
1595 | "wx_object"
1596 | "wxe_master"
1597 | "wxe_server"
1598 | "wxe_util"
1599 | "xmerl"
1600 | "xmerl_b64Bin"
1601 | "xmerl_b64Bin_scan"
1602 | "xmerl_eventp"
1603 | "xmerl_html"
1604 | "xmerl_lib"
1605 | "xmerl_otpsgml"
1606 | "xmerl_regexp"
1607 | "xmerl_sax_old_dom"
1608 | "xmerl_sax_parser"
1609 | "xmerl_sax_parser_latin1"
1610 | "xmerl_sax_parser_list"
1611 | "xmerl_sax_parser_utf16be"
1612 | "xmerl_sax_parser_utf16le"
1613 | "xmerl_sax_parser_utf8"
1614 | "xmerl_sax_simple_dom"
1615 | "xmerl_scan"
1616 | "xmerl_sgml"
1617 | "xmerl_simple"
1618 | "xmerl_text"
1619 | "xmerl_ucs"
1620 | "xmerl_uri"
1621 | "xmerl_validate"
1622 | "xmerl_xlate"
1623 | "xmerl_xml"
1624 | "xmerl_xpath"
1625 | "xmerl_xpath_lib"
1626 | "xmerl_xpath_parse"
1627 | "xmerl_xpath_pred"
1628 | "xmerl_xpath_scan"
1629 | "xmerl_xs"
1630 | "xmerl_xsd"
1631 | "xmerl_xsd_type"
1632 | "xref"
1633 | "xref_base"
1634 | "xref_compiler"
1635 | "xref_parser"
1636 | "xref_reader"
1637 | "xref_scanner"
1638 | "xref_utils"
1639 | "yecc"
1640 | "yeccparser"
1641 | "yeccscan"
1642 | "zip"
1643 | "zlib" => (),
1644 _ => return Ok(()),
1645 }
1646
1647 Err(Error::GleamModuleWouldOverwriteStandardErlangModule {
1648 name: input.name.clone(),
1649 path: input.path.to_owned(),
1650 })
1651}
1652#[derive(Debug, Default)]
1653pub struct StaleTracker(HashSet<EcoString>);
1654
1655impl StaleTracker {
1656 fn add(&mut self, name: EcoString) {
1657 _ = self.0.insert(name);
1658 }
1659
1660 fn includes_any(&self, names: &[(EcoString, SrcSpan)]) -> bool {
1661 names.iter().any(|n| self.0.contains(n.0.as_str()))
1662 }
1663
1664 pub fn empty(&mut self) {
1665 let _ = self.0.drain(); // Clears the set but retains allocated memory
1666 }
1667
1668 pub fn is_empty(&self) -> bool {
1669 self.0.is_empty()
1670 }
1671}
1672
1673#[derive(Debug)]
1674pub struct Inputs<'a> {
1675 /// The name of the package for which we're loading the inputs.
1676 package: EcoString,
1677 collection: HashMap<EcoString, (DefinedModuleOrigin, Input)>,
1678 already_defined_modules: &'a mut im::HashMap<EcoString, DefinedModuleOrigin>,
1679}
1680
1681impl<'a> Inputs<'a> {
1682 fn new(
1683 package: EcoString,
1684 already_defined_modules: &'a mut im::HashMap<EcoString, DefinedModuleOrigin>,
1685 ) -> Self {
1686 Self {
1687 package,
1688 collection: HashMap::new(),
1689 already_defined_modules,
1690 }
1691 }
1692
1693 /// Insert a module into the hashmap. If there is already a module with the
1694 /// same name then an error is returned.
1695 fn insert(&mut self, input: Input) -> Result<()> {
1696 let name = input.name().clone();
1697
1698 let origin = DefinedModuleOrigin {
1699 package_name: self.package.clone(),
1700 path: input.source_path().to_path_buf(),
1701 };
1702
1703 if let Some(first) = self
1704 .already_defined_modules
1705 .insert(name.clone(), origin.clone())
1706 {
1707 return Err(Error::DuplicateModule {
1708 module: name.clone(),
1709 first,
1710 second: origin,
1711 });
1712 }
1713
1714 if let Some((first, _)) = self
1715 .collection
1716 .insert(name.clone(), (origin.clone(), input))
1717 {
1718 return Err(Error::DuplicateModule {
1719 module: name,
1720 first,
1721 second: origin,
1722 });
1723 }
1724
1725 Ok(())
1726 }
1727}
1728
1729/// A Gleam source file (`.gleam`) and the module name deduced from it
1730pub struct GleamFile {
1731 pub path: Utf8PathBuf,
1732 pub module_name: EcoString,
1733}
1734
1735static IS_GLEAM_PATH_PATTERN: OnceLock<Regex> = OnceLock::new();
1736
1737impl GleamFile {
1738 pub fn new(dir: &Utf8Path, path: Utf8PathBuf) -> Self {
1739 Self {
1740 module_name: Self::module_name(&path, &dir),
1741 path,
1742 }
1743 }
1744
1745 /// Iterates over Gleam source files (`.gleam`) in a certain directory.
1746 /// Symlinks are followed.
1747 /// If the there is a .gleam file with a path that would be an
1748 /// invalid module name it should not be loaded. For example, if it
1749 /// has a uppercase letter in it.
1750 pub fn iterate_files_in_directory<'b>(
1751 io: &'b impl FileSystemReader,
1752 dir: &'b Utf8Path,
1753 ) -> impl Iterator<Item = Result<Self, crate::Warning>> + 'b {
1754 tracing::trace!("gleam_source_files {:?}", dir);
1755 files_with_extension(io, dir, "gleam").map(move |path| {
1756 if (Self::is_gleam_path(&path, &dir)) {
1757 Ok(Self::new(dir, path))
1758 } else {
1759 Err(crate::Warning::InvalidSource { path })
1760 }
1761 })
1762 }
1763
1764 pub fn cache_files(&self, artefact_directory: &Utf8Path) -> CacheFiles {
1765 CacheFiles::new(artefact_directory, &self.module_name)
1766 }
1767
1768 fn module_name(path: &Utf8Path, dir: &Utf8Path) -> EcoString {
1769 // /path/to/project/_build/default/lib/the_package/src/my/module.gleam
1770
1771 // my/module.gleam
1772 let mut module_path = path
1773 .strip_prefix(dir)
1774 .expect("Stripping package prefix from module path")
1775 .to_path_buf();
1776
1777 // my/module
1778 let _ = module_path.set_extension("");
1779
1780 // Stringify
1781 let name = module_path.to_string();
1782
1783 // normalise windows paths
1784 name.replace("\\", "/").into()
1785 }
1786
1787 fn is_gleam_path(path: &Utf8Path, dir: &Utf8Path) -> bool {
1788 IS_GLEAM_PATH_PATTERN
1789 .get_or_init(|| {
1790 Regex::new(&format!(
1791 "^({module}{slash})*{module}\\.gleam$",
1792 module = "[a-z][_a-z0-9]*",
1793 slash = "(/|\\\\)",
1794 ))
1795 .expect("is_gleam_path() RE regex")
1796 })
1797 .is_match(
1798 path.strip_prefix(dir)
1799 .expect("is_gleam_path(): strip_prefix")
1800 .as_str(),
1801 )
1802 }
1803}
1804
1805/// The collection of cache files paths related to a module.
1806/// These files are not guaranteed to exist.
1807pub struct CacheFiles {
1808 pub cache_path: Utf8PathBuf,
1809 pub meta_path: Utf8PathBuf,
1810}
1811
1812impl CacheFiles {
1813 pub fn new(artefact_directory: &Utf8Path, module_name: &EcoString) -> Self {
1814 let file_name = module_name.replace("/", "@");
1815 let cache_path = artefact_directory
1816 .join(file_name.as_str())
1817 .with_extension("cache");
1818 let meta_path = artefact_directory
1819 .join(file_name.as_str())
1820 .with_extension("cache_meta");
1821
1822 Self {
1823 cache_path,
1824 meta_path,
1825 }
1826 }
1827
1828 pub fn delete(&self, io: &dyn io::FileSystemWriter) -> Result<()> {
1829 io.delete_file(&self.cache_path)?;
1830 io.delete_file(&self.meta_path)
1831 }
1832
1833 /// Iterates over `.cache_meta` files in the given directory,
1834 /// and returns the respective module names.
1835 /// Symlinks are followed.
1836 pub fn modules_with_meta_files<'a>(
1837 io: &'a impl FileSystemReader,
1838 dir: &'a Utf8Path,
1839 ) -> impl Iterator<Item = EcoString> + 'a {
1840 tracing::trace!("CacheFiles::modules_with_meta_files {:?}", dir);
1841 files_with_extension(io, dir, "cache_meta").map(move |path| Self::module_name(&dir, &path))
1842 }
1843
1844 fn module_name(dir: &Utf8Path, path: &Utf8Path) -> EcoString {
1845 // /path/to/artefact/dir/my@module.cache_meta
1846
1847 // my@module.cache_meta
1848 let mut module_path = path
1849 .strip_prefix(dir)
1850 .expect("Stripping package prefix from module path")
1851 .to_path_buf();
1852
1853 // my@module
1854 let _ = module_path.set_extension("");
1855
1856 // my/module
1857 module_path.to_string().replace("@", "/").into()
1858 }
1859}