1#![allow(rustdoc::private_intra_doc_links)]
6#![allow(rustdoc::broken_intra_doc_links)]
7#![allow(clippy::needless_range_loop)]
8
9pub mod agent;
10pub mod ai;
11pub mod ai_sugar;
12pub mod aop;
13pub mod aot;
14pub mod ast;
15pub mod builtins;
16pub mod bytecode;
17pub mod capture;
18pub mod cluster;
19pub mod compiler;
20pub mod controller;
21pub mod convert;
22mod crypt_util;
23pub mod data_section;
24pub mod debugger;
25pub mod deconvert;
26pub mod deparse;
27pub mod english;
28pub mod error;
29mod fib_like_tail;
30pub mod fmt;
31pub mod format;
32mod jit;
33mod jwt;
34pub mod lexer;
35pub mod list_builtins;
36pub mod lsp;
37mod map_grep_fast;
38mod map_stream;
39pub mod mcp;
40pub mod mro;
41mod nanbox;
42mod native_codec;
43pub mod native_data;
44pub mod pack;
45pub mod par_lines;
46mod par_list;
47pub mod par_pipeline;
48pub mod par_walk;
49pub mod parallel_trace;
50pub mod parser;
51pub mod pcache;
52pub mod pchannel;
53mod pending_destroy;
54pub mod perl_decode;
55pub mod perl_fs;
56pub mod perl_inc;
57#[cfg(unix)]
58pub mod perl_pty;
59mod perl_regex;
60pub mod perl_signal;
61pub mod pkg;
62mod pmap_progress;
63pub mod ppool;
64pub mod profiler;
65pub mod pwatch;
66pub mod remote_wire;
67pub mod rust_ffi;
68pub mod rust_sugar;
69pub mod scope;
70pub mod script_cache;
71pub mod secrets;
72pub mod serialize_normalize;
73mod sort_fast;
74pub mod special_vars;
75pub mod static_analysis;
76pub mod stress;
77pub mod token;
78pub mod value;
79pub mod vm;
80pub mod vm_helper;
81pub mod web;
82pub mod web_orm;
83
84pub use zsh::exec as shell_exec;
86pub use zsh::fds as shell_fds;
87pub use zsh::history as shell_history;
88pub use zsh::jobs as shell_jobs;
89pub use zsh::lexer as zsh_lex;
90pub use zsh::parser as shell_parse;
91pub use zsh::parser as zsh_parse;
92pub use zsh::signals as shell_signal;
93pub use zsh::tokens as zsh_tokens;
94pub use zsh::zle as shell_zle;
95pub use zsh::zwc as shell_zwc;
96
97pub use vm_helper::{
98 perl_bracket_version, FEAT_SAY, FEAT_STATE, FEAT_SWITCH, FEAT_UNICODE_STRINGS,
99};
100
101use error::{PerlError, PerlResult};
102use vm_helper::VMHelper;
103
104use std::sync::atomic::{AtomicBool, Ordering};
107
108static COMPAT_MODE: AtomicBool = AtomicBool::new(false);
112
113static NO_INTEROP_MODE: AtomicBool = AtomicBool::new(false);
117
118static BIGINT_PRAGMA: AtomicBool = AtomicBool::new(false);
123
124pub fn set_compat_mode(on: bool) {
126 COMPAT_MODE.store(on, Ordering::Relaxed);
127}
128
129#[inline]
131pub fn compat_mode() -> bool {
132 COMPAT_MODE.load(Ordering::Relaxed)
133}
134
135pub fn set_bigint_pragma(on: bool) {
138 BIGINT_PRAGMA.store(on, Ordering::Relaxed);
139}
140
141#[inline]
143pub fn bigint_pragma() -> bool {
144 BIGINT_PRAGMA.load(Ordering::Relaxed)
145}
146
147pub fn set_no_interop_mode(on: bool) {
149 NO_INTEROP_MODE.store(on, Ordering::Relaxed);
150}
151
152#[inline]
154pub fn no_interop_mode() -> bool {
155 NO_INTEROP_MODE.load(Ordering::Relaxed)
156}
157use value::PerlValue;
158
159pub fn format_program(p: &ast::Program) -> String {
162 fmt::format_program(p)
163}
164
165pub fn convert_to_stryke(p: &ast::Program) -> String {
167 convert::convert_program(p)
168}
169
170pub fn convert_to_stryke_with_options(p: &ast::Program, opts: &convert::ConvertOptions) -> String {
172 convert::convert_program_with_options(p, opts)
173}
174
175pub fn deconvert_to_perl(p: &ast::Program) -> String {
177 deconvert::deconvert_program(p)
178}
179
180pub fn deconvert_to_perl_with_options(
182 p: &ast::Program,
183 opts: &deconvert::DeconvertOptions,
184) -> String {
185 deconvert::deconvert_program_with_options(p, opts)
186}
187
188pub fn parse(code: &str) -> PerlResult<ast::Program> {
189 parse_with_file(code, "-e")
190}
191
192pub fn parse_with_file(code: &str, file: &str) -> PerlResult<ast::Program> {
195 parse_with_file_inner(code, file, false)
196}
197
198pub fn parse_module_with_file(code: &str, file: &str) -> PerlResult<ast::Program> {
201 parse_with_file_inner(code, file, true)
202}
203
204fn parse_with_file_inner(code: &str, file: &str, is_module: bool) -> PerlResult<ast::Program> {
205 let desugared = if compat_mode() {
209 code.to_string()
210 } else {
211 let s = rust_sugar::desugar_rust_blocks(code);
212 ai_sugar::desugar(&s)
213 };
214 let mut lexer = lexer::Lexer::new_with_file(&desugared, file);
215 let tokens = lexer.tokenize()?;
216 let bare_positional_indices = std::mem::take(&mut lexer.bare_positional_indices);
217 let mut parser = parser::Parser::new_with_file(tokens, file);
218 parser.bare_positional_indices = bare_positional_indices;
219 parser.parsing_module = is_module;
220 parser.parse_program()
221}
222
223pub fn parse_and_run_string(code: &str, interp: &mut VMHelper) -> PerlResult<PerlValue> {
227 let file = interp.file.clone();
228 parse_and_run_string_in_file(code, interp, &file)
229}
230
231pub fn parse_and_run_string_in_file(
234 code: &str,
235 interp: &mut VMHelper,
236 file: &str,
237) -> PerlResult<PerlValue> {
238 parse_and_run_string_in_file_inner(code, interp, file, false)
239}
240
241pub fn parse_and_run_module_in_file(
244 code: &str,
245 interp: &mut VMHelper,
246 file: &str,
247) -> PerlResult<PerlValue> {
248 parse_and_run_string_in_file_inner(code, interp, file, true)
249}
250
251fn parse_and_run_string_in_file_inner(
252 code: &str,
253 interp: &mut VMHelper,
254 file: &str,
255 is_module: bool,
256) -> PerlResult<PerlValue> {
257 let program = if is_module {
258 parse_module_with_file(code, file)?
259 } else {
260 parse_with_file(code, file)?
261 };
262 let saved = interp.file.clone();
263 interp.file = file.to_string();
264 let r = interp.execute(&program);
265 interp.file = saved;
266 let v = r?;
267 interp.drain_pending_destroys(0)?;
268 Ok(v)
269}
270
271pub fn vendor_perl_inc_path() -> std::path::PathBuf {
274 std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("vendor/perl")
275}
276
277pub fn run_lsp_stdio() -> i32 {
279 match lsp::run_stdio() {
280 Ok(()) => 0,
281 Err(e) => {
282 eprintln!("stryke --lsp: {e}");
283 1
284 }
285 }
286}
287
288pub fn run(code: &str) -> PerlResult<PerlValue> {
290 let program = parse(code)?;
291 let mut interp = VMHelper::new();
292 let v = interp.execute(&program)?;
293 interp.run_global_teardown()?;
294 Ok(v)
295}
296
297pub fn try_vm_execute(
305 program: &ast::Program,
306 interp: &mut VMHelper,
307) -> Option<PerlResult<PerlValue>> {
308 if let Err(e) = interp.prepare_program_top_level(program) {
309 return Some(Err(e));
310 }
311
312 if let Some(chunk) = interp.cached_chunk.take() {
315 return Some(run_compiled_chunk(chunk, interp));
316 }
317
318 let comp = compiler::Compiler::new()
323 .with_source_file(interp.file.clone())
324 .with_strict_vars(interp.strict_vars);
325 let chunk = match comp.compile_program(program) {
326 Ok(chunk) => chunk,
327 Err(compiler::CompileError::Frozen { line, detail }) => {
328 let err = if detail.starts_with("Global symbol") {
329 PerlError::syntax(detail, line)
330 } else {
331 PerlError::runtime(detail, line)
332 };
333 return Some(Err(err));
334 }
335 Err(compiler::CompileError::Unsupported(reason)) => {
336 return Some(Err(PerlError::runtime(
337 format!("VM compile error (unsupported): {}", reason),
338 0,
339 )));
340 }
341 };
342
343 if let Some(path) = interp.cache_script_path.take() {
345 let _ = script_cache::try_save(&path, program, &chunk);
346 }
347 Some(run_compiled_chunk(chunk, interp))
348}
349
350fn run_compiled_chunk(chunk: bytecode::Chunk, interp: &mut VMHelper) -> PerlResult<PerlValue> {
354 interp.clear_flip_flop_state();
355 interp.prepare_flip_flop_vm_slots(chunk.flip_flop_slots);
356 if interp.disasm_bytecode {
357 eprintln!("{}", chunk.disassemble());
358 }
359 interp.clear_begin_end_blocks_after_vm_compile();
360 for def in &chunk.struct_defs {
361 interp
362 .struct_defs
363 .insert(def.name.clone(), std::sync::Arc::new(def.clone()));
364 }
365 for def in &chunk.enum_defs {
366 interp
367 .enum_defs
368 .insert(def.name.clone(), std::sync::Arc::new(def.clone()));
369 }
370 for def in &chunk.trait_defs {
372 interp
373 .trait_defs
374 .insert(def.name.clone(), std::sync::Arc::new(def.clone()));
375 }
376 for def in &chunk.class_defs {
377 let mut def = def.clone();
378 for parent_name in &def.extends.clone() {
380 if let Some(parent_def) = interp.class_defs.get(parent_name) {
381 if parent_def.is_final {
382 return Err(crate::error::PerlError::runtime(
383 format!("cannot extend final class `{}`", parent_name),
384 0,
385 ));
386 }
387 for m in &def.methods {
388 if let Some(parent_method) = parent_def.method(&m.name) {
389 if parent_method.is_final {
390 return Err(crate::error::PerlError::runtime(
391 format!(
392 "cannot override final method `{}` from class `{}`",
393 m.name, parent_name
394 ),
395 0,
396 ));
397 }
398 }
399 }
400 }
401 }
402 for trait_name in &def.implements.clone() {
404 if let Some(trait_def) = interp.trait_defs.get(trait_name) {
405 for required in trait_def.required_methods() {
406 let has_method = def.methods.iter().any(|m| m.name == required.name);
407 if !has_method {
408 return Err(crate::error::PerlError::runtime(
409 format!(
410 "class `{}` implements trait `{}` but does not define required method `{}`",
411 def.name, trait_name, required.name
412 ),
413 0,
414 ));
415 }
416 }
417 for tm in &trait_def.methods {
419 if tm.body.is_some() && !def.methods.iter().any(|m| m.name == tm.name) {
420 def.methods.push(tm.clone());
421 }
422 }
423 }
424 }
425 if !def.is_abstract {
428 for parent_name in &def.extends.clone() {
429 if let Some(parent_def) = interp.class_defs.get(parent_name) {
430 if parent_def.is_abstract {
431 for m in &parent_def.methods {
432 if m.body.is_none() && !def.methods.iter().any(|dm| dm.name == m.name) {
433 return Err(crate::error::PerlError::runtime(
434 format!(
435 "class `{}` must implement abstract method `{}` from `{}`",
436 def.name, m.name, parent_name
437 ),
438 0,
439 ));
440 }
441 }
442 }
443 }
444 }
445 }
446 for sf in &def.static_fields {
448 let val = if let Some(ref expr) = sf.default {
449 match interp.eval_expr(expr) {
450 Ok(v) => v,
451 Err(crate::vm_helper::FlowOrError::Error(e)) => return Err(e),
452 Err(_) => crate::value::PerlValue::UNDEF,
453 }
454 } else {
455 crate::value::PerlValue::UNDEF
456 };
457 let key = format!("{}::{}", def.name, sf.name);
458 interp.scope.declare_scalar(&key, val);
459 }
460 for m in &def.methods {
462 if let Some(ref body) = m.body {
463 let fq = format!("{}::{}", def.name, m.name);
464 let sub = std::sync::Arc::new(crate::value::PerlSub {
465 name: fq.clone(),
466 params: m.params.clone(),
467 body: body.clone(),
468 closure_env: None,
469 prototype: None,
470 fib_like: None,
471 });
472 interp.subs.insert(fq, sub);
473 }
474 }
475 if !def.extends.is_empty() {
477 let isa_key = format!("{}::ISA", def.name);
478 let parents: Vec<crate::value::PerlValue> = def
479 .extends
480 .iter()
481 .map(|p| crate::value::PerlValue::string(p.clone()))
482 .collect();
483 interp.scope.declare_array(&isa_key, parents);
484 }
485 interp
486 .class_defs
487 .insert(def.name.clone(), std::sync::Arc::new(def));
488 }
489 let vm_jit = interp.vm_jit_enabled && interp.profiler.is_none();
490 let mut vm = vm::VM::new(&chunk, interp);
491 vm.set_jit_enabled(vm_jit);
492 match vm.execute() {
493 Ok(val) => {
494 interp.drain_pending_destroys(0)?;
495 Ok(val)
496 }
497 Err(e)
502 if e.message.starts_with("VM: unimplemented op")
503 || e.message.starts_with("Unimplemented builtin") =>
504 {
505 Err(PerlError::runtime(e.message, 0))
506 }
507 Err(e) => Err(e),
508 }
509}
510
511pub fn compile_and_run_prelude(program: &ast::Program, interp: &mut VMHelper) -> PerlResult<()> {
514 interp.prepare_program_top_level(program)?;
515 let comp = compiler::Compiler::new()
516 .with_source_file(interp.file.clone())
517 .with_strict_vars(interp.strict_vars);
518 let mut chunk = match comp.compile_program(program) {
519 Ok(chunk) => chunk,
520 Err(compiler::CompileError::Frozen { line, detail }) => {
521 let err = if detail.starts_with("Global symbol") {
522 PerlError::syntax(detail, line)
523 } else {
524 PerlError::runtime(detail, line)
525 };
526 return Err(err);
527 }
528 Err(compiler::CompileError::Unsupported(reason)) => {
529 return Err(PerlError::runtime(
530 format!("VM compile error (unsupported): {}", reason),
531 0,
532 ));
533 }
534 };
535
536 interp.clear_flip_flop_state();
537 interp.prepare_flip_flop_vm_slots(chunk.flip_flop_slots);
538 if interp.disasm_bytecode {
539 eprintln!("{}", chunk.disassemble());
540 }
541 interp.clear_begin_end_blocks_after_vm_compile();
542 for def in &chunk.struct_defs {
543 interp
544 .struct_defs
545 .insert(def.name.clone(), std::sync::Arc::new(def.clone()));
546 }
547 for def in &chunk.enum_defs {
548 interp
549 .enum_defs
550 .insert(def.name.clone(), std::sync::Arc::new(def.clone()));
551 }
552 for def in &chunk.trait_defs {
553 interp
554 .trait_defs
555 .insert(def.name.clone(), std::sync::Arc::new(def.clone()));
556 }
557 for def in &chunk.class_defs {
558 interp
559 .class_defs
560 .insert(def.name.clone(), std::sync::Arc::new(def.clone()));
561 }
562 for def in &chunk.class_defs {
564 for m in &def.methods {
565 if let Some(ref body) = m.body {
566 let fq = format!("{}::{}", def.name, m.name);
567 let sub = std::sync::Arc::new(crate::value::PerlSub {
568 name: fq.clone(),
569 params: m.params.clone(),
570 body: body.clone(),
571 closure_env: None,
572 prototype: None,
573 fib_like: None,
574 });
575 interp.subs.insert(fq, sub);
576 }
577 }
578 }
579
580 let body_ip = chunk.body_start_ip;
581 if body_ip > 0 && body_ip < chunk.ops.len() {
582 let saved_op = chunk.ops[body_ip].clone();
584 chunk.ops[body_ip] = bytecode::Op::Halt;
585 let vm_jit = interp.vm_jit_enabled && interp.profiler.is_none();
586 let mut vm = vm::VM::new(&chunk, interp);
587 vm.set_jit_enabled(vm_jit);
588 let _ = vm.execute()?;
589 chunk.ops[body_ip] = saved_op;
590 }
591
592 interp.line_mode_chunk = Some(chunk);
593 Ok(())
594}
595
596pub fn run_line_body(
599 chunk: &bytecode::Chunk,
600 interp: &mut VMHelper,
601 line_str: &str,
602 is_last_input_line: bool,
603) -> PerlResult<Option<String>> {
604 interp.line_mode_eof_pending = is_last_input_line;
605 let result: PerlResult<Option<String>> = (|| {
606 interp.line_number += 1;
607 interp
608 .scope
609 .set_topic(value::PerlValue::string(line_str.to_string()));
610
611 if interp.auto_split {
612 let sep = interp.field_separator.as_deref().unwrap_or(" ");
613 let re = regex::Regex::new(sep).unwrap_or_else(|_| regex::Regex::new(" ").unwrap());
614 let fields: Vec<value::PerlValue> = re
615 .split(line_str)
616 .map(|s| value::PerlValue::string(s.to_string()))
617 .collect();
618 interp.scope.set_array("F", fields)?;
619 }
620
621 let vm_jit = interp.vm_jit_enabled && interp.profiler.is_none();
622 let mut vm = vm::VM::new(chunk, interp);
623 vm.set_jit_enabled(vm_jit);
624 vm.ip = chunk.body_start_ip;
625 let _ = vm.execute()?;
626
627 let mut out = interp.scope.get_scalar("_").to_string();
628 out.push_str(&interp.ors);
629 Ok(Some(out))
630 })();
631 interp.line_mode_eof_pending = false;
632 result
633}
634
635pub fn lint_program(program: &ast::Program, interp: &mut VMHelper) -> PerlResult<()> {
638 interp.prepare_program_top_level(program)?;
639 static_analysis::analyze_program(program, &interp.file)?;
640 if interp.strict_refs || interp.strict_subs || interp.strict_vars {
641 return Ok(());
642 }
643 let comp = compiler::Compiler::new().with_source_file(interp.file.clone());
644 match comp.compile_program(program) {
645 Ok(_) => Ok(()),
646 Err(e) => Err(compile_error_to_perl(e)),
647 }
648}
649
650fn compile_error_to_perl(e: compiler::CompileError) -> PerlError {
651 match e {
652 compiler::CompileError::Unsupported(msg) => {
653 PerlError::runtime(format!("compile: {}", msg), 0)
654 }
655 compiler::CompileError::Frozen { line, detail } => {
656 if detail.starts_with("Global symbol") {
661 PerlError::syntax(detail, line)
662 } else {
663 PerlError::runtime(detail, line)
664 }
665 }
666 }
667}
668
669#[cfg(test)]
670mod tests {
671 use super::*;
672
673 #[test]
674 fn run_executes_last_expression_value() {
675 let p = parse("2 + 2").expect("parse");
677 assert!(!p.statements.is_empty());
678 let _ = run("2 + 2").expect("run");
679 }
680
681 #[test]
682 fn run_propagates_parse_errors() {
683 assert!(run("sub f {").is_err());
684 }
685
686 #[test]
687 fn interpreter_scope_persists_global_scalar_across_execute_calls() {
688 let mut interp = VMHelper::new();
689 let assign = parse("$persist_test = 100").expect("parse assign");
690 interp.execute(&assign).expect("assign");
691 let read = parse("$persist_test").expect("parse read");
692 let v = interp.execute(&read).expect("read");
693 assert_eq!(v.to_int(), 100);
694 }
695
696 #[test]
697 fn parse_empty_program() {
698 let p = parse("").expect("empty input should parse");
699 assert!(p.statements.is_empty());
700 }
701
702 #[test]
703 fn parse_expression_statement() {
704 let p = parse("2 + 2").expect("parse");
705 assert!(!p.statements.is_empty());
706 }
707
708 #[test]
709 fn parse_semicolon_only_statements() {
710 parse(";;").expect("semicolons only");
711 }
712
713 #[test]
714 fn parse_if_with_block() {
715 parse("if (1) { 2 }").expect("if");
716 }
717
718 #[test]
719 fn parse_fails_on_invalid_syntax() {
720 assert!(parse("sub f {").is_err());
721 }
722
723 #[test]
724 fn parse_qw_word_list() {
725 parse("my @a = qw(x y z)").expect("qw list");
726 }
727
728 #[test]
729 fn parse_c_style_for_loop() {
730 parse("for (my $i = 0; $i < 3; $i = $i + 1) { 1; }").expect("c-style for");
731 }
732
733 #[test]
734 fn parse_package_statement() {
735 parse("package Foo::Bar; 1").expect("package");
736 }
737
738 #[test]
739 fn parse_unless_block() {
740 parse("unless (0) { 1; }").expect("unless");
741 }
742
743 #[test]
744 fn parse_if_elsif_else() {
745 parse("if (0) { 1; } elsif (1) { 2; } else { 3; }").expect("if elsif");
746 }
747
748 #[test]
749 fn parse_q_constructor() {
750 parse(r#"my $s = q{braces}"#).expect("q{}");
751 parse(r#"my $t = qq(double)"#).expect("qq()");
752 }
753
754 #[test]
755 fn parse_regex_literals() {
756 parse("m/foo/").expect("m//");
757 parse("s/foo/bar/g").expect("s///");
758 }
759
760 #[test]
761 fn parse_begin_and_end_blocks() {
762 parse("BEGIN { 1; }").expect("BEGIN");
763 parse("END { 1; }").expect("END");
764 }
765
766 #[test]
767 fn parse_transliterate_y() {
768 parse("$_ = 'a'; y/a/A/").expect("y//");
769 }
770
771 #[test]
772 fn parse_foreach_with_my_iterator() {
773 parse("foreach my $x (1, 2) { $x; }").expect("foreach my");
774 }
775
776 #[test]
777 fn parse_our_declaration() {
778 parse("our $g = 1").expect("our");
779 }
780
781 #[test]
782 fn parse_local_declaration() {
783 parse("local $x = 1").expect("local");
784 }
785
786 #[test]
787 fn parse_use_no_statements() {
788 parse("use strict").expect("use");
789 parse("no warnings").expect("no");
790 }
791
792 #[test]
793 fn parse_sub_with_prototype() {
794 parse("fn add2 ($$) { return $_0 + $_1; }").expect("fn prototype");
795 parse("fn try_block (&;@) { my ( $try, @code_refs ) = @_; }").expect("prototype @ slurpy");
796 }
797
798 #[test]
799 fn parse_list_expression_in_parentheses() {
800 parse("my @a = (1, 2, 3)").expect("list");
801 }
802
803 #[test]
804 fn parse_require_expression() {
805 parse("require strict").expect("require");
806 }
807
808 #[test]
809 fn parse_do_string_eval_form() {
810 parse(r#"do "foo.pl""#).expect("do string");
811 }
812
813 #[test]
814 fn parse_package_qualified_name() {
815 parse("package Foo::Bar::Baz").expect("package ::");
816 }
817
818 #[test]
819 fn parse_my_multiple_declarations() {
820 parse("my ($a, $b, $c)").expect("my list");
821 }
822
823 #[test]
824 fn parse_eval_block_statement() {
825 parse("eval { 1; }").expect("eval block");
826 }
827
828 #[test]
829 fn parse_p_statement() {
830 parse("p 42").expect("p");
831 }
832
833 #[test]
834 fn parse_chop_scalar() {
835 parse("chop $s").expect("chop");
836 }
837
838 #[test]
839 fn vendor_perl_inc_path_points_at_vendor_perl() {
840 let p = vendor_perl_inc_path();
841 assert!(
842 p.ends_with("vendor/perl"),
843 "unexpected vendor path: {}",
844 p.display()
845 );
846 }
847
848 #[test]
849 fn format_program_roundtrips_simple_expression() {
850 let p = parse("$x + 1").expect("parse");
851 let out = format_program(&p);
852 assert!(!out.trim().is_empty());
853 }
854}
855
856#[cfg(test)]
857mod builtins_extended_tests;
858
859#[cfg(test)]
860mod lib_api_extended_tests;
861
862#[cfg(test)]
863mod cache_bench;
864
865#[cfg(test)]
866mod parallel_api_tests;
867
868#[cfg(test)]
869mod parse_smoke_extended;
870
871#[cfg(test)]
872mod parse_smoke_batch2;
873
874#[cfg(test)]
875mod parse_smoke_batch3;
876
877#[cfg(test)]
878mod parse_smoke_batch4;
879
880#[cfg(test)]
881mod crate_api_tests;
882
883#[cfg(test)]
884mod parser_shape_tests;
885
886#[cfg(test)]
887mod interpreter_unit_tests;
888
889#[cfg(test)]
890mod run_semantics_tests;
891
892#[cfg(test)]
893mod run_semantics_more;
894
895#[cfg(test)]
896mod value_extra_tests;
897
898#[cfg(test)]
899mod lexer_extra_tests;
900
901#[cfg(test)]
902mod parser_extra_tests;
903
904#[cfg(test)]
905mod builtins_extra_tests;
906
907#[cfg(test)]
908mod keywords_hash_tests;
909
910#[cfg(test)]
911mod thread_extra_tests;
912
913#[cfg(test)]
914mod error_extra_tests;
915
916#[cfg(test)]
917mod oo_extra_tests;
918
919#[cfg(test)]
920mod regex_extra_tests;
921
922#[cfg(test)]
923mod aot_extra_tests;