Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 3 additions & 6 deletions rust_src/remacs-sys/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1103,8 +1103,10 @@ pub struct emacs_globals {
extern "C" {
pub static mut globals: emacs_globals;
pub static Qt: Lisp_Object;
pub static Qerror: Lisp_Object;
pub static Qarith_error: Lisp_Object;
pub static Qrange_error: Lisp_Object;
pub static Qwrong_type_argument: Lisp_Object;
pub static Qnumber_or_marker_p: Lisp_Object;
pub static Qinteger_or_marker_p: Lisp_Object;
pub static Qconsp: Lisp_Object;
Expand Down Expand Up @@ -1154,6 +1156,7 @@ extern "C" {
pub fn Fcons(car: Lisp_Object, cdr: Lisp_Object) -> Lisp_Object;
pub fn Fcurrent_buffer() -> Lisp_Object;
pub fn Fsignal(error_symbol: Lisp_Object, data: Lisp_Object) -> !;
pub fn Ffuncall(nargs: ptrdiff_t, args: *mut Lisp_Object) -> Lisp_Object;

pub fn make_float(float_value: c_double) -> Lisp_Object;
pub fn make_string(s: *const c_char, length: ptrdiff_t) -> Lisp_Object;
Expand All @@ -1174,15 +1177,9 @@ extern "C" {
depth: c_int,
ht: Lisp_Object,
) -> bool;
pub fn call2(fn_: Lisp_Object, arg1: Lisp_Object, arg2: Lisp_Object) -> Lisp_Object;

// These signal an error, therefore are marked as non-returning.
pub fn circular_list(tail: Lisp_Object) -> !;
pub fn wrong_type_argument(predicate: Lisp_Object, value: Lisp_Object) -> !;
// defined in eval.c, where it can actually take an arbitrary
// number of arguments.
// TODO: define a Rust version of this that uses Rust strings.
pub fn error(m: *const u8, ...) -> !;
pub fn nsberror(spec: Lisp_Object) -> !;

pub fn emacs_abort() -> !;
Expand Down
54 changes: 25 additions & 29 deletions rust_src/src/base64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use base64_crate;
use lisp::LispObject;
use strings::MIME_LINE_LENGTH;
use multibyte::{MAX_5_BYTE_CHAR, multibyte_char_at, raw_byte_from_codepoint};
use remacs_sys::{error, make_unibyte_string};
use remacs_sys::make_unibyte_string;
use remacs_macros::lisp_fn;

#[no_mangle]
Expand Down Expand Up @@ -151,26 +151,24 @@ fn base64_encode_string(string: LispObject, no_line_break: LispObject) -> LispOb
// This function uses SAFE_ALLOCA in the c layer, however I cannot find an equivalent
// for rust. Instead, we will use a Vec to store the temporary char buffer.
let mut buffer: Vec<c_char> = Vec::with_capacity(allength as usize);
unsafe {
let encoded = buffer.as_mut_ptr();
let encoded_length = base64_encode_1(
string.sdata_ptr(),
encoded,
length,
no_line_break.is_nil(),
string.is_multibyte(),
);

if encoded_length > allength {
panic!("base64 encoded length is larger then allocated buffer");
}
let encoded = buffer.as_mut_ptr();
let encoded_length = base64_encode_1(
string.sdata_ptr(),
encoded,
length,
no_line_break.is_nil(),
string.is_multibyte(),
);

if encoded_length < 0 {
error("Multibyte character in data for base64 encoding\0".as_ptr());
}
if encoded_length > allength {
panic!("base64 encoded length is larger then allocated buffer");
}

LispObject::from_raw(make_unibyte_string(encoded, encoded_length))
if encoded_length < 0 {
error!("Multibyte character in data for base64 encoding");
}

unsafe { LispObject::from_raw(make_unibyte_string(encoded, encoded_length)) }
}

/// Base64-decode STRING and return the result.
Expand All @@ -181,16 +179,14 @@ fn base64_decode_string(string: LispObject) -> LispObject {
let length = string.len_bytes();
let mut buffer: Vec<c_char> = Vec::with_capacity(length as usize);

unsafe {
let decoded = buffer.as_mut_ptr();
let decoded_length =
base64_decode_1(string.sdata_ptr(), decoded, length, false, ptr::null_mut());

if decoded_length > length {
panic!("Decoded length is above length");
} else if decoded_length < 0 {
error("Invalid base64 data\0".as_ptr());
}
LispObject::from_raw(make_unibyte_string(decoded, decoded_length))
let decoded = buffer.as_mut_ptr();
let decoded_length =
base64_decode_1(string.sdata_ptr(), decoded, length, false, ptr::null_mut());

if decoded_length > length {
panic!("Decoded length is above length");
} else if decoded_length < 0 {
error!("Invalid base64 data");
}
unsafe { LispObject::from_raw(make_unibyte_string(decoded, decoded_length)) }
}
6 changes: 2 additions & 4 deletions rust_src/src/character.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use lisp::LispObject;
use multibyte::{MAX_CHAR, make_char_multibyte, raw_byte_from_codepoint_safe};
use remacs_macros::lisp_fn;
use remacs_sys::{EmacsInt, error};
use remacs_sys::EmacsInt;

/// Return the character of the maximum code.
#[lisp_fn]
Expand Down Expand Up @@ -32,9 +32,7 @@ fn char_or_string_p(object: LispObject) -> LispObject {
fn unibyte_char_to_multibyte(ch: LispObject) -> LispObject {
let c = ch.as_character_or_error();
if c >= 0x100 {
unsafe {
error("Not a unibyte character: %d\0".as_ptr(), c);
}
error!("Not a unibyte character: {}", c);
}
LispObject::from_fixnum(make_char_multibyte(c) as EmacsInt)
}
Expand Down
85 changes: 67 additions & 18 deletions rust_src/src/eval.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,77 @@
//! Generic Lisp eval functions.
//! Generic Lisp eval functions and macros.

use lisp::LispObject;
use remacs_sys::Fsignal;

/// Signal an error in Emacs.
/// Macro to generate an error with a list from any number of arguments.
/// Replaces xsignal0, etc. in the C layer.
///
/// Like `Fsignal`, but never returns. Can be used for any error
/// except `Qquit`, which can return from `Fsignal`. See the elisp docstring
/// for `signal` for an explanation of the arguments.
fn xsignal(error_symbol: LispObject, data: LispObject) -> ! {
unsafe {
Fsignal(error_symbol.to_raw(), data.to_raw());
}
macro_rules! xsignal {
($symbol:expr) => {{
unsafe {
::remacs_sys::Fsignal($symbol, ::remacs_sys::Qnil);
}
}};
($symbol:expr, $arg:expr) => {{
let list = $crate::lisp::LispObject::cons($arg, $crate::lisp::LispObject::constant_nil());
unsafe {
::remacs_sys::Fsignal($symbol, list.to_raw());
}
}};
($symbol:expr, $arg1:expr, $arg2:expr) => {{
let list = $crate::lisp::LispObject::cons(
$arg1,
$crate::lisp::LispObject::cons($arg2, $crate::lisp::LispObject::constant_nil())
);
unsafe {
::remacs_sys::Fsignal($symbol, list.to_raw());
}
}};
($symbol:expr, $($arg:expr),*) => {{
let mut argsarray = [$($arg),*];
unsafe {
::remacs_sys::Fsignal($symbol,
$crate::lists::list(&mut argsarray[..]).to_raw());
}
}}
}

/// Macro to call Lisp functions with any number of arguments.
/// Replaces CALLN, call1, etc. in the C layer.
macro_rules! call {
($func:expr, $($arg:expr),*) => {{
let mut argsarray = [$func.to_raw(), $($arg.to_raw()),*];
unsafe {
LispObject::from_raw(
::remacs_sys::Ffuncall(argsarray.len() as ::libc::ptrdiff_t, argsarray.as_mut_ptr())
)
}
}}
}

/// Convenience function for calling `xsignal` with an empty list.
pub fn xsignal0(error_symbol: LispObject) -> ! {
xsignal(error_symbol, LispObject::constant_nil());
/// Macro to format an error message.
/// Replaces error() in the C layer.
macro_rules! error {
($str:expr) => {{
let strobj = unsafe {
::remacs_sys::make_string($str.as_ptr() as *const i8,
$str.len() as ::libc::ptrdiff_t)
};
xsignal!(::remacs_sys::Qerror, $crate::lisp::LispObject::from_raw(strobj));
}};
($fmtstr:expr, $($arg:expr),*) => {{
let formatted = format!($fmtstr, $($arg),*);
let strobj = unsafe {
::remacs_sys::make_string(formatted.as_ptr() as *const i8,
formatted.len() as ::libc::ptrdiff_t)
};
xsignal!(::remacs_sys::Qerror, $crate::lisp::LispObject::from_raw(strobj));
}}
}

/// Convenience function for calling `xsignal` with a two-element list.
pub fn xsignal2(error_symbol: LispObject, arg1: LispObject, arg2: LispObject) -> ! {
xsignal(
error_symbol,
LispObject::cons(arg1, LispObject::cons(arg2, LispObject::constant_nil())),
)
/// Macro to format a "wrong argument type" error message.
macro_rules! wrong_type {
($pred:expr, $arg:expr) => {{
xsignal!(::remacs_sys::Qwrong_type_argument, LispObject::from_raw(unsafe { $pred }), $arg);
}}
}
29 changes: 11 additions & 18 deletions rust_src/src/floatfns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,11 @@
use std::mem;
use libc;

use eval::{xsignal0, xsignal2};
use math::ArithOp;
use lisp::{LispObject, LispNumber};
use remacs_sys::{EmacsDouble, EmacsInt, EmacsUint, Lisp_Object, Qnumberp, Qinteger_or_marker_p,
Qarith_error, Qrange_error, wrong_type_argument, build_string,
MOST_NEGATIVE_FIXNUM, MOST_POSITIVE_FIXNUM};
Qarith_error, Qrange_error, build_string, MOST_NEGATIVE_FIXNUM,
MOST_POSITIVE_FIXNUM};
use remacs_sys::libm;
use remacs_macros::lisp_fn;

Expand Down Expand Up @@ -86,14 +85,14 @@ pub fn float_arith_driver(
accum = next;
} else {
if next == 0. {
xsignal0(LispObject::from_raw(unsafe { Qarith_error }));
xsignal!(Qarith_error);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lovely! :)

}
accum /= next;
}
}
ArithOp::Logand | ArithOp::Logior | ArithOp::Logxor => unsafe {
wrong_type_argument(Qinteger_or_marker_p, val.to_raw())
},
ArithOp::Logand | ArithOp::Logior | ArithOp::Logxor => {
wrong_type!(Qinteger_or_marker_p, val)
}
}
}
LispObject::from_float(accum)
Expand Down Expand Up @@ -181,9 +180,7 @@ fn float(arg: LispObject) -> LispObject {
} else if let Some(n) = arg.as_fixnum() {
LispObject::from_float(n as EmacsDouble)
} else {
unsafe {
wrong_type_argument(Qnumberp, arg.to_raw());
}
wrong_type!(Qnumberp, arg);
}
}

Expand Down Expand Up @@ -263,9 +260,7 @@ fn logb(arg: LispObject) -> LispObject {
MOST_POSITIVE_FIXNUM
}
} else {
unsafe {
wrong_type_argument(Qnumberp, arg.to_raw());
}
wrong_type!(Qnumberp, arg)
};
LispObject::from_fixnum(res)
}
Expand Down Expand Up @@ -330,14 +325,12 @@ where
} else if let Some(f) = arg.as_float() {
d = f;
} else {
unsafe {
wrong_type_argument(Qnumberp, arg.to_raw());
}
wrong_type!(Qnumberp, arg)
}
} else {
if let (Some(arg), Some(div)) = (arg.as_fixnum(), divisor.as_fixnum()) {
if div == 0 {
xsignal0(LispObject::from_raw(unsafe { Qarith_error }));
xsignal!(Qarith_error);
}
return LispObject::from_fixnum(int_round2(arg, div));
}
Expand All @@ -360,7 +353,7 @@ where
let errstr = LispObject::from_raw(unsafe {
build_string(name.as_ptr() as *const libc::c_char)
});
xsignal2(LispObject::from_raw(unsafe { Qrange_error }), errstr, arg)
xsignal!(Qrange_error, errstr, arg)
}

fn ceiling2(i1: EmacsInt, i2: EmacsInt) -> EmacsInt {
Expand Down
3 changes: 2 additions & 1 deletion rust_src/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@ extern crate sha1;
extern crate sha2;
extern crate base64 as base64_crate;

#[macro_use]
mod eval;
mod lisp;
mod lists;
mod marker;
mod eval;
mod floatfns;
mod math;
mod numbers;
Expand Down
Loading