just/src/compilation_error.rs

316 lines
7.9 KiB
Rust
Raw Normal View History

use crate::common::*;
2017-11-16 23:30:08 -08:00
use crate::misc::{maybe_s, show_whitespace, write_error_context, Or};
2017-11-16 23:30:08 -08:00
2017-11-17 17:28:06 -08:00
pub type CompilationResult<'a, T> = Result<T, CompilationError<'a>>;
2017-11-16 23:30:08 -08:00
#[derive(Debug, PartialEq)]
pub struct CompilationError<'a> {
pub text: &'a str,
pub offset: usize,
pub line: usize,
2017-11-16 23:30:08 -08:00
pub column: usize,
pub width: usize,
pub kind: CompilationErrorKind<'a>,
2017-11-16 23:30:08 -08:00
}
#[derive(Debug, PartialEq)]
pub enum CompilationErrorKind<'a> {
AliasShadowsRecipe {
alias: &'a str,
recipe_line: usize,
},
CircularRecipeDependency {
recipe: &'a str,
circle: Vec<&'a str>,
},
CircularVariableDependency {
variable: &'a str,
circle: Vec<&'a str>,
},
DependencyHasParameters {
recipe: &'a str,
dependency: &'a str,
},
DuplicateAlias {
alias: &'a str,
first: usize,
},
DuplicateDependency {
recipe: &'a str,
dependency: &'a str,
},
DuplicateParameter {
recipe: &'a str,
parameter: &'a str,
},
DuplicateRecipe {
recipe: &'a str,
first: usize,
},
DuplicateVariable {
variable: &'a str,
},
2017-11-16 23:30:08 -08:00
ExtraLeadingWhitespace,
FunctionArgumentCountMismatch {
function: &'a str,
found: usize,
expected: usize,
},
InconsistentLeadingWhitespace {
expected: &'a str,
found: &'a str,
},
Internal {
message: String,
},
InvalidEscapeSequence {
character: char,
},
MixedLeadingWhitespace {
whitespace: &'a str,
},
ParameterFollowsVariadicParameter {
parameter: &'a str,
},
ParameterShadowsVariable {
parameter: &'a str,
},
RequiredParameterFollowsDefaultParameter {
parameter: &'a str,
},
UndefinedVariable {
variable: &'a str,
},
UnexpectedToken {
expected: Vec<TokenKind>,
found: TokenKind,
},
UnknownAliasTarget {
alias: &'a str,
target: &'a str,
},
UnknownDependency {
recipe: &'a str,
unknown: &'a str,
},
UnknownFunction {
function: &'a str,
},
2017-11-16 23:30:08 -08:00
UnknownStartOfToken,
UnpairedCarriageReturn,
UnterminatedInterpolation,
2017-11-16 23:30:08 -08:00
UnterminatedString,
UnterminatedBacktick,
2017-11-16 23:30:08 -08:00
}
impl<'a> Display for CompilationError<'a> {
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
2017-11-16 23:30:08 -08:00
use CompilationErrorKind::*;
let error = Color::fmt(f).error();
2017-11-16 23:30:08 -08:00
let message = Color::fmt(f).message();
write!(f, "{} {}", error.paint("error:"), message.prefix())?;
match self.kind {
AliasShadowsRecipe { alias, recipe_line } => {
writeln!(
f,
"Alias `{}` defined on `{}` shadows recipe defined on `{}`",
alias,
self.line + 1,
recipe_line + 1,
)?;
}
CircularRecipeDependency { recipe, ref circle } => {
2017-11-16 23:30:08 -08:00
if circle.len() == 2 {
writeln!(f, "Recipe `{}` depends on itself", recipe)?;
} else {
writeln!(
f,
"Recipe `{}` has circular dependency `{}`",
recipe,
circle.join(" -> ")
)?;
2017-11-16 23:30:08 -08:00
}
}
CircularVariableDependency {
variable,
ref circle,
} => {
2017-11-16 23:30:08 -08:00
if circle.len() == 2 {
writeln!(f, "Variable `{}` is defined in terms of itself", variable)?;
} else {
writeln!(
f,
"Variable `{}` depends on its own value: `{}`",
variable,
circle.join(" -> ")
)?;
2017-11-16 23:30:08 -08:00
}
}
InvalidEscapeSequence { character } => {
let representation = match character {
'`' => r"\`".to_string(),
'\\' => r"\".to_string(),
'\'' => r"'".to_string(),
'"' => r#"""#.to_string(),
_ => character.escape_default().collect(),
};
writeln!(f, "`\\{}` is not a valid escape sequence", representation)?;
2017-11-16 23:30:08 -08:00
}
DuplicateParameter { recipe, parameter } => {
writeln!(
f,
"Recipe `{}` has duplicate parameter `{}`",
recipe, parameter
)?;
2017-11-16 23:30:08 -08:00
}
DuplicateVariable { variable } => {
2017-11-16 23:30:08 -08:00
writeln!(f, "Variable `{}` has multiple definitions", variable)?;
}
UnexpectedToken {
ref expected,
found,
} => {
2017-11-16 23:30:08 -08:00
writeln!(f, "Expected {}, but found {}", Or(expected), found)?;
}
DuplicateAlias { alias, first } => {
writeln!(
f,
"Alias `{}` first defined on line `{}` is redefined on line `{}`",
alias,
first + 1,
self.line + 1,
)?;
}
DuplicateDependency { recipe, dependency } => {
writeln!(
f,
"Recipe `{}` has duplicate dependency `{}`",
recipe, dependency
)?;
2017-11-16 23:30:08 -08:00
}
DuplicateRecipe { recipe, first } => {
writeln!(
f,
"Recipe `{}` first defined on line {} is redefined on line {}",
recipe,
first + 1,
self.line + 1
)?;
2017-11-16 23:30:08 -08:00
}
DependencyHasParameters { recipe, dependency } => {
writeln!(
f,
"Recipe `{}` depends on `{}` which requires arguments. \
Dependencies may not require arguments",
recipe, dependency
)?;
2017-11-16 23:30:08 -08:00
}
ParameterShadowsVariable { parameter } => {
writeln!(
f,
"Parameter `{}` shadows variable of the same name",
parameter
)?;
2017-11-16 23:30:08 -08:00
}
RequiredParameterFollowsDefaultParameter { parameter } => {
writeln!(
f,
"Non-default parameter `{}` follows default parameter",
parameter
)?;
2017-11-16 23:30:08 -08:00
}
ParameterFollowsVariadicParameter { parameter } => {
2017-11-16 23:30:08 -08:00
writeln!(f, "Parameter `{}` follows variadic parameter", parameter)?;
}
MixedLeadingWhitespace { whitespace } => {
writeln!(
f,
2017-11-16 23:30:08 -08:00
"Found a mix of tabs and spaces in leading whitespace: `{}`\n\
Leading whitespace may consist of tabs or spaces, but not both",
2017-11-16 23:30:08 -08:00
show_whitespace(whitespace)
)?;
}
ExtraLeadingWhitespace => {
writeln!(f, "Recipe line has extra leading whitespace")?;
}
FunctionArgumentCountMismatch {
function,
found,
expected,
} => {
writeln!(
f,
"Function `{}` called with {} argument{} but takes {}",
function,
found,
maybe_s(found),
expected
)?;
}
InconsistentLeadingWhitespace { expected, found } => {
writeln!(
f,
2017-11-16 23:30:08 -08:00
"Recipe line has inconsistent leading whitespace. \
Recipe started with `{}` but found line with `{}`",
show_whitespace(expected),
show_whitespace(found)
2017-11-16 23:30:08 -08:00
)?;
}
UnknownAliasTarget { alias, target } => {
writeln!(f, "Alias `{}` has an unknown target `{}`", alias, target)?;
}
UnknownDependency { recipe, unknown } => {
writeln!(
f,
"Recipe `{}` has unknown dependency `{}`",
recipe, unknown
)?;
2017-11-16 23:30:08 -08:00
}
UndefinedVariable { variable } => {
2017-11-16 23:30:08 -08:00
writeln!(f, "Variable `{}` not defined", variable)?;
}
UnknownFunction { function } => {
writeln!(f, "Call to unknown function `{}`", function)?;
}
2017-11-16 23:30:08 -08:00
UnknownStartOfToken => {
writeln!(f, "Unknown start of token:")?;
}
UnpairedCarriageReturn => {
writeln!(f, "Unpaired carriage return")?;
}
UnterminatedInterpolation => {
writeln!(f, "Unterminated interpolation")?;
}
2017-11-16 23:30:08 -08:00
UnterminatedString => {
writeln!(f, "Unterminated string")?;
}
UnterminatedBacktick => {
writeln!(f, "Unterminated backtick")?;
}
Internal { ref message } => {
writeln!(
f,
"Internal error, this may indicate a bug in just: {}\n\
consider filing an issue: https://github.com/casey/just/issues/new",
message
)?;
2017-11-16 23:30:08 -08:00
}
}
write!(f, "{}", message.suffix())?;
write_error_context(
f,
self.text,
self.offset,
self.line,
self.column,
self.width,
)
2017-11-16 23:30:08 -08:00
}
}