| // Copyright 2019 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| use crate::compiler::CompilerError; |
| use crate::dependency_graph::DependencyError; |
| use crate::parser_common::{BindParserError, CompoundIdentifier}; |
| use std::fmt; |
| |
| pub struct UserError { |
| index: String, |
| message: String, |
| span: Option<String>, |
| } |
| |
| impl UserError { |
| fn new(index: &str, message: &str, span: Option<String>) -> Self { |
| UserError { index: index.to_string(), message: message.to_string(), span: span } |
| } |
| } |
| |
| impl fmt::Display for UserError { |
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| writeln!(f, "[{}]: {}", self.index, self.message)?; |
| if let Some(span) = &self.span { |
| writeln!(f, "{}", span)?; |
| } |
| Ok(()) |
| } |
| } |
| |
| impl From<BindParserError> for UserError { |
| fn from(error: BindParserError) -> Self { |
| match error { |
| BindParserError::Type(span) => { |
| UserError::new("E001", "Expected a type keyword.", Some(span)) |
| } |
| BindParserError::StringLiteral(span) => { |
| UserError::new("E002", "Expected a string literal.", Some(span)) |
| } |
| BindParserError::NumericLiteral(span) => { |
| UserError::new("E003", "Expected a numerical literal.", Some(span)) |
| } |
| BindParserError::BoolLiteral(span) => { |
| UserError::new("E004", "Expected a boolean literal.", Some(span)) |
| } |
| BindParserError::Identifier(span) => { |
| UserError::new("E005", "Expected an identifier.", Some(span)) |
| } |
| BindParserError::Semicolon(span) => { |
| UserError::new("E006", "Missing semicolon (;).", Some(span)) |
| } |
| BindParserError::Assignment(span) => { |
| UserError::new("E007", "Expected an assignment. Are you missing a '='?", Some(span)) |
| } |
| BindParserError::ListStart(span) => { |
| UserError::new("E008", "Expected a list. Are you missing a '{'?", Some(span)) |
| } |
| BindParserError::ListEnd(span) => UserError::new( |
| "E009", |
| "List does not terminate. Are you missing a '}'?", |
| Some(span), |
| ), |
| BindParserError::ListSeparator(span) => UserError::new( |
| "E010", |
| "Expected a list separator. Are you missing a ','?", |
| Some(span), |
| ), |
| BindParserError::LibraryKeyword(span) => { |
| UserError::new("E011", "Expected 'library' keyword.", Some(span)) |
| } |
| BindParserError::UsingKeyword(span) => { |
| UserError::new("E012", "Expected 'using' keyword.", Some(span)) |
| } |
| BindParserError::AsKeyword(span) => { |
| UserError::new("E013", "Expected 'as' keyword", Some(span)) |
| } |
| BindParserError::IfBlockStart(span) => { |
| UserError::new("E014", "Expected '{' to begin if statement block.", Some(span)) |
| } |
| BindParserError::IfBlockEnd(span) => { |
| UserError::new("E015", "Expected '}' to end if statement block.", Some(span)) |
| } |
| BindParserError::IfKeyword(span) => { |
| UserError::new("E016", "Expected 'if' keyword.", Some(span)) |
| } |
| BindParserError::ElseKeyword(span) => { |
| UserError::new("E017", "Expected 'else' keyword", Some(span)) |
| } |
| BindParserError::ConditionOp(span) => { |
| UserError::new("E018", "Expected a condition operation ('==' or '!='.)", Some(span)) |
| } |
| BindParserError::ConditionValue(span) => UserError::new( |
| "E019", |
| "Expected a condition value: string, number, boolean, or identifier", |
| Some(span), |
| ), |
| BindParserError::AcceptKeyword(span) => { |
| UserError::new("E020", "Expected 'accept' keyword.", Some(span)) |
| } |
| BindParserError::AbortKeyword(span) => { |
| UserError::new("E024", "Expected 'abort' keyword.", Some(span)) |
| } |
| BindParserError::NoStatements(span) => UserError::new( |
| "E021", |
| "Bind programs must contain at least one statement.", |
| Some(span), |
| ), |
| BindParserError::UnterminatedComment => { |
| UserError::new("E023", "Found an unterminated multiline comment.", None) |
| } |
| BindParserError::Unknown(span, kind) => UserError::new( |
| "E022", |
| &format!( |
| "Unexpected parser error: {:?}. This is a bind compiler bug, please report it!", |
| kind |
| ), |
| Some(span), |
| ), |
| } |
| } |
| } |
| |
| impl From<CompilerError> for UserError { |
| fn from(error: CompilerError) -> Self { |
| match error { |
| CompilerError::FileOpenError(path) => UserError::new( |
| "E100", |
| &format!("Failed to open file: {}.", path.to_string_lossy()), |
| None, |
| ), |
| CompilerError::FileReadError(path) => UserError::new( |
| "E101", |
| &format!("Failed to read file: {}.", path.to_string_lossy()), |
| None, |
| ), |
| CompilerError::BindParserError(error) => UserError::from(error), |
| CompilerError::DependencyError(error) => UserError::from(error), |
| CompilerError::DuplicateIdentifier(identifier) => UserError::new( |
| "E102", |
| &format!("The identifier `{}` is defined multiple times.", identifier), |
| None, |
| ), |
| CompilerError::TypeMismatch(identifier) => UserError::new( |
| "E103", |
| &format!("The identifier `{}` is extended with a mismatched type.", identifier), |
| None, |
| ), |
| CompilerError::UnresolvedQualification(identifier) => UserError::new( |
| "E104", |
| &format!("Could not resolve the qualifier on `{}`.", identifier), |
| None, |
| ), |
| CompilerError::UndeclaredKey(identifier) => UserError::new( |
| "E105", |
| &format!("Could not find previous definition of extended key `{}`.", identifier), |
| None, |
| ), |
| CompilerError::MissingExtendsKeyword(identifier) => UserError::new( |
| "E106", |
| &format!( |
| "Cannot define a key with a namespace: `{}`. Are you missing an `extend`?", |
| identifier |
| ), |
| None, |
| ), |
| CompilerError::InvalidExtendsKeyword(identifier) => UserError::new( |
| "E107", |
| &format!("Cannot extend a key with no namespace: `{}`.", identifier), |
| None, |
| ), |
| CompilerError::UnknownKey(identifier) => UserError::new( |
| "E108", |
| &format!("Bind program refers to undefined identifier: `{}`.", identifier), |
| None, |
| ), |
| CompilerError::IfStatementMustBeTerminal => { |
| UserError::new("E109", "If statements must be the last statement in a block", None) |
| } |
| } |
| } |
| } |
| |
| impl From<DependencyError<CompoundIdentifier>> for UserError { |
| fn from(error: DependencyError<CompoundIdentifier>) -> Self { |
| match error { |
| DependencyError::MissingDependency(library) => { |
| UserError::new("E200", &format!("Missing dependency: {}", library), None) |
| } |
| DependencyError::CircularDependency => { |
| UserError::new("E201", "Cicular dependency", None) |
| } |
| } |
| } |
| } |