Skip to content

Commit

Permalink
feat(remap): add abort-statement
Browse files Browse the repository at this point in the history
Signed-off-by: Jean Mertz <git@jeanmertz.com>
  • Loading branch information
JeanMertz committed Mar 12, 2021
1 parent 415c2b0 commit dc0c2e4
Show file tree
Hide file tree
Showing 14 changed files with 186 additions and 46 deletions.
5 changes: 5 additions & 0 deletions lib/vrl/compiler/src/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ impl<'a> Compiler<'a> {
FunctionCall(node) => self.compile_function_call(node).into(),
Variable(node) => self.compile_variable(node).into(),
Unary(node) => self.compile_unary(node).into(),
Abort(node) => self.compile_abort(node).into(),
}
}

Expand Down Expand Up @@ -381,6 +382,10 @@ impl<'a> Compiler<'a> {
})
}

fn compile_abort(&mut self, _: Node<()>) -> Abort {
Abort
}

fn handle_parser_error(&mut self, error: parser::Error) {
self.errors.push(Box::new(error))
}
Expand Down
54 changes: 43 additions & 11 deletions lib/vrl/compiler/src/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use diagnostic::{DiagnosticError, Label, Note};
use dyn_clone::{clone_trait_object, DynClone};
use std::fmt;

mod abort;
mod array;
mod block;
mod function_argument;
Expand All @@ -22,6 +23,7 @@ pub(crate) mod literal;
pub(crate) mod predicate;
pub(crate) mod query;

pub use abort::Abort;
pub use array::Array;
pub use assignment::Assignment;
pub use block::Block;
Expand Down Expand Up @@ -80,6 +82,7 @@ pub enum Expr {
Variable(Variable),
Noop(Noop),
Unary(Unary),
Abort(Abort),
}

impl Expr {
Expand All @@ -103,6 +106,7 @@ impl Expr {
Variable(..) => "variable call",
Noop(..) => "noop",
Unary(..) => "unary operation",
Abort(..) => "abort operation",
}
}
}
Expand All @@ -122,6 +126,7 @@ impl Expression for Expr {
Variable(v) => v.resolve(ctx),
Noop(v) => v.resolve(ctx),
Unary(v) => v.resolve(ctx),
Abort(v) => v.resolve(ctx),
}
}

Expand All @@ -139,6 +144,7 @@ impl Expression for Expr {
Variable(v) => v.type_def(state),
Noop(v) => v.type_def(state),
Unary(v) => v.type_def(state),
Abort(v) => v.type_def(state),
}
}
}
Expand All @@ -158,6 +164,7 @@ impl fmt::Display for Expr {
Variable(v) => v.fmt(f),
Noop(v) => v.fmt(f),
Unary(v) => v.fmt(f),
Abort(v) => v.fmt(f),
}
}
}
Expand Down Expand Up @@ -224,6 +231,12 @@ impl From<Unary> for Expr {
}
}

impl From<Abort> for Expr {
fn from(abort: Abort) -> Self {
Expr::Abort(abort)
}
}

// -----------------------------------------------------------------------------

#[derive(thiserror::Error, Debug)]
Expand Down Expand Up @@ -263,16 +276,19 @@ impl DiagnosticError for Error {

// -----------------------------------------------------------------------------

#[derive(Debug, Default, PartialEq)]
pub struct ExpressionError {
pub message: String,
pub labels: Vec<Label>,
pub notes: Vec<Note>,
#[derive(Debug, PartialEq)]
pub enum ExpressionError {
Abort,
Error {
message: String,
labels: Vec<Label>,
notes: Vec<Note>,
},
}

impl std::fmt::Display for ExpressionError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.message.fmt(f)
self.message().fmt(f)
}
}

Expand All @@ -288,23 +304,39 @@ impl DiagnosticError for ExpressionError {
}

fn message(&self) -> String {
self.message.clone()
use ExpressionError::*;

match self {
Abort => "aborted".to_owned(),
Error { message, .. } => message.clone(),
}
}

fn labels(&self) -> Vec<Label> {
self.labels.clone()
use ExpressionError::*;

match self {
Abort => vec![],
Error { labels, .. } => labels.clone(),
}
}

fn notes(&self) -> Vec<Note> {
self.notes.clone()
use ExpressionError::*;

match self {
Abort => vec![],
Error { notes, .. } => notes.clone(),
}
}
}

impl From<String> for ExpressionError {
fn from(message: String) -> Self {
ExpressionError {
ExpressionError::Error {
message,
..Default::default()
labels: vec![],
notes: vec![],
}
}
}
Expand Down
22 changes: 22 additions & 0 deletions lib/vrl/compiler/src/expression/abort.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use crate::expression::{ExpressionError, Resolved};
use crate::{Context, Expression, State, TypeDef};
use std::fmt;

#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Abort;

impl Expression for Abort {
fn resolve(&self, _: &mut Context) -> Resolved {
Err(ExpressionError::Abort)
}

fn type_def(&self, _: &State) -> TypeDef {
TypeDef::new().infallible().null()
}
}

impl fmt::Display for Abort {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "abort")
}
}
33 changes: 22 additions & 11 deletions lib/vrl/compiler/src/expression/function_call.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::expression::{FunctionArgument, Noop};
use crate::expression::{ExpressionError, FunctionArgument, Noop};
use crate::function::{ArgumentList, Parameter};
use crate::parser::{Ident, Node};
use crate::{value::Kind, Context, Expression, Function, Resolved, Span, State, TypeDef};
Expand Down Expand Up @@ -205,16 +205,27 @@ impl FunctionCall {
impl Expression for FunctionCall {
fn resolve(&self, ctx: &mut Context) -> Resolved {
span!(Level::ERROR, "remap", vrl_position = &self.span.start()).in_scope(|| {
self.expr.resolve(ctx).map_err(|mut err| {
err.message = format!(
r#"function call error for "{}" at ({}:{}): {}"#,
self.ident,
self.span.start(),
self.span.end(),
err.message
);

err
self.expr.resolve(ctx).map_err(|err| {
use ExpressionError::*;

match err {
Abort => panic!("abort errors must only be defined by `abort` statement"),
Error {
message,
labels,
notes,
} => ExpressionError::Error {
message: format!(
r#"function call error for "{}" at ({}:{}): {}"#,
self.ident,
self.span.start(),
self.span.end(),
message
),
labels,
notes,
},
}
})
})
}
Expand Down
5 changes: 3 additions & 2 deletions lib/vrl/compiler/src/value/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,10 @@ impl DiagnosticError for Error {

impl From<Error> for ExpressionError {
fn from(err: Error) -> Self {
ExpressionError {
Self::Error {
message: err.message(),
..Default::default()
labels: vec![],
notes: vec![],
}
}
}
2 changes: 1 addition & 1 deletion lib/vrl/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ pub use compiler::{
state, value, Context, Expression, Function, Program, Target, Value,
};
pub use diagnostic;
pub use runtime::{Runtime, RuntimeResult};
pub use runtime::{Runtime, RuntimeResult, Terminate};

/// Compile a given source into the final [`Program`].
pub fn compile(source: &str, fns: &[Box<dyn Function>]) -> compiler::Result {
Expand Down
47 changes: 36 additions & 11 deletions lib/vrl/core/src/runtime.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,38 @@
use crate::{state, Context, Path, Program, Target, Value};
use compiler::ExpressionError;
use std::{error::Error, fmt};

pub type RuntimeResult = Result<Value, Abort>;
pub type RuntimeResult = Result<Value, Terminate>;

#[derive(Debug, Default)]
pub struct Runtime {
state: state::Runtime,
}

/// The error raised if the runtime is aborted.
/// The error raised if the runtime is terminated.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Abort(String);
pub enum Terminate {
/// A manual `abort` call.
///
/// This is an intentional termination that does not result in an
/// `Ok(Value)` result, but should neither be interpreted as an unexpected
/// outcome.
Abort,

impl fmt::Display for Abort {
/// An unexpected program termination.
Error(String),
}

impl fmt::Display for Terminate {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.0)
match self {
Terminate::Abort => Ok(()),
Terminate::Error(error) => f.write_str(&error),
}
}
}

impl Error for Abort {
impl Error for Terminate {
fn source(&self) -> Option<&(dyn Error + 'static)> {
None
}
Expand All @@ -39,23 +53,34 @@ impl Runtime {
match target.get(&Path::root()) {
Ok(Some(Value::Object(_))) => {}
Ok(Some(value)) => {
return Err(Abort(format!(
return Err(Terminate::Error(format!(
"target must be a valid object, got {}: {}",
value.kind(),
value
)))
}
Ok(None) => return Err(Abort("expected target object, got nothing".to_owned())),
Err(err) => return Err(Abort(format!("error querying target object: {}", err))),
Ok(None) => {
return Err(Terminate::Error(
"expected target object, got nothing".to_owned(),
))
}
Err(err) => {
return Err(Terminate::Error(format!(
"error querying target object: {}",
err
)))
}
};

let mut context = Context::new(target, &mut self.state);

let mut values = program
.iter()
.map(|expr| {
expr.resolve(&mut context)
.map_err(|err| Abort(err.to_string()))
expr.resolve(&mut context).map_err(|err| match err {
ExpressionError::Abort => Terminate::Abort,
err @ ExpressionError::Error { .. } => Terminate::Error(err.to_string()),
})
})
.collect::<Result<Vec<_>, _>>()?;

Expand Down
3 changes: 3 additions & 0 deletions lib/vrl/parser/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ pub enum Expr {
FunctionCall(Node<FunctionCall>),
Variable(Node<Ident>),
Unary(Node<Unary>),
Abort(Node<()>),
}

impl fmt::Debug for Expr {
Expand All @@ -225,6 +226,7 @@ impl fmt::Debug for Expr {
FunctionCall(v) => format!("{:?}", v),
Variable(v) => format!("{:?}", v),
Unary(v) => format!("{:?}", v),
Abort(_) => "abort".to_owned(),
};

write!(f, "Expr({})", value)
Expand All @@ -245,6 +247,7 @@ impl fmt::Display for Expr {
FunctionCall(v) => v.fmt(f),
Variable(v) => v.fmt(f),
Unary(v) => v.fmt(f),
Abort(_) => f.write_str("abort"),
}
}
}
Expand Down

0 comments on commit dc0c2e4

Please sign in to comment.