1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
use std::{
    fs,
    io::{self, prelude::*},
    path::Path,
    sync::Arc,
};

use calypso_common::gcx::GlobalCtxt;
use calypso_diagnostic::prelude::*;
use calypso_repl::Repl;

use crate::{buildinfo::BUILD_INFO, cli::UnprettyFormat};

pub mod ast;
pub mod toks;

pub fn unpretty(
    gcx: &Arc<GlobalCtxt>,
    format: UnprettyFormat,
    path: &Path,
    repl: bool,
) -> CalResult<()> {
    let (file_name, contents) = if path == Path::new("-") {
        if repl {
            run_repl(gcx, format);
            return Ok(());
        }

        let stdin = io::stdin();
        let mut contents = String::new();
        if let Err(err) = stdin.lock().read_to_string(&mut contents) {
            gcx.emit
                .write()
                .err
                .error(None, "while reading from stdin:", None)?
                .error(None, &format!("{}", err), None)?
                .flush()?;
            return Ok(());
        }

        ("<stdin>".to_string(), contents)
    } else {
        if !path.exists() {
            gcx.emit
                .write()
                .err
                .error(
                    None,
                    "file does not exist",
                    Some(&format!("`{}`", path.display())),
                )?
                .flush()?;
            return Ok(());
        }

        (
            path.display().to_string(),
            match fs::read_to_string(&path) {
                Ok(v) => v,
                Err(err) => {
                    gcx.emit
                        .write()
                        .err
                        .error(
                            None,
                            "while reading file",
                            Some(&format!("`{}`:", path.display())),
                        )?
                        .error(None, &format!("{}", err), None)?
                        .flush()?;
                    return Ok(());
                }
            },
        )
    };

    match format {
        UnprettyFormat::Ast => ast::run_parser(gcx, file_name, contents),
        UnprettyFormat::TokenList => toks::run_lexer(gcx, file_name, contents),
    }
}

pub fn run_repl(gcx: &Arc<GlobalCtxt>, format: UnprettyFormat) {
    struct ReplCtx {
        line: usize,
    }

    let repl_gcx = Arc::clone(gcx);
    let mut repl = Repl::new(
        Box::new(move |rcx: &mut ReplCtx, contents| {
            let res = match format {
                UnprettyFormat::Ast => {
                    ast::run_parser(&repl_gcx, format!("<repl:{}>", rcx.line), contents)
                }
                UnprettyFormat::TokenList => {
                    toks::run_lexer(&repl_gcx, format!("<repl:{}>", rcx.line), contents)
                }
            }
            .ok()
            .map(|_| String::new());
            rcx.line += 1;
            repl_gcx.grcx.write().clear();
            res
        }),
        ReplCtx { line: 1 },
    )
    .prefix("\\".to_string());
    repl.run(
        &format!(
            "Calypso CLI v{} - unpretty: {}",
            BUILD_INFO.version,
            format.to_string()
        ),
        |rcx| format!("[{}]: ", rcx.line),
    )
    .expect("REPL failure");
}