2019-04-11 15:23:14 -07:00
|
|
|
use crate::common::*;
|
2017-11-16 23:30:08 -08:00
|
|
|
|
|
|
|
#[derive(Debug, PartialEq)]
|
2019-11-13 19:32:50 -08:00
|
|
|
pub(crate) struct CompilationError<'src> {
|
|
|
|
pub(crate) token: Token<'src>,
|
2020-02-10 20:07:06 -08:00
|
|
|
pub(crate) kind: CompilationErrorKind<'src>,
|
2017-11-16 23:30:08 -08:00
|
|
|
}
|
|
|
|
|
Gargantuan refactor (#522)
- Instead of changing the current directory with `env::set_current_dir`
to be implicitly inherited by subprocesses, we now use
`Command::current_dir` to set it explicitly. This feels much better,
since we aren't dependent on the implicit state of the process's
current directory.
- Subcommand execution is much improved.
- Added a ton of tests for config parsing, config execution, working
dir, and search dir.
- Error messages are improved. Many more will be colored.
- The Config is now onwed, instead of borrowing from the arguments and
the `clap::ArgMatches` object. This is a huge ergonomic improvement,
especially in tests, and I don't think anyone will notice.
- `--edit` now uses `$VISUAL`, `$EDITOR`, or `vim`, in that order,
matching git, which I think is what most people will expect.
- Added a cute `tmptree!{}` macro, for creating temporary directories
populated with directories and files for tests.
- Admitted that grammer is LL(k) and I don't know what `k` is.
2019-11-09 21:43:20 -08:00
|
|
|
impl Error for CompilationError<'_> {}
|
|
|
|
|
|
|
|
impl Display for CompilationError<'_> {
|
2019-04-11 15:23:14 -07:00
|
|
|
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
|
2017-11-16 23:30:08 -08:00
|
|
|
use CompilationErrorKind::*;
|
|
|
|
let message = Color::fmt(f).message();
|
|
|
|
|
Gargantuan refactor (#522)
- Instead of changing the current directory with `env::set_current_dir`
to be implicitly inherited by subprocesses, we now use
`Command::current_dir` to set it explicitly. This feels much better,
since we aren't dependent on the implicit state of the process's
current directory.
- Subcommand execution is much improved.
- Added a ton of tests for config parsing, config execution, working
dir, and search dir.
- Error messages are improved. Many more will be colored.
- The Config is now onwed, instead of borrowing from the arguments and
the `clap::ArgMatches` object. This is a huge ergonomic improvement,
especially in tests, and I don't think anyone will notice.
- `--edit` now uses `$VISUAL`, `$EDITOR`, or `vim`, in that order,
matching git, which I think is what most people will expect.
- Added a cute `tmptree!{}` macro, for creating temporary directories
populated with directories and files for tests.
- Admitted that grammer is LL(k) and I don't know what `k` is.
2019-11-09 21:43:20 -08:00
|
|
|
write!(f, "{}", message.prefix())?;
|
2017-11-16 23:30:08 -08:00
|
|
|
|
|
|
|
match self.kind {
|
2019-04-11 12:30:29 -07:00
|
|
|
AliasShadowsRecipe { alias, recipe_line } => {
|
|
|
|
writeln!(
|
|
|
|
f,
|
2019-10-19 20:00:41 -07:00
|
|
|
"Alias `{}` defined on line {} shadows recipe `{}` defined on line {}",
|
2019-04-11 12:30:29 -07:00
|
|
|
alias,
|
2019-11-13 19:32:50 -08:00
|
|
|
self.token.line.ordinal(),
|
2019-10-19 20:00:41 -07:00
|
|
|
alias,
|
2019-04-19 02:17:43 -07:00
|
|
|
recipe_line.ordinal(),
|
2019-04-11 12:30:29 -07:00
|
|
|
)?;
|
2020-02-10 20:07:06 -08:00
|
|
|
},
|
|
|
|
CircularRecipeDependency { recipe, ref circle } =>
|
2017-11-16 23:30:08 -08:00
|
|
|
if circle.len() == 2 {
|
|
|
|
writeln!(f, "Recipe `{}` depends on itself", recipe)?;
|
|
|
|
} else {
|
2018-12-08 14:29:41 -08:00
|
|
|
writeln!(
|
|
|
|
f,
|
|
|
|
"Recipe `{}` has circular dependency `{}`",
|
|
|
|
recipe,
|
|
|
|
circle.join(" -> ")
|
|
|
|
)?;
|
2020-02-10 20:07:06 -08:00
|
|
|
},
|
2018-12-08 14:29:41 -08:00
|
|
|
CircularVariableDependency {
|
|
|
|
variable,
|
|
|
|
ref circle,
|
2020-02-10 20:07:06 -08:00
|
|
|
} =>
|
2017-11-16 23:30:08 -08:00
|
|
|
if circle.len() == 2 {
|
|
|
|
writeln!(f, "Variable `{}` is defined in terms of itself", variable)?;
|
|
|
|
} else {
|
2018-12-08 14:29:41 -08:00
|
|
|
writeln!(
|
|
|
|
f,
|
|
|
|
"Variable `{}` depends on its own value: `{}`",
|
|
|
|
variable,
|
|
|
|
circle.join(" -> ")
|
|
|
|
)?;
|
2020-02-10 20:07:06 -08:00
|
|
|
},
|
2018-06-30 19:19:13 -07:00
|
|
|
|
2018-12-08 14:29:41 -08:00
|
|
|
InvalidEscapeSequence { character } => {
|
2018-06-30 19:19:13 -07:00
|
|
|
let representation = match character {
|
2018-12-08 14:29:41 -08:00
|
|
|
'`' => r"\`".to_string(),
|
2018-06-30 19:19:13 -07:00
|
|
|
'\\' => r"\".to_string(),
|
|
|
|
'\'' => r"'".to_string(),
|
|
|
|
'"' => r#"""#.to_string(),
|
|
|
|
_ => character.escape_default().collect(),
|
|
|
|
};
|
|
|
|
writeln!(f, "`\\{}` is not a valid escape sequence", representation)?;
|
2020-02-10 20:07:06 -08:00
|
|
|
},
|
2018-12-08 14:29:41 -08:00
|
|
|
DuplicateParameter { recipe, parameter } => {
|
|
|
|
writeln!(
|
|
|
|
f,
|
|
|
|
"Recipe `{}` has duplicate parameter `{}`",
|
|
|
|
recipe, parameter
|
|
|
|
)?;
|
2020-02-10 20:07:06 -08:00
|
|
|
},
|
2018-12-08 14:29:41 -08:00
|
|
|
DuplicateVariable { variable } => {
|
2017-11-16 23:30:08 -08:00
|
|
|
writeln!(f, "Variable `{}` has multiple definitions", variable)?;
|
2020-02-10 20:07:06 -08:00
|
|
|
},
|
2018-12-08 14:29:41 -08:00
|
|
|
UnexpectedToken {
|
|
|
|
ref expected,
|
|
|
|
found,
|
|
|
|
} => {
|
2019-10-09 01:40:40 -07:00
|
|
|
writeln!(f, "Expected {}, but found {}", List::or(expected), found)?;
|
2020-02-10 20:07:06 -08:00
|
|
|
},
|
2019-04-11 12:30:29 -07:00
|
|
|
DuplicateAlias { alias, first } => {
|
|
|
|
writeln!(
|
|
|
|
f,
|
2019-10-19 20:00:41 -07:00
|
|
|
"Alias `{}` first defined on line {} is redefined on line {}",
|
2019-04-11 12:30:29 -07:00
|
|
|
alias,
|
2019-04-19 02:17:43 -07:00
|
|
|
first.ordinal(),
|
2019-11-13 19:32:50 -08:00
|
|
|
self.token.line.ordinal(),
|
2019-04-11 12:30:29 -07:00
|
|
|
)?;
|
2020-02-10 20:07:06 -08:00
|
|
|
},
|
2018-12-08 14:29:41 -08:00
|
|
|
DuplicateRecipe { recipe, first } => {
|
|
|
|
writeln!(
|
|
|
|
f,
|
|
|
|
"Recipe `{}` first defined on line {} is redefined on line {}",
|
|
|
|
recipe,
|
2019-04-19 02:17:43 -07:00
|
|
|
first.ordinal(),
|
2019-11-13 19:32:50 -08:00
|
|
|
self.token.line.ordinal()
|
2018-12-08 14:29:41 -08:00
|
|
|
)?;
|
2020-02-10 20:07:06 -08:00
|
|
|
},
|
2019-11-10 23:17:47 -08:00
|
|
|
DuplicateSet { setting, first } => {
|
|
|
|
writeln!(
|
|
|
|
f,
|
|
|
|
"Setting `{}` first set on line {} is redefined on line {}",
|
|
|
|
setting,
|
|
|
|
first.ordinal(),
|
2019-11-13 19:32:50 -08:00
|
|
|
self.token.line.ordinal(),
|
2019-11-10 23:17:47 -08:00
|
|
|
)?;
|
2020-02-10 20:07:06 -08:00
|
|
|
},
|
2019-12-07 04:03:03 -08:00
|
|
|
DependencyArgumentCountMismatch {
|
|
|
|
dependency,
|
|
|
|
found,
|
|
|
|
min,
|
|
|
|
max,
|
|
|
|
} => {
|
|
|
|
write!(
|
2018-12-08 14:29:41 -08:00
|
|
|
f,
|
2019-12-07 04:03:03 -08:00
|
|
|
"Dependency `{}` got {} {} but takes ",
|
|
|
|
dependency,
|
|
|
|
found,
|
|
|
|
Count("argument", found),
|
2018-12-08 14:29:41 -08:00
|
|
|
)?;
|
2019-12-07 04:03:03 -08:00
|
|
|
|
|
|
|
if min == max {
|
|
|
|
let expected = min;
|
|
|
|
writeln!(f, "{} {}", expected, Count("argument", expected))?;
|
|
|
|
} else if found < min {
|
|
|
|
writeln!(f, "at least {} {}", min, Count("argument", min))?;
|
|
|
|
} else {
|
|
|
|
writeln!(f, "at most {} {}", max, Count("argument", max))?;
|
|
|
|
}
|
2020-02-10 20:07:06 -08:00
|
|
|
},
|
2020-10-26 18:16:42 -07:00
|
|
|
ExpectedKeyword { expected, found } => writeln!(
|
|
|
|
f,
|
|
|
|
"Expected keyword `{}` but found identifier `{}`",
|
|
|
|
expected, found
|
|
|
|
)?,
|
2018-12-08 14:29:41 -08:00
|
|
|
ParameterShadowsVariable { parameter } => {
|
|
|
|
writeln!(
|
|
|
|
f,
|
|
|
|
"Parameter `{}` shadows variable of the same name",
|
|
|
|
parameter
|
|
|
|
)?;
|
2020-02-10 20:07:06 -08:00
|
|
|
},
|
2018-12-08 14:29:41 -08:00
|
|
|
RequiredParameterFollowsDefaultParameter { parameter } => {
|
|
|
|
writeln!(
|
|
|
|
f,
|
|
|
|
"Non-default parameter `{}` follows default parameter",
|
|
|
|
parameter
|
|
|
|
)?;
|
2020-02-10 20:07:06 -08:00
|
|
|
},
|
2018-12-08 14:29:41 -08:00
|
|
|
ParameterFollowsVariadicParameter { parameter } => {
|
2017-11-16 23:30:08 -08:00
|
|
|
writeln!(f, "Parameter `{}` follows variadic parameter", parameter)?;
|
2020-02-10 20:07:06 -08:00
|
|
|
},
|
2018-12-08 14:29:41 -08:00
|
|
|
MixedLeadingWhitespace { whitespace } => {
|
|
|
|
writeln!(
|
|
|
|
f,
|
2020-02-10 20:07:06 -08:00
|
|
|
"Found a mix of tabs and spaces in leading whitespace: `{}`\nLeading whitespace may \
|
|
|
|
consist of tabs or spaces, but not both",
|
2019-10-09 01:40:40 -07:00
|
|
|
ShowWhitespace(whitespace)
|
2017-11-16 23:30:08 -08:00
|
|
|
)?;
|
2020-02-10 20:07:06 -08:00
|
|
|
},
|
2017-11-16 23:30:08 -08:00
|
|
|
ExtraLeadingWhitespace => {
|
|
|
|
writeln!(f, "Recipe line has extra leading whitespace")?;
|
2020-02-10 20:07:06 -08:00
|
|
|
},
|
2018-12-08 14:29:41 -08:00
|
|
|
FunctionArgumentCountMismatch {
|
|
|
|
function,
|
|
|
|
found,
|
|
|
|
expected,
|
|
|
|
} => {
|
2017-12-02 14:59:07 -08:00
|
|
|
writeln!(
|
|
|
|
f,
|
2019-10-09 01:40:40 -07:00
|
|
|
"Function `{}` called with {} {} but takes {}",
|
2018-12-08 14:29:41 -08:00
|
|
|
function,
|
|
|
|
found,
|
2019-10-09 01:40:40 -07:00
|
|
|
Count("argument", found),
|
2018-12-08 14:29:41 -08:00
|
|
|
expected
|
2017-12-02 14:59:07 -08:00
|
|
|
)?;
|
2020-02-10 20:07:06 -08:00
|
|
|
},
|
2018-12-08 14:29:41 -08:00
|
|
|
InconsistentLeadingWhitespace { expected, found } => {
|
|
|
|
writeln!(
|
|
|
|
f,
|
2020-02-10 20:07:06 -08:00
|
|
|
"Recipe line has inconsistent leading whitespace. Recipe started with `{}` but found \
|
|
|
|
line with `{}`",
|
2019-10-09 01:40:40 -07:00
|
|
|
ShowWhitespace(expected),
|
|
|
|
ShowWhitespace(found)
|
2017-11-16 23:30:08 -08:00
|
|
|
)?;
|
2020-02-10 20:07:06 -08:00
|
|
|
},
|
2019-04-11 12:30:29 -07:00
|
|
|
UnknownAliasTarget { alias, target } => {
|
|
|
|
writeln!(f, "Alias `{}` has an unknown target `{}`", alias, target)?;
|
2020-02-10 20:07:06 -08:00
|
|
|
},
|
2018-12-08 14:29:41 -08:00
|
|
|
UnknownDependency { recipe, unknown } => {
|
|
|
|
writeln!(
|
|
|
|
f,
|
|
|
|
"Recipe `{}` has unknown dependency `{}`",
|
|
|
|
recipe, unknown
|
|
|
|
)?;
|
2020-02-10 20:07:06 -08:00
|
|
|
},
|
2018-12-08 14:29:41 -08:00
|
|
|
UndefinedVariable { variable } => {
|
2017-11-16 23:30:08 -08:00
|
|
|
writeln!(f, "Variable `{}` not defined", variable)?;
|
2020-02-10 20:07:06 -08:00
|
|
|
},
|
2018-12-08 14:29:41 -08:00
|
|
|
UnknownFunction { function } => {
|
2017-12-02 05:37:10 -08:00
|
|
|
writeln!(f, "Call to unknown function `{}`", function)?;
|
2020-02-10 20:07:06 -08:00
|
|
|
},
|
2019-11-10 23:17:47 -08:00
|
|
|
UnknownSetting { setting } => {
|
|
|
|
writeln!(f, "Unknown setting `{}`", setting)?;
|
2020-02-10 20:07:06 -08:00
|
|
|
},
|
2020-10-26 18:16:42 -07:00
|
|
|
UnexpectedCharacter { expected } => {
|
|
|
|
writeln!(f, "Expected character `{}`", expected)?;
|
|
|
|
},
|
2017-11-16 23:30:08 -08:00
|
|
|
UnknownStartOfToken => {
|
|
|
|
writeln!(f, "Unknown start of token:")?;
|
2020-02-10 20:07:06 -08:00
|
|
|
},
|
2019-04-15 22:40:02 -07:00
|
|
|
UnpairedCarriageReturn => {
|
|
|
|
writeln!(f, "Unpaired carriage return")?;
|
2020-02-10 20:07:06 -08:00
|
|
|
},
|
2017-12-02 12:49:31 -08:00
|
|
|
UnterminatedInterpolation => {
|
|
|
|
writeln!(f, "Unterminated interpolation")?;
|
2020-02-10 20:07:06 -08:00
|
|
|
},
|
2017-11-16 23:30:08 -08:00
|
|
|
UnterminatedString => {
|
|
|
|
writeln!(f, "Unterminated string")?;
|
2020-02-10 20:07:06 -08:00
|
|
|
},
|
2019-04-15 22:40:02 -07:00
|
|
|
UnterminatedBacktick => {
|
|
|
|
writeln!(f, "Unterminated backtick")?;
|
2020-02-10 20:07:06 -08:00
|
|
|
},
|
2018-12-08 14:29:41 -08:00
|
|
|
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
|
|
|
|
)?;
|
2020-02-10 20:07:06 -08:00
|
|
|
},
|
2017-11-16 23:30:08 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
write!(f, "{}", message.suffix())?;
|
|
|
|
|
2019-11-13 19:32:50 -08:00
|
|
|
self.token.write_context(f, Color::fmt(f).error())
|
2017-11-16 23:30:08 -08:00
|
|
|
}
|
|
|
|
}
|