summaryrefslogtreecommitdiff
path: root/src/main.rs
blob: cdab3c03664b056e9d1719bfd1a10f90a3e8d768 (plain)
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
use std::io::{self, Read};
use std::error::Error;
use term_painter::ToStyle;

use dhall::*;

const ERROR_STYLE: term_painter::Color = term_painter::Color::Red;
const BOLD: term_painter::Attr = term_painter::Attr::Bold;

fn print_error(message: &str, source: &str, start: usize, end: usize) {
    let line_number = bytecount::count(source[..start].as_bytes(), b'\n');
    let line_start = source[..start].rfind('\n').map(|i| i + 1).unwrap_or(0);
    let line_end = source[end..].find('\n').unwrap_or(0) + end;
    let context_prefix = &source[line_start..start];
    let context_highlighted = &source[start..end];
    let context_suffix = &source[end..line_end];

    let line_number_str = line_number.to_string();
    let line_number_width = line_number_str.len();

    BOLD.with(|| {
        ERROR_STYLE.with(|| {
            print!("error: ");
        });
        println!("{}", message);
    });
    BOLD.with(|| {
        print!("  -->");
    });
    println!(" {}:{}:0", "(stdin)", line_number);
    BOLD.with(|| {
        println!("{:w$} |", "", w = line_number_width);
        print!("{} |", line_number_str);
    });
    print!(" {}", context_prefix);
    BOLD.with(|| {
        ERROR_STYLE.with(|| {
            print!("{}", context_highlighted);
        });
    });
    println!("{}", context_suffix);
    BOLD.with(|| {
        print!("{:w$} |", "", w = line_number_width);
        ERROR_STYLE.with(|| {
            println!(" {:so$}{:^>ew$}", "", "",
                     so = source[line_start..start].chars().count(),
                     ew = ::std::cmp::max(1, source[start..end].chars().count()));
        });
    });
}

fn main() {
    let mut buffer = String::new();
    io::stdin().read_to_string(&mut buffer).unwrap();
    let expr = match parser::parse_expr(&buffer) {
        Ok(e) => e,
        Err(lalrpop_util::ParseError::User { error: lexer::LexicalError::Error(pos, e) }) => {
            print_error(&format!("Unexpected token {:?}", e), &buffer, pos, pos);
            return;
        }
        Err(lalrpop_util::ParseError::UnrecognizedToken { token: Some((start, t, end)), expected: e }) => {
            print_error(&format!("Unrecognized token {:?}", t), &buffer, start, end);
            if !e.is_empty() {
                println!("Expected {:?}", e);
            }
            return;
        }
        Err(e) => {
            print_error(&format!("Parser error {:?}", e), &buffer, 0, 0);
            return;
        }
    };

    /*
    expr' <- load expr
    */

    let type_expr = match typecheck::type_of(&expr) {
        Err(e) => {
            let explain = ::std::env::args().any(|s| s == "--explain");
            if !explain {
                term_painter::Color::BrightBlack.with(|| {
                    println!("Use \"dhall --explain\" for detailed errors");
                });
            }
            ERROR_STYLE.with(|| print!("Error: "));
            println!("{}", e.type_message.description());
            if explain {
                println!("{}", e.type_message);
            }
            println!("{}", e.current);
            // FIXME Print source position
            return;
        }
        Ok(type_expr) => type_expr,
    };

    println!("{}", type_expr);
    println!("");
    println!("{}", normalize::<_, X, _>(&expr));
}