Skip to content

Commit

Permalink
Merge pull request #33 from lumen/error-2
Browse files Browse the repository at this point in the history
:erlang.error/2
  • Loading branch information
bitwalker committed May 21, 2019
2 parents 2d285a6 + 8df804d commit 1f470a5
Show file tree
Hide file tree
Showing 7 changed files with 355 additions and 6 deletions.
64 changes: 64 additions & 0 deletions lumen_runtime/src/exception.rs
Expand Up @@ -12,6 +12,7 @@ pub enum Class {
pub struct Exception {
pub class: Class,
pub reason: Term,
pub arguments: Option<Term>,
pub file: &'static str,
pub line: u32,
pub column: u32,
Expand Down Expand Up @@ -66,6 +67,12 @@ macro_rules! assert_error {
($left:expr, $reason:expr, $process:expr,) => {{
assert_eq_in_process!($left, Err(error!($reason)), $process)
}};
($left:expr, $reason:expr, $arguments:expr, $process:expr) => {{
assert_eq_in_process!($left, Err(error!($reason, $arguments)), $process)
}};
($left:expr, $reason:expr, $arguments:expr, $process:expr,) => {{
assert_eq_in_process!($left, Err(error!($reason, $arguments)), $process)
}};
}

#[macro_export]
Expand All @@ -86,9 +93,66 @@ macro_rules! error {
Exception {
class: Error,
reason: $reason,
arguments: None,
file: file!(),
line: line!(),
column: column!(),
}
}};
($reason:expr, $arguments:expr) => {{
use crate::exception::{Class::Error, Exception};

Exception {
class: Error,
reason: $reason,
arguments: Some($arguments),
file: file!(),
line: line!(),
column: column!(),
}
}};
($reason:expr, $arguments:expr,) => {{
error!($reason, $arguments)
}};
}

#[cfg(test)]
mod tests {
use super::*;

mod error {
use super::*;

use std::sync::{Arc, RwLock};

use crate::atom::Existence::DoNotCare;
use crate::environment::{self, Environment};

#[test]
fn without_arguments_stores_none() {
let environment_rw_lock: Arc<RwLock<Environment>> = Default::default();
let process_rw_lock = environment::process(Arc::clone(&environment_rw_lock));
let mut process = process_rw_lock.write().unwrap();
let reason = Term::str_to_atom("badarg", DoNotCare, &mut process).unwrap();

let error = error!(reason);

assert_eq_in_process!(error.reason, reason, &mut process);
assert_eq_in_process!(error.arguments, None, &mut process);
}

#[test]
fn without_arguments_stores_some() {
let environment_rw_lock: Arc<RwLock<Environment>> = Default::default();
let process_rw_lock = environment::process(Arc::clone(&environment_rw_lock));
let mut process = process_rw_lock.write().unwrap();
let reason = Term::str_to_atom("badarg", DoNotCare, &mut process).unwrap();
let arguments = Term::EMPTY_LIST;

let error = error!(reason, arguments);

assert_eq_in_process!(error.reason, reason, &mut process);
assert_eq_in_process!(error.arguments, Some(arguments), &mut process);
}
}
}
4 changes: 2 additions & 2 deletions lumen_runtime/src/lib.rs
Expand Up @@ -14,11 +14,11 @@
#[macro_use]
extern crate cfg_if;

#[macro_use]
mod exception;
#[macro_use]
mod process;
#[macro_use]
mod exception;
#[macro_use]
mod support;

mod atom;
Expand Down
6 changes: 6 additions & 0 deletions lumen_runtime/src/otp/erlang.rs
Expand Up @@ -428,10 +428,16 @@ pub fn element(tuple: Term, index: Term, mut process: &mut Process) -> Result {
inner_tuple.element(inner_index, &mut process)
}

/// `error/1`
pub fn error(reason: Term) -> Result {
Err(error!(reason))
}

/// `error/2`
pub fn error_with_arguments(reason: Term, arguments: Term) -> Result {
Err(error!(reason, arguments))
}

pub fn head(list: Term, mut process: &mut Process) -> Result {
let cons: &Cons = list.try_into_in_process(&mut process)?;

Expand Down
1 change: 1 addition & 0 deletions lumen_runtime/src/otp/erlang/tests.rs
Expand Up @@ -24,6 +24,7 @@ mod convert_time_unit;
mod delete_element;
mod element;
mod error;
mod error_with_arguments;
mod head;
mod insert_element;
mod is_atom;
Expand Down
256 changes: 256 additions & 0 deletions lumen_runtime/src/otp/erlang/tests/error_with_arguments.rs
@@ -0,0 +1,256 @@
use super::*;

use std::sync::{Arc, RwLock};

use num_traits::Num;

use crate::atom::Existence::DoNotCare;
use crate::environment::{self, Environment};
use crate::process::IntoProcess;

#[test]
fn with_atom_returns_error_with_atom_reason() {
let environment_rw_lock: Arc<RwLock<Environment>> = Default::default();
let process_rw_lock = environment::process(Arc::clone(&environment_rw_lock));
let mut process = process_rw_lock.write().unwrap();
let reason = Term::str_to_atom("reason", DoNotCare, &mut process).unwrap();
let arguments = Term::cons(
Term::str_to_atom("first", DoNotCare, &mut process).unwrap(),
Term::EMPTY_LIST,
&mut process,
);

assert_error!(
erlang::error_with_arguments(reason, arguments),
reason,
arguments,
&mut process
);
}

#[test]
fn with_empty_list_returns_error_with_empty_list_reason() {
let environment_rw_lock: Arc<RwLock<Environment>> = Default::default();
let process_rw_lock = environment::process(Arc::clone(&environment_rw_lock));
let mut process = process_rw_lock.write().unwrap();
let reason = Term::EMPTY_LIST;
let arguments = Term::EMPTY_LIST;

assert_error!(
erlang::error_with_arguments(reason, arguments),
reason,
arguments,
&mut process
);
}

#[test]
fn with_list_returns_error_with_list_reason() {
let environment_rw_lock: Arc<RwLock<Environment>> = Default::default();
let process_rw_lock = environment::process(Arc::clone(&environment_rw_lock));
let mut process = process_rw_lock.write().unwrap();
let reason = list_term(&mut process);
let arguments = Term::cons(list_term(&mut process), Term::EMPTY_LIST, &mut process);

assert_error!(
erlang::error_with_arguments(reason, arguments),
reason,
arguments,
&mut process
);
}

#[test]
fn with_small_integer_returns_error_with_small_integer_reason() {
let environment_rw_lock: Arc<RwLock<Environment>> = Default::default();
let process_rw_lock = environment::process(Arc::clone(&environment_rw_lock));
let mut process = process_rw_lock.write().unwrap();
let reason = 0usize.into_process(&mut process);
let arguments = Term::cons(1.into_process(&mut process), Term::EMPTY_LIST, &mut process);

assert_error!(
erlang::error_with_arguments(reason, arguments),
reason,
arguments,
&mut process
);
}

#[test]
fn with_big_integer_returns_error_with_big_integer_reason() {
let environment_rw_lock: Arc<RwLock<Environment>> = Default::default();
let process_rw_lock = environment::process(Arc::clone(&environment_rw_lock));
let mut process = process_rw_lock.write().unwrap();
let reason = <BigInt as Num>::from_str_radix("576460752303423489", 10)
.unwrap()
.into_process(&mut process);
let arguments = Term::cons(
<BigInt as Num>::from_str_radix("576460752303423490", 10)
.unwrap()
.into_process(&mut process),
Term::EMPTY_LIST,
&mut process,
);

assert_error!(
erlang::error_with_arguments(reason, arguments),
reason,
arguments,
&mut process
);
}

#[test]
fn with_float_returns_error_with_float_reason() {
let environment_rw_lock: Arc<RwLock<Environment>> = Default::default();
let process_rw_lock = environment::process(Arc::clone(&environment_rw_lock));
let mut process = process_rw_lock.write().unwrap();
let reason = 1.0.into_process(&mut process);
let arguments = Term::cons(
2.0.into_process(&mut process),
Term::EMPTY_LIST,
&mut process,
);

assert_error!(
erlang::error_with_arguments(reason, arguments),
reason,
arguments,
&mut process
);
}

#[test]
fn with_local_pid_returns_error_with_local_pid_reason() {
let environment_rw_lock: Arc<RwLock<Environment>> = Default::default();
let process_rw_lock = environment::process(Arc::clone(&environment_rw_lock));
let mut process = process_rw_lock.write().unwrap();
let reason = Term::local_pid(0, 0, &mut process).unwrap();
let arguments = Term::cons(
Term::local_pid(1, 2, &mut process).unwrap(),
Term::EMPTY_LIST,
&mut process,
);

assert_error!(
erlang::error_with_arguments(reason, arguments),
reason,
arguments,
&mut process
);
}

#[test]
fn with_external_pid_returns_error_with_external_pid_reason() {
let environment_rw_lock: Arc<RwLock<Environment>> = Default::default();
let process_rw_lock = environment::process(Arc::clone(&environment_rw_lock));
let mut process = process_rw_lock.write().unwrap();
let reason = Term::external_pid(1, 0, 0, &mut process).unwrap();
let arguments = Term::cons(
Term::external_pid(2, 3, 4, &mut process).unwrap(),
Term::EMPTY_LIST,
&mut process,
);

assert_error!(
erlang::error_with_arguments(reason, arguments),
reason,
arguments,
&mut process
);
}

#[test]
fn with_tuple_returns_error_with_tuple_reason() {
let environment_rw_lock: Arc<RwLock<Environment>> = Default::default();
let process_rw_lock = environment::process(Arc::clone(&environment_rw_lock));
let mut process = process_rw_lock.write().unwrap();
let reason = Term::slice_to_tuple(&[], &mut process);
let arguments = Term::cons(
Term::slice_to_tuple(&[1.into_process(&mut process)], &mut process),
Term::EMPTY_LIST,
&mut process,
);

assert_error!(
erlang::error_with_arguments(reason, arguments),
reason,
arguments,
&mut process
);
}

#[test]
fn with_map_returns_error_with_map_reason() {
let environment_rw_lock: Arc<RwLock<Environment>> = Default::default();
let process_rw_lock = environment::process(Arc::clone(&environment_rw_lock));
let mut process = process_rw_lock.write().unwrap();
let reason = Term::slice_to_map(
&[(
Term::str_to_atom("a", DoNotCare, &mut process).unwrap(),
1.into_process(&mut process),
)],
&mut process,
);
let arguments = Term::cons(
Term::slice_to_map(
&[(
Term::str_to_atom("b", DoNotCare, &mut process).unwrap(),
2.into_process(&mut process),
)],
&mut process,
),
Term::EMPTY_LIST,
&mut process,
);

assert_error!(
erlang::error_with_arguments(reason, arguments),
reason,
arguments,
&mut process
);
}

#[test]
fn with_heap_binary_returns_error_with_heap_binary_reason() {
let environment_rw_lock: Arc<RwLock<Environment>> = Default::default();
let process_rw_lock = environment::process(Arc::clone(&environment_rw_lock));
let mut process = process_rw_lock.write().unwrap();
let reason = Term::slice_to_binary(&[0], &mut process);
let arguments = Term::cons(
Term::slice_to_binary(&[1], &mut process),
Term::EMPTY_LIST,
&mut process,
);

assert_error!(
erlang::error_with_arguments(reason, arguments),
reason,
arguments,
&mut process
);
}

#[test]
fn with_subbinary_returns_error_with_subbinary_reason() {
let environment_rw_lock: Arc<RwLock<Environment>> = Default::default();
let process_rw_lock = environment::process(Arc::clone(&environment_rw_lock));
let mut process = process_rw_lock.write().unwrap();

// <<1::1, 2>>
let reason_original = Term::slice_to_binary(&[129, 0b0000_0000], &mut process);
let reason = Term::subbinary(reason_original, 0, 1, 1, 0, &mut process);

// <<3::3, 4>>
let argument_original = Term::slice_to_binary(&[96, 0b0100_0000], &mut process);
let argument = Term::subbinary(argument_original, 0, 2, 1, 0, &mut process);
let arguments = Term::cons(argument, Term::EMPTY_LIST, &mut process);

assert_error!(
erlang::error_with_arguments(reason, arguments),
reason,
arguments,
&mut process
);
}
6 changes: 3 additions & 3 deletions lumen_runtime/src/process.rs
Expand Up @@ -152,9 +152,9 @@ impl DebugInProcess for exception::Result {
fn format_in_process(&self, process: &Process) -> String {
match self {
Ok(term) => format!("Ok({})", term.format_in_process(process)),
Err(Exception { class, reason, file, line, column }) => format!(
"Err(BadArgument {{ class: {:?}, reason: {}, file: {:?}, line: {:?}, column: {:?} }})",
class, reason.format_in_process(&process), file, line, column
Err(Exception { class, reason, arguments, file, line, column }) => format!(
"Err(Exception {{ class: {:?}, reason: {}, arguments: {}, file: {:?}, line: {:?}, column: {:?} }})",
class, arguments.format_in_process(&process), reason.format_in_process(&process), file, line, column
),
}
}
Expand Down

0 comments on commit 1f470a5

Please sign in to comment.