aboutsummaryrefslogtreecommitdiffstats
path: root/modelica-parser-lalrpop/src/lib.rs
blob: 26fca7991b75614dd5844941fa2bc31e37169f7c (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

extern crate lalrpop_util;
extern crate colored;
extern crate regex;

mod parser;
mod ast;

use colored::*;
use lalrpop_util::ParseError;
use regex::Regex;

pub use ast::*;
pub use parser::{
    parse_file,
    parse_model,
    parse_package,
    parse_block,
    parse_connector,
    parse_record,
};

pub fn strip_comments(raw: &str) -> String {
    // TODO: shouldn't recompile regex on every function call

    // Match on comments:
    //      (?m) sets multi-line mode
    let comment_re = Regex::new(r"(?m)(//.*)$").unwrap();
    comment_re.replace_all(&raw, "")
}

fn pp_segment(raw: &str, start: usize, end: usize) -> String {
    let mut line_start = 0;
    let mut num = 0;
    let mut ret = String::new();
    for line in raw.lines() {
        num += 1;
        let line_end = line_start + line.len();
        if (line_start <= start) && (start < line_end) {
            ret += &format!("    {}\n{:>3} {} {}{}{}\n    {} {}{}\n",
                "|".blue().bold(),
                num.to_string().blue().bold(),
                "|".blue().bold(),
                raw[line_start..start].normal(),
                raw[start..end].red().bold(),
                if end < line_end {
                    raw[end..line_end].normal()
                } else {
                    "".normal()
                },
                "|".blue().bold(),
                std::iter::repeat(" ").take(start - line_start).collect::<String>(),
                std::iter::repeat("^").take(end - start).collect::<String>().red().bold());
        }
        line_start += line.len() + 1;
        if line_start > end { break };
    }
    ret
}

pub fn pp_parseerror(raw: &str, pe: ParseError<usize, (usize, &str), ()>) -> String {
    match pe {
        ParseError::InvalidToken{location} => {
            format!("{} invalid token starting at:\n{}",
                "parse error:".red().bold(),
                pp_segment(raw, location, location+1)) },
        ParseError::UnrecognizedToken{token: Some((start, (_, tok), end)), expected} => {
            format!("{} unrecognized token '{}'{}:\n{}",
                "parse error:".red().bold(),
                tok,
                if expected.len() > 0 {
                    format!(" (expected one of {:?})", expected)
                } else {
                    format!("")
                },
                pp_segment(raw, start, end)) },
        ParseError::UnrecognizedToken{token: None, expected} => {
            format!("{} premature end-of-file{}",
                "parse error:".red().bold(),
                if expected.len() > 0 {
                    format!(" (expected one of {:?})", expected)
                } else {
                    format!("")
                }) },
        ParseError::ExtraToken{token: (start, (_, tok), end)} => {
            format!("{} unexpected extra token '{}':\n{}",
                "parse error:".red().bold(),
                tok,
                pp_segment(raw, start, end)) },
        _ => {
            format!("{} {:?}", "parse error:".red().bold(), pe) },
    }
}