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
use crate::{RantProgram, RantProgramInfo};
use self::parser::RantParser;
use std::{error::Error, fs};
use std::{fmt::Display, path::Path, rc::Rc};
use std::io::ErrorKind as IOErrorKind;
pub(crate) mod lexer;
pub(crate) mod reader;
pub(crate) mod parser;
pub(crate) mod message;
pub use message::*;
pub type CompileResult = Result<RantProgram, CompilerErrorKind>;
#[derive(Debug)]
pub enum CompilerErrorKind {
SyntaxError,
IOError(IOErrorKind),
}
impl Display for CompilerErrorKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
CompilerErrorKind::SyntaxError => write!(f, "syntax error"),
CompilerErrorKind::IOError(_) => write!(f, "I/O error"),
}
}
}
impl Error for CompilerErrorKind {
fn source(&self) -> Option<&(dyn Error + 'static)> {
None
}
fn cause(&self) -> Option<&dyn Error> {
self.source()
}
}
pub trait Reporter {
fn report(&mut self, msg: CompilerMessage);
}
impl Reporter for () {
fn report(&mut self, _msg: CompilerMessage) {}
}
impl Reporter for Vec<CompilerMessage> {
fn report(&mut self, msg: CompilerMessage) {
self.push(msg);
}
}
pub(crate) fn compile_string<R: Reporter>(source: &str, reporter: &mut R, debug_enabled: bool, info: RantProgramInfo) -> CompileResult {
let info = Rc::new(info);
let mut parser = RantParser::new(source, reporter, debug_enabled, &info);
match parser.parse() {
Ok(seq) => Ok(RantProgram::new(seq, info)),
Err(()) => Err(CompilerErrorKind::SyntaxError),
}
}
pub(crate) fn compile_file<P: AsRef<Path>, R: Reporter>(path: P, reporter: &mut R, debug_enabled: bool) -> CompileResult {
let source_name = path.as_ref().canonicalize().unwrap_or_else(|_| path.as_ref().to_path_buf()).to_string_lossy().to_string();
let file_read_result = fs::read_to_string(path);
match file_read_result {
Ok(source) => {
compile_string(&source, reporter, debug_enabled, RantProgramInfo {
name: None,
path: Some(source_name)
})
},
Err(err) => {
let problem = match err.kind() {
IOErrorKind::NotFound => Problem::FileNotFound(source_name),
_ => Problem::FileSystemError(err.to_string())
};
reporter.report(CompilerMessage::new(problem, Severity::Error, None));
Err(CompilerErrorKind::IOError(err.kind()))
}
}
}