Skip to main content

ucglib/build/opcode/
error.rs

1// Copyright 2019 Jeremy Wall
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14use std::convert::From;
15use std::fmt;
16use std::fmt::Display;
17use std::io;
18use std::rc::Rc;
19
20use crate::ast::Position;
21use crate::build::opcode::convert;
22
23#[derive(Debug)]
24pub struct Error {
25    message: Rc<str>,
26    pos: Option<Position>,
27    call_stack: Vec<Position>,
28}
29
30impl Error {
31    pub fn new(msg: Rc<str>, pos: Position) -> Self {
32        Self {
33            message: msg,
34            pos: Some(pos),
35            call_stack: Vec::new(),
36        }
37    }
38
39    pub fn with_pos(mut self, pos: Position) -> Self {
40        self.pos = Some(pos);
41        self
42    }
43
44    pub fn push_call_stack(&mut self, pos: Position) {
45        self.call_stack.push(pos);
46    }
47}
48
49macro_rules! decorate_error {
50    ($pos:expr => $result:expr) => {
51        match $result {
52            Ok(v) => Ok(v),
53            Err(e) => Err(e.with_pos($pos.clone())),
54        }
55    };
56}
57
58macro_rules! decorate_call {
59    ($pos:expr => $result:expr) => {
60        match $result {
61            Ok(v) => Ok(v),
62            Err(mut e) => {
63                e.push_call_stack($pos.clone());
64                Err(e)
65            }
66        }
67    };
68}
69
70impl From<regex::Error> for Error {
71    fn from(e: regex::Error) -> Self {
72        Error {
73            message: format!("{}", e).into(),
74            pos: None,
75            call_stack: Vec::new(),
76        }
77    }
78}
79
80impl From<std::io::Error> for Error {
81    fn from(e: std::io::Error) -> Self {
82        let msg = match e.kind() {
83            io::ErrorKind::NotFound | io::ErrorKind::Other => {
84                format!("OSError: Path not found: {}", e)
85            }
86            _ => format!("{}", e),
87        }
88        .into();
89        Error {
90            message: msg,
91            pos: None,
92            call_stack: Vec::new(),
93        }
94    }
95}
96
97impl From<convert::Error> for Error {
98    fn from(e: convert::Error) -> Self {
99        Error {
100            message: e.message().into(),
101            pos: None,
102            call_stack: Vec::new(),
103        }
104    }
105}
106
107impl Display for Error {
108    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
109        if let Some(ref pos) = self.pos {
110            write!(f, "{} at {}", self.message, pos)?;
111        } else {
112            write!(f, "{}", self.message)?;
113        }
114        if !self.call_stack.is_empty() {
115            for p in self.call_stack.iter() {
116                write!(f, "\nVIA: {}", p)?;
117            }
118        }
119        Ok(())
120    }
121}
122
123impl std::error::Error for Error {}