blob: 635e1dccb692baeef528ac5762da38329230fcca [file] [log] [blame]
// Copyright 2020 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::debugger;
use crate::dependency_graph::DependencyError;
use crate::offline_debugger;
use crate::parser_common::{BindParserError, CompoundIdentifier};
use crate::test;
use std::fmt;
pub struct UserError {
index: String,
message: String,
span: Option<String>,
is_compiler_bug: bool,
}
impl UserError {
fn new(index: &str, message: &str, span: Option<String>, is_compiler_bug: bool) -> Self {
UserError { index: index.to_string(), message: message.to_string(), span, is_compiler_bug }
}
}
impl fmt::Display for UserError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "[{}]: {}", self.index, self.message)?;
if self.is_compiler_bug {
writeln!(f, "This is a bind compiler bug, please report it!")?;
}
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), false)
}
BindParserError::StringLiteral(span) => {
UserError::new("E002", "Expected a string literal.", Some(span), false)
}
BindParserError::NumericLiteral(span) => {
UserError::new("E003", "Expected a numerical literal.", Some(span), false)
}
BindParserError::BoolLiteral(span) => {
UserError::new("E004", "Expected a boolean literal.", Some(span), false)
}
BindParserError::Identifier(span) => {
UserError::new("E005", "Expected an identifier.", Some(span), false)
}
BindParserError::Semicolon(span) => {
UserError::new("E006", "Missing semicolon (;).", Some(span), false)
}
BindParserError::Assignment(span) => UserError::new(
"E007",
"Expected an assignment. Are you missing a '='?",
Some(span),
false,
),
BindParserError::ListStart(span) => {
UserError::new("E008", "Expected a list. Are you missing a '{'?", Some(span), false)
}
BindParserError::ListEnd(span) => UserError::new(
"E009",
"List does not terminate. Are you missing a '}'?",
Some(span),
false,
),
BindParserError::ListSeparator(span) => UserError::new(
"E010",
"Expected a list separator. Are you missing a ','?",
Some(span),
false,
),
BindParserError::LibraryKeyword(span) => {
UserError::new("E011", "Expected 'library' keyword.", Some(span), false)
}
BindParserError::UsingKeyword(span) => {
UserError::new("E012", "Expected 'using' keyword.", Some(span), false)
}
BindParserError::AsKeyword(span) => {
UserError::new("E013", "Expected 'as' keyword", Some(span), false)
}
BindParserError::IfBlockStart(span) => UserError::new(
"E014",
"Expected '{' to begin if statement block.",
Some(span),
false,
),
BindParserError::IfBlockEnd(span) => {
UserError::new("E015", "Expected '}' to end if statement block.", Some(span), false)
}
BindParserError::IfKeyword(span) => {
UserError::new("E016", "Expected 'if' keyword.", Some(span), false)
}
BindParserError::ElseKeyword(span) => {
UserError::new("E017", "Expected 'else' keyword", Some(span), false)
}
BindParserError::ConditionOp(span) => UserError::new(
"E018",
"Expected a condition operation ('==' or '!='.)",
Some(span),
false,
),
BindParserError::ConditionValue(span) => UserError::new(
"E019",
"Expected a condition value: string, number, boolean, or identifier",
Some(span),
false,
),
BindParserError::AcceptKeyword(span) => {
UserError::new("E020", "Expected 'accept' keyword.", Some(span), false)
}
BindParserError::AbortKeyword(span) => {
UserError::new("E024", "Expected 'abort' keyword.", Some(span), false)
}
BindParserError::NoStatements(span) => UserError::new(
"E021",
"Bind programs must contain at least one statement.",
Some(span),
false,
),
BindParserError::Eof(span) => {
UserError::new("E025", "Expected end of file.", Some(span), false)
}
BindParserError::UnterminatedComment => {
UserError::new("E023", "Found an unterminated multiline comment.", None, false)
}
BindParserError::Unknown(span, kind) => UserError::new(
"E022",
&format!("Unexpected parser error: {:?}.", kind),
Some(span),
true,
),
}
}
}
impl From<CompilerError> for UserError {
fn from(error: CompilerError) -> Self {
match error {
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,
false,
),
CompilerError::TypeMismatch(identifier) => UserError::new(
"E103",
&format!("The identifier `{}` is extended with a mismatched type.", identifier),
None,
false,
),
CompilerError::UnresolvedQualification(identifier) => UserError::new(
"E104",
&format!("Could not resolve the qualifier on `{}`.", identifier),
None,
false,
),
CompilerError::UndeclaredKey(identifier) => UserError::new(
"E105",
&format!("Could not find previous definition of extended key `{}`.", identifier),
None,
false,
),
CompilerError::MissingExtendsKeyword(identifier) => UserError::new(
"E106",
&format!(
"Cannot define a key with a namespace: `{}`. Are you missing an `extend`?",
identifier
),
None,
false,
),
CompilerError::InvalidExtendsKeyword(identifier) => UserError::new(
"E107",
&format!("Cannot extend a key with no namespace: `{}`.", identifier),
None,
false,
),
CompilerError::UnknownKey(identifier) => UserError::new(
"E108",
&format!("Bind program refers to undefined identifier: `{}`.", identifier),
None,
false,
),
CompilerError::IfStatementMustBeTerminal => UserError::new(
"E109",
"If statements must be the last statement in a block",
None,
false,
),
}
}
}
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, false)
}
DependencyError::CircularDependency => {
UserError::new("E201", "Cicular dependency", None, false)
}
}
}
}
impl From<offline_debugger::DebuggerError> for UserError {
fn from(error: offline_debugger::DebuggerError) -> Self {
match error {
offline_debugger::DebuggerError::BindParserError(error) => UserError::from(error),
offline_debugger::DebuggerError::CompilerError(error) => UserError::from(error),
offline_debugger::DebuggerError::DuplicateKey(identifier) => UserError::new(
"E300",
&format!(
"The key `{}` appears multiple times in the device specification.",
identifier
),
None,
false,
),
offline_debugger::DebuggerError::MissingLabel => UserError::new(
"E301",
"Missing label in the bind program symbolic instructions.",
None,
true,
),
offline_debugger::DebuggerError::NoOutcome => UserError::new(
"E302",
"Reached the end of the symbolic instructions without binding or aborting.",
None,
true,
),
offline_debugger::DebuggerError::IncorrectAstLocation => UserError::new(
"E303",
"Symbolic instruction has an incorrect AST location.",
None,
true,
),
offline_debugger::DebuggerError::InvalidAstLocation => UserError::new(
"E304",
"AST location contains an incorrect statement type.",
None,
true,
),
offline_debugger::DebuggerError::UnknownKey(identifier) => UserError::new(
"E305",
&format!("Statement contains an undefined identifier: `{}`.", identifier),
None,
true,
),
offline_debugger::DebuggerError::InvalidValueSymbol(symbol) => UserError::new(
"E306",
&format!("Symbol is not a valid value type: `{:?}`.", symbol),
None,
true,
),
}
}
}
impl From<debugger::DebuggerError> for UserError {
fn from(error: debugger::DebuggerError) -> Self {
match error {
debugger::DebuggerError::BindFlagsNotSupported => {
UserError::new("E001", "The BIND_FLAGS property is not supported.", None, false)
}
debugger::DebuggerError::InvalidCondition(condition) => UserError::new(
"E002",
&format!(
"A bind program instruction contained an invalid condition: {}.",
condition
),
None,
true,
),
debugger::DebuggerError::InvalidOperation(operation) => UserError::new(
"E003",
&format!(
"A bind program instruction contained an invalid operation: {}.",
operation
),
None,
true,
),
debugger::DebuggerError::InvalidAstLocation(ast_location) => UserError::new(
"E004",
&format!(
"A bind program instruction contained an invalid AST location: {}.",
ast_location
),
None,
true,
),
debugger::DebuggerError::IncorrectAstLocation => UserError::new(
"E005",
"The debugger only works with bind programs written in the new bind language.",
None,
false,
),
debugger::DebuggerError::MissingLabel => UserError::new(
"E006",
"The bind program contained a GOTO with no matching LABEL.",
None,
true,
),
debugger::DebuggerError::MissingBindProtocol => UserError::new(
"E007",
concat!(
"Device doesn't have a BIND_PROTOCOL property. ",
"The outcome of the bind program would depend on the device's protocol_id."
),
None,
false,
),
debugger::DebuggerError::NoOutcome => UserError::new(
"E008",
"Reached the end of the instructions without binding or aborting.",
None,
true,
),
debugger::DebuggerError::DuplicateKey(key) => UserError::new(
"E009",
&format!("The device has multiple values for the key {:#06x}.", key),
None,
false,
),
debugger::DebuggerError::IncorrectCondition => {
UserError::new("E010", "An incorrect condition type was encountered.", None, true)
}
debugger::DebuggerError::InvalidDeprecatedKey(key) => UserError::new(
"E011",
&format!("The bind program contained an invalid deprecated key: {:#06x}.", key),
None,
true,
),
}
}
}
impl From<test::TestError> for UserError {
fn from(error: test::TestError) -> Self {
match error {
test::TestError::BindParserError(error) => UserError::from(error),
test::TestError::DeviceSpecParserError(error) => UserError::from(error),
test::TestError::DebuggerError(error) => UserError::from(error),
test::TestError::CompilerError(error) => UserError::from(error),
test::TestError::InvalidSchema => {
UserError::new("E401", "The test specification JSON schema is invalid.", None, true)
}
test::TestError::InvalidJsonError => UserError::new(
"E402",
"The test specification is invalid according to the schema.",
None,
false,
),
test::TestError::JsonParserError(error) => {
UserError::new("E403", &format!("Failed to parse JSON: {}.", error), None, false)
}
}
}
}