// Copyright 2017 Jeremy Wall // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //! Errors for use by the ucg compiler. use std::error; use std::fmt; use std::fmt::Debug; use crate::ast::*; use crate::iter::FilePositioned; /// ErrorType defines the various types of errors that can result from compiling UCG into an /// output format. pub enum ErrorType { // Build Errors TypeFail, DuplicateBinding, Unsupported, NoSuchSymbol, BadArgLen, FormatError, ReservedWordError, // Parsing Errors ParseError, AssertError, // User Defined Declarative Errors UserDefined, } impl fmt::Display for ErrorType { fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result { let name = match self { &ErrorType::TypeFail => "TypeFail", &ErrorType::DuplicateBinding => "DuplicateBinding", &ErrorType::Unsupported => "Unsupported", &ErrorType::NoSuchSymbol => "NoSuchSymbol", &ErrorType::BadArgLen => "BadArgLen", &ErrorType::FormatError => "FormatError", &ErrorType::ReservedWordError => "ReservedWordError", &ErrorType::ParseError => "ParseError", &ErrorType::AssertError => "AssertError", &ErrorType::UserDefined => "UserDefined", }; w.write_str(name) } } /// Error defines an Error type for parsing and building UCG code. pub struct BuildError { pub err_type: ErrorType, pub pos: Position, pub msg: String, _pkgonly: (), } impl BuildError { pub fn new>(msg: S, t: ErrorType, pos: Position) -> Self { BuildError { err_type: t, pos: pos, msg: msg.into(), _pkgonly: (), } } fn render(&self, w: &mut fmt::Formatter) -> fmt::Result { let file = match self.pos.file { Some(ref pb) => pb.to_string_lossy().to_string(), None => "".to_string(), }; write!( w, "{} at {} line: {} column: {}\nCaused By:\n\t{} ", self.err_type, file, self.pos.line, self.pos.column, self.msg )?; Ok(()) } } impl Debug for BuildError { fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result { self.render(w) } } impl fmt::Display for BuildError { fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result { self.render(w) } } impl error::Error for BuildError { fn description(&self) -> &str { &self.msg } } #[derive(Debug)] pub struct StackPrinter { pub err: abortable_parser::Error, } impl StackPrinter { pub fn render(&self, w: &mut fmt::Formatter) -> fmt::Result { let mut curr_err = Some(&self.err); let mut tabstop = ""; loop { match curr_err { // our exit condition; None => break, Some(err) => { let context = err.get_context(); let file = match context.file() { Some(ref pb) => pb.to_string_lossy().to_string(), None => "".to_string(), }; write!( w, "{}{}: at {} line: {}, column: {}\n", tabstop, err.get_msg(), file, context.line(), context.column(), )?; tabstop = "\t"; curr_err = err.get_cause(); if curr_err.is_some() { write!(w, "Caused by: \n")?; } } } } Ok(()) } } impl fmt::Display for StackPrinter { fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result { self.render(w) } }