Move CompilationErrorKind into separate module (#416)
This commit is contained in:
parent
415c84ea39
commit
9c82a1e329
@ -116,7 +116,7 @@ impl<'a, 'b> AssignmentEvaluator<'a, 'b> {
|
||||
invocation_directory: &self.invocation_directory,
|
||||
dotenv: self.dotenv,
|
||||
};
|
||||
evaluate_function(token, name, &context, &call_arguments)
|
||||
Function::evaluate(token, name, &context, &call_arguments)
|
||||
}
|
||||
Expression::String { ref cooked_string } => Ok(cooked_string.cooked.to_string()),
|
||||
Expression::Backtick { raw, ref token } => {
|
||||
|
@ -77,7 +77,7 @@ impl<'a: 'b, 'b> AssignmentResolver<'a, 'b> {
|
||||
ref token,
|
||||
ref arguments,
|
||||
..
|
||||
} => resolve_function(token, arguments.len())?,
|
||||
} => Function::resolve(token, arguments.len())?,
|
||||
Expression::Concatination { ref lhs, ref rhs } => {
|
||||
self.resolve_expression(lhs)?;
|
||||
self.resolve_expression(rhs)?;
|
||||
|
@ -26,11 +26,12 @@ pub(crate) use crate::{
|
||||
assignment_evaluator::AssignmentEvaluator,
|
||||
assignment_resolver::AssignmentResolver,
|
||||
color::Color,
|
||||
compilation_error::{CompilationError, CompilationErrorKind, CompilationResult},
|
||||
compilation_error::CompilationError,
|
||||
compilation_error_kind::CompilationErrorKind,
|
||||
configuration::Configuration,
|
||||
expression::Expression,
|
||||
fragment::Fragment,
|
||||
function::{evaluate_function, resolve_function},
|
||||
function::Function,
|
||||
function_context::FunctionContext,
|
||||
functions::Functions,
|
||||
interrupt_guard::InterruptGuard,
|
||||
@ -45,7 +46,7 @@ pub(crate) use crate::{
|
||||
recipe::Recipe,
|
||||
recipe_context::RecipeContext,
|
||||
recipe_resolver::RecipeResolver,
|
||||
runtime_error::{RunResult, RuntimeError},
|
||||
runtime_error::RuntimeError,
|
||||
shebang::Shebang,
|
||||
state::State,
|
||||
string_literal::StringLiteral,
|
||||
@ -56,6 +57,10 @@ pub(crate) use crate::{
|
||||
verbosity::Verbosity,
|
||||
};
|
||||
|
||||
pub type CompilationResult<'a, T> = Result<T, CompilationError<'a>>;
|
||||
|
||||
pub type RunResult<'a, T> = Result<T, RuntimeError<'a>>;
|
||||
|
||||
#[allow(unused_imports)]
|
||||
pub(crate) use std::io::prelude::*;
|
||||
|
||||
|
@ -2,8 +2,6 @@ use crate::common::*;
|
||||
|
||||
use crate::misc::{maybe_s, show_whitespace, write_error_context, Or};
|
||||
|
||||
pub type CompilationResult<'a, T> = Result<T, CompilationError<'a>>;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct CompilationError<'a> {
|
||||
pub text: &'a str,
|
||||
@ -14,96 +12,6 @@ pub struct CompilationError<'a> {
|
||||
pub kind: CompilationErrorKind<'a>,
|
||||
}
|
||||
|
||||
#[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,
|
||||
},
|
||||
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,
|
||||
},
|
||||
UnknownStartOfToken,
|
||||
UnpairedCarriageReturn,
|
||||
UnterminatedInterpolation,
|
||||
UnterminatedString,
|
||||
UnterminatedBacktick,
|
||||
}
|
||||
|
||||
impl<'a> Display for CompilationError<'a> {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
|
||||
use CompilationErrorKind::*;
|
||||
|
91
src/compilation_error_kind.rs
Normal file
91
src/compilation_error_kind.rs
Normal file
@ -0,0 +1,91 @@
|
||||
use crate::common::*;
|
||||
|
||||
#[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,
|
||||
},
|
||||
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,
|
||||
},
|
||||
UnknownStartOfToken,
|
||||
UnpairedCarriageReturn,
|
||||
UnterminatedInterpolation,
|
||||
UnterminatedString,
|
||||
UnterminatedBacktick,
|
||||
}
|
102
src/function.rs
102
src/function.rs
@ -20,7 +20,7 @@ lazy_static! {
|
||||
.collect();
|
||||
}
|
||||
|
||||
enum Function {
|
||||
pub enum Function {
|
||||
Nullary(fn(&FunctionContext) -> Result<String, String>),
|
||||
Unary(fn(&FunctionContext, &str) -> Result<String, String>),
|
||||
Binary(fn(&FunctionContext, &str, &str) -> Result<String, String>),
|
||||
@ -35,64 +35,64 @@ impl Function {
|
||||
Binary(_) => 2,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resolve_function<'a>(token: &Token<'a>, argc: usize) -> CompilationResult<'a, ()> {
|
||||
let name = token.lexeme();
|
||||
if let Some(function) = FUNCTIONS.get(&name) {
|
||||
use self::Function::*;
|
||||
match (function, argc) {
|
||||
(&Nullary(_), 0) | (&Unary(_), 1) | (&Binary(_), 2) => Ok(()),
|
||||
_ => Err(
|
||||
token.error(CompilationErrorKind::FunctionArgumentCountMismatch {
|
||||
function: name,
|
||||
found: argc,
|
||||
expected: function.argc(),
|
||||
}),
|
||||
),
|
||||
pub fn resolve<'a>(token: &Token<'a>, argc: usize) -> CompilationResult<'a, ()> {
|
||||
let name = token.lexeme();
|
||||
if let Some(function) = FUNCTIONS.get(&name) {
|
||||
use self::Function::*;
|
||||
match (function, argc) {
|
||||
(&Nullary(_), 0) | (&Unary(_), 1) | (&Binary(_), 2) => Ok(()),
|
||||
_ => Err(
|
||||
token.error(CompilationErrorKind::FunctionArgumentCountMismatch {
|
||||
function: name,
|
||||
found: argc,
|
||||
expected: function.argc(),
|
||||
}),
|
||||
),
|
||||
}
|
||||
} else {
|
||||
Err(token.error(CompilationErrorKind::UnknownFunction {
|
||||
function: token.lexeme(),
|
||||
}))
|
||||
}
|
||||
} else {
|
||||
Err(token.error(CompilationErrorKind::UnknownFunction {
|
||||
function: token.lexeme(),
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn evaluate_function<'a>(
|
||||
token: &Token<'a>,
|
||||
name: &'a str,
|
||||
context: &FunctionContext,
|
||||
arguments: &[String],
|
||||
) -> RunResult<'a, String> {
|
||||
if let Some(function) = FUNCTIONS.get(name) {
|
||||
use self::Function::*;
|
||||
let argc = arguments.len();
|
||||
match (function, argc) {
|
||||
(&Nullary(f), 0) => f(context).map_err(|message| RuntimeError::FunctionCall {
|
||||
token: token.clone(),
|
||||
message,
|
||||
}),
|
||||
(&Unary(f), 1) => f(context, &arguments[0]).map_err(|message| RuntimeError::FunctionCall {
|
||||
token: token.clone(),
|
||||
message,
|
||||
}),
|
||||
(&Binary(f), 2) => {
|
||||
f(context, &arguments[0], &arguments[1]).map_err(|message| RuntimeError::FunctionCall {
|
||||
pub fn evaluate<'a>(
|
||||
token: &Token<'a>,
|
||||
name: &'a str,
|
||||
context: &FunctionContext,
|
||||
arguments: &[String],
|
||||
) -> RunResult<'a, String> {
|
||||
if let Some(function) = FUNCTIONS.get(name) {
|
||||
use self::Function::*;
|
||||
let argc = arguments.len();
|
||||
match (function, argc) {
|
||||
(&Nullary(f), 0) => f(context).map_err(|message| RuntimeError::FunctionCall {
|
||||
token: token.clone(),
|
||||
message,
|
||||
})
|
||||
}),
|
||||
(&Unary(f), 1) => f(context, &arguments[0]).map_err(|message| RuntimeError::FunctionCall {
|
||||
token: token.clone(),
|
||||
message,
|
||||
}),
|
||||
(&Binary(f), 2) => {
|
||||
f(context, &arguments[0], &arguments[1]).map_err(|message| RuntimeError::FunctionCall {
|
||||
token: token.clone(),
|
||||
message,
|
||||
})
|
||||
}
|
||||
_ => Err(RuntimeError::Internal {
|
||||
message: format!(
|
||||
"attempted to evaluate function `{}` with {} arguments",
|
||||
name, argc
|
||||
),
|
||||
}),
|
||||
}
|
||||
_ => Err(RuntimeError::Internal {
|
||||
message: format!(
|
||||
"attempted to evaluate function `{}` with {} arguments",
|
||||
name, argc
|
||||
),
|
||||
}),
|
||||
} else {
|
||||
Err(RuntimeError::Internal {
|
||||
message: format!("attempted to evaluate unknown function: `{}`", name),
|
||||
})
|
||||
}
|
||||
} else {
|
||||
Err(RuntimeError::Internal {
|
||||
message: format!("attempted to evaluate unknown function: `{}`", name),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,7 @@ mod color;
|
||||
mod command_ext;
|
||||
mod common;
|
||||
mod compilation_error;
|
||||
mod compilation_error_kind;
|
||||
mod configuration;
|
||||
mod expression;
|
||||
mod fragment;
|
||||
|
@ -71,7 +71,7 @@ impl<'a, 'b> RecipeResolver<'a, 'b> {
|
||||
}
|
||||
|
||||
fn resolve_function(&self, function: &Token, argc: usize) -> CompilationResult<'a, ()> {
|
||||
resolve_function(function, argc).map_err(|error| CompilationError {
|
||||
Function::resolve(function, argc).map_err(|error| CompilationError {
|
||||
offset: error.offset,
|
||||
line: error.line,
|
||||
column: error.column,
|
||||
|
@ -4,8 +4,6 @@ use brev::OutputError;
|
||||
|
||||
use crate::misc::{maybe_s, ticks, write_error_context, And, Or, Tick};
|
||||
|
||||
pub type RunResult<'a, T> = Result<T, RuntimeError<'a>>;
|
||||
|
||||
fn write_token_error_context(f: &mut Formatter, token: &Token) -> Result<(), fmt::Error> {
|
||||
write_error_context(
|
||||
f,
|
||||
|
Loading…
Reference in New Issue
Block a user