use self::parser::RantyParser;
use crate::{RantyProgram, RantyProgramInfo};
use std::io::ErrorKind as IOErrorKind;
use std::{error::Error, fs};
use std::{fmt::Display, path::Path, rc::Rc};
pub(crate) mod lexer;
pub(crate) mod message;
pub(crate) mod parser;
pub(crate) mod reader;
pub use message::*;
pub type CompileResult = Result<RantyProgram, CompilerError>;
#[derive(Debug)]
pub enum CompilerError {
SyntaxError,
IOError(IOErrorKind),
}
impl Display for CompilerError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
CompilerError::SyntaxError => write!(f, "syntax error"),
CompilerError::IOError(_) => write!(f, "I/O error"),
}
}
}
impl Error for CompilerError {
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: RantyProgramInfo,
) -> CompileResult {
let info = Rc::new(info);
let mut parser = RantyParser::new(source, reporter, debug_enabled, &info);
match parser.parse() {
Ok(seq) => Ok(RantyProgram::new(seq, info)),
Err(()) => Err(CompilerError::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,
RantyProgramInfo {
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(CompilerError::IOError(err.kind()))
}
}
}