New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add some macros for convenience and safety #266

Merged
merged 3 commits into from Jul 24, 2017
Jump to file or symbol
Failed to load files and symbols.
+158 −154
Diff settings

Always

Just for now

Copy path View file
@@ -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;
@@ -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;
@@ -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() -> !;
Copy path View file
@@ -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]
@@ -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.
@@ -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)) }
}
Copy path View file
@@ -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]
@@ -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)
}
Copy path View file
@@ -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);
}}
}
Copy path View file
@@ -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;
@@ -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);

This comment has been minimized.

@Wilfred

Wilfred Jul 23, 2017

Owner

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)
@@ -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);
}
}
@@ -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)
}
@@ -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));
}
@@ -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 {
Copy path View file
@@ -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;
Oops, something went wrong.
ProTip! Use n and p to navigate between commits in a pull request.