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
#[cfg(test)]
mod test;

mod diagnostics;
use diagnostics::emit_slide_diagnostics;

use libslide::diagnostics::Diagnostic;
use libslide::scanner::ScanResult;
use libslide::{
    evaluate, parse_expression, parse_expression_pattern, scan, EvaluatorContext, Grammar,
};

pub struct Opts {
    pub program: String,
    pub output_form: OutputForm,
    pub parse_only: bool,
    pub expr_pat: bool,
    pub no_emit: bool,
}

#[derive(Copy, Clone)]
pub enum OutputForm {
    Pretty,
    SExpression,
    Debug,
}

pub fn run_slide(opts: Opts) -> i32 {
    let output_form = opts.output_form;
    let file = None; // currently programs can only be read from stdin
    let program = opts.program;
    let emit = !opts.no_emit;

    let emit_diagnostics = |diagnostics: Vec<Diagnostic>| {
        if emit {
            emit_slide_diagnostics(file, program.clone(), diagnostics);
        }
        1
    };
    let emit_tree = move |obj: &dyn Grammar| {
        if emit {
            println!("{}", print(obj, output_form));
        }
        0
    };

    let ScanResult {
        tokens,
        diagnostics,
    } = scan(&*program);
    if !diagnostics.is_empty() {
        return emit_diagnostics(diagnostics);
    }

    if opts.expr_pat {
        let (parse_tree, diagnostics) = parse_expression_pattern(tokens);
        if !diagnostics.is_empty() {
            return emit_diagnostics(diagnostics);
        }
        if opts.parse_only {
            return emit_tree(&parse_tree);
        }
        unreachable!();
    }
    let (parse_tree, diagnostics) = parse_expression(tokens);

    if !diagnostics.is_empty() {
        return emit_diagnostics(diagnostics);
    }

    if opts.parse_only {
        return emit_tree(&parse_tree);
    }

    let simplified = evaluate(parse_tree, EvaluatorContext::default()).unwrap();
    emit_tree(&simplified)
}

fn print(obj: &dyn Grammar, output_form: OutputForm) -> String {
    match output_form {
        OutputForm::Pretty => obj.to_string(),
        OutputForm::SExpression => obj.s_form(),
        OutputForm::Debug => format!("{:#?}", obj),
    }
}