1use crate::ast::*;
14use crate::deparse;
15
16#[derive(Debug, Clone, Default)]
18pub struct DeconvertOptions {
19 pub output_delim: Option<char>,
21}
22
23pub fn deconvert_program(p: &Program) -> String {
25 deconvert_program_with_options(p, &DeconvertOptions::default())
26}
27
28pub fn deconvert_program_with_options(p: &Program, opts: &DeconvertOptions) -> String {
30 let body = if let Some(delim) = opts.output_delim {
31 deparse::deparse_block_with_delim(&p.statements, delim)
32 } else {
33 deparse::deparse_block(&p.statements)
34 };
35 format!(
36 "#!/usr/bin/env perl\nuse v5.10;\nuse strict;\nuse warnings;\n\n{}\n",
37 body
38 )
39}
40
41#[cfg(test)]
42mod tests {
43 use super::*;
44 use crate::parse;
45
46 fn deconvert(code: &str) -> String {
47 let p = parse(code).expect("parse failed");
48 deconvert_program(&p)
49 }
50
51 #[test]
52 fn deconvert_simple() {
53 let out = deconvert("my $x = 1;");
54 assert!(out.contains("#!/usr/bin/env perl"));
55 assert!(out.contains("my $x = 1;"));
56 }
57
58 #[test]
59 fn deconvert_fn_to_sub() {
60 let out = deconvert("fn foo { 42 }");
61 assert!(out.contains("sub foo"));
62 assert!(out.contains("42"));
63 }
64
65 #[test]
66 fn deconvert_say() {
67 let out = deconvert("p 'hello';");
68 assert!(out.contains("say"));
69 assert!(out.contains("hello"));
70 }
71
72 #[test]
73 fn deconvert_has_strict_warnings() {
74 let out = deconvert("1;");
75 assert!(out.contains("use strict;"));
76 assert!(out.contains("use warnings;"));
77 }
78
79 #[test]
80 fn deconvert_pipe_to_nested() {
81 let out = deconvert("@a |> map { $_ * 2 } |> join \",\";");
82 assert!(out.contains("join"));
83 assert!(out.contains("map"));
84 assert!(out.contains("@a"));
85 assert!(!out.contains("|>"));
86 }
87
88 #[test]
89 fn deconvert_thread_macro() {
90 let out = deconvert("t $x uc lc;");
91 assert!(out.contains("lc"));
92 assert!(out.contains("uc"));
93 assert!(out.contains("$x"));
94 assert!(!out.contains(" t "));
95 }
96}