use std::cell::Cell;
use std::ffi::*;
use std::fmt;
use std::mem;
use std::ops::Drop;
use std::ptr;
use super::*;
use exprtk_sys::*;
use libc::{c_char, c_double, c_void, size_t};
unsafe impl Send for Expression {}
unsafe impl Sync for Expression {}
unsafe impl Send for SymbolTable {}
unsafe impl Sync for SymbolTable {}
unsafe impl Send for StringValue {}
unsafe impl Sync for StringValue {}
fn c_string(s: &str) -> Result<CString, InvalidName> {
CString::new(s).map_err(|_| InvalidName(s.to_string()))
}
#[derive(Debug)]
struct Parser(*mut CParser);
impl Parser {
pub fn new() -> Parser {
unsafe { Parser(parser_new()) }
}
fn formula_to_cstring(s: &str) -> Result<CString, ParseError> {
c_string(s).map_err(From::from)
}
pub fn compile(&self, string: &str, expr: &Expression) -> Result<(), ParseError> {
let formula = Self::formula_to_cstring(string)?;
unsafe {
if !parser_compile(self.0, formula.as_ptr(), expr.expr) {
return Err(self.get_err());
}
}
Ok(())
}
pub fn compile_resolve<F, S>(
&self,
string: &str,
expr: &mut Expression,
mut func: F,
) -> Result<(), ParseError>
where
F: FnMut(&str, &mut SymbolTable) -> Result<(), S>,
S: AsRef<str>,
{
let formula = Self::formula_to_cstring(string)?;
let expr_ptr = expr.expr;
let symbols = expr.symbols_mut();
let mut user_data = (symbols, &mut func);
unsafe {
let r = parser_compile_resolve(
self.0,
formula.as_ptr(),
expr_ptr,
wrapper::<F, S>,
&mut user_data as *const _ as *mut c_void,
);
if !r {
return Err(self.get_err());
}
};
extern "C" fn wrapper<F, S>(c_name: *const c_char, user_data: *mut c_void) -> *const c_char
where
F: FnMut(&str, &mut SymbolTable) -> Result<(), S>,
S: AsRef<str>,
{
let (ref mut symbols, ref mut opt_f) =
unsafe { &mut *(user_data as *mut (&mut SymbolTable, Option<&mut F>)) };
let name = unsafe { CStr::from_ptr(c_name).to_str().unwrap() };
opt_f
.as_mut()
.map(|ref mut f| {
if let Err(e) = f(name, symbols) {
return CString::new(e.as_ref()).unwrap().into_raw() as *const c_char;
}
ptr::null() as *const c_char
})
.unwrap()
}
Ok(())
}
fn get_err(&self) -> ParseError {
unsafe { ParseError::from_c_err(self.0) }
.expect("Compiler notified about error, but there is none.")
}
}
impl Drop for Parser {
fn drop(&mut self) {
unsafe { parser_destroy(self.0) };
}
}
pub struct Expression {
expr: *mut CExpression,
string: String,
symbols: SymbolTable,
}
impl Expression {
pub fn new(string: &str, symbols: SymbolTable) -> Result<Expression, ParseError> {
let parser = Parser::new();
let e = Expression {
expr: unsafe { expression_new() },
string: string.to_string(),
symbols,
};
e.register_symbol_table();
parser.compile(string, &e)?;
Ok(e)
}
pub fn parse_vars(
string: &str,
symbols: SymbolTable,
) -> Result<(Expression, Vec<(String, usize)>), ParseError> {
let mut vars = vec![];
let e = Expression::handle_unknown(string, symbols, |name, symbols| {
let var_id = symbols
.add_variable(name, 0.)
.map_err(|_| "invalid name.")?
.unwrap();
vars.push((name.to_string(), var_id));
Ok(())
})?;
Ok((e, vars))
}
pub fn handle_unknown<F>(
string: &str,
symbols: SymbolTable,
func: F,
) -> Result<Expression, ParseError>
where
F: FnMut(&str, &mut SymbolTable) -> Result<(), String>,
{
let parser = Parser::new();
let mut e = Expression {
expr: unsafe { expression_new() },
string: string.to_string(),
symbols,
};
e.register_symbol_table();
parser.compile_resolve(string, &mut e, func)?;
Ok(e)
}
fn register_symbol_table(&self) {
unsafe {
expression_register_symbol_table(self.expr, self.symbols.sym);
}
}
pub fn value(&mut self) -> c_double {
unsafe { expression_value(self.expr) }
}
#[inline]
pub fn symbols(&self) -> &SymbolTable {
&self.symbols
}
#[inline]
pub fn symbols_mut(&mut self) -> &mut SymbolTable {
&mut self.symbols
}
}
impl Drop for Expression {
fn drop(&mut self) {
unsafe { expression_destroy(self.expr) };
}
}
impl fmt::Debug for Expression {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"Expression {{ string: {}, symbols: {:?} }}",
self.string, self.symbols
)
}
}
impl Clone for Expression {
fn clone(&self) -> Expression {
Expression::new(&self.string, self.symbols.clone()).unwrap()
}
}
struct FuncData {
name: String,
cpp_func: *mut c_void,
rust_closure: *mut c_void,
clone_func: fn(&str, *mut c_void, &mut SymbolTable) -> Result<bool, InvalidName>,
free_cpp_func: unsafe extern "C" fn(*mut c_void),
free_closure_func: fn(*mut c_void),
}
pub struct SymbolTable {
sym: *mut CSymbolTable,
values: Vec<*mut c_double>,
strings: Vec<StringValue>,
vectors: Vec<Box<[c_double]>>,
funcs: Vec<FuncData>,
}
impl SymbolTable {
pub fn new() -> SymbolTable {
SymbolTable {
sym: unsafe { symbol_table_new() },
values: vec![],
strings: vec![],
vectors: vec![],
funcs: vec![],
}
}
pub fn add_constant(&mut self, name: &str, value: c_double) -> Result<bool, InvalidName> {
let c_name = c_string(name)?;
let rv = unsafe { symbol_table_add_constant(self.sym, c_name.as_ptr(), value) };
let added = self.validate_added(name, rv, ())?;
Ok(added.is_some())
}
pub fn add_variable(
&mut self,
name: &str,
value: c_double,
) -> Result<Option<usize>, InvalidName> {
let var_id = self.values.len();
let c_name = c_string(name)?;
let rv =
unsafe { symbol_table_create_variable(self.sym, c_name.as_ptr(), value as c_double) };
let res = self.validate_added(name, rv, var_id)?;
let ptr = unsafe { symbol_table_variable_ref(self.sym, c_name.as_ptr()) };
self.values.push(ptr);
Ok(res)
}
#[allow(clippy::mut_from_ref)]
#[inline]
unsafe fn _value_mut(&self, var_id: usize) -> &mut c_double {
let ptr = self.values.get(var_id).expect("Invalid variable ID");
ptr.as_mut().expect("null pointer!")
}
#[inline]
pub fn value(&self, var_id: usize) -> c_double {
unsafe { *self._value_mut(var_id) }
}
#[inline]
pub fn value_mut(&mut self, var_id: usize) -> &mut c_double {
unsafe { self._value_mut(var_id) }
}
#[inline]
pub fn value_cell(&self, var_id: usize) -> &Cell<c_double> {
let mut_ref = unsafe { self._value_mut(var_id) };
Cell::from_mut(mut_ref)
}
#[inline]
pub fn value_from_name(&self, name: &str) -> Result<c_double, InvalidName> {
let c_name = c_string(name)?;
let var_ref = unsafe {
symbol_table_variable_ref(self.sym, c_name.as_ptr())
.as_ref()
.cloned()
};
Ok(var_ref.expect("Unknown variable name"))
}
pub fn add_stringvar(&mut self, name: &str, text: &str) -> Result<Option<usize>, InvalidName> {
let i = self.strings.len();
let s = StringValue::new(text);
self.strings.push(s);
let c_name = c_string(name)?;
let rv = unsafe {
symbol_table_add_stringvar(self.sym, c_name.as_ptr(), self.strings[i].0, false)
};
let res = self.validate_added(name, rv, i);
if res.is_err() {
self.strings.pop();
}
res
}
#[inline]
pub fn set_string(&mut self, var_id: usize, text: &str) -> bool {
if let Some(s) = self.strings.get_mut(var_id) {
s.set(text);
return true;
}
false
}
#[inline]
pub fn string(&self, var_id: usize) -> &StringValue {
self.strings.get(var_id).expect("Invalid variable ID")
}
#[inline]
pub fn string_mut(&mut self, var_id: usize) -> &mut StringValue {
self.strings.get_mut(var_id).expect("Invalid variable ID")
}
pub fn add_vector(
&mut self,
name: &str,
vec: &[c_double],
) -> Result<Option<usize>, InvalidName> {
let i = self.vectors.len();
let l = vec.len();
self.vectors.push(vec.to_vec().into_boxed_slice());
let c_name = c_string(name)?;
let rv = unsafe {
symbol_table_add_vector(self.sym, c_name.as_ptr(), self.vectors[i].as_ptr(), l)
};
let res = self.validate_added(name, rv, i);
if res.is_err() {
self.vectors.pop();
}
res
}
#[inline]
pub fn vector(&self, var_id: usize) -> &[c_double] {
&**self.vectors.get(var_id).expect("Invalid variable ID")
}
#[inline]
pub fn vector_mut(&mut self, var_id: usize) -> &mut [c_double] {
&mut **self.vectors.get_mut(var_id).expect("Invalid variable ID")
}
#[inline]
pub fn vector_of_cells(&self, var_id: usize) -> &[Cell<c_double>] {
let v = self.vector(var_id);
unsafe {
let cell_slice = &*(v as *const [c_double] as *const Cell<[c_double]>);
cell_slice.as_slice_of_cells()
}
}
fn validate_added<O>(
&self,
name: &str,
result: bool,
out: O,
) -> Result<Option<O>, InvalidName> {
if !result {
let valid = unsafe { symbol_table_valid(self.sym) };
if !valid {
panic!("Bug: SymbolTable state invalid!");
}
if !self.symbol_exists(name).unwrap() {
return Err(InvalidName(name.to_string()));
}
assert_eq!(self.symbol_exists(name), Ok(true));
return Ok(None);
}
Ok(Some(out))
}
fn get_var_ptr_from_name(&self, name: &str) -> Result<Option<*mut c_double>, InvalidName> {
let c_name = c_string(name)?;
let rv = unsafe { symbol_table_variable_ref(self.sym, c_name.as_ptr()) };
let rv = if rv.is_null() { None } else { Some(rv) };
Ok(rv)
}
pub fn get_var_id(&self, name: &str) -> Result<Option<usize>, InvalidName> {
self.get_var_ptr_from_name(name)
.map(|opt_ptr| opt_ptr.and_then(|ptr| self.values.iter().position(|&p| p == ptr)))
}
pub fn get_string_id(&self, name: &str) -> Result<Option<usize>, InvalidName> {
let c_name = c_string(name)?;
let ptr = unsafe { symbol_table_stringvar_ref(self.sym, c_name.as_ptr()) };
let rv = if ptr.is_null() {
None
} else {
self.strings.iter().position(|s| s.0 == ptr)
};
Ok(rv)
}
pub fn get_vec_id(&self, name: &str) -> Result<Option<usize>, InvalidName> {
let c_name = c_string(name)?;
let ptr = unsafe { symbol_table_vector_ptr(self.sym, c_name.as_ptr()) };
let rv = if ptr.is_null() {
None
} else {
self.vectors.iter().position(|v| v.as_ptr() == ptr)
};
Ok(rv)
}
pub fn clear_variables(&mut self) {
self.values.clear();
unsafe { symbol_table_clear_variables(self.sym) }
}
pub fn clear_strings(&mut self) {
self.strings.clear();
unsafe { symbol_table_clear_strings(self.sym) }
}
pub fn clear_vectors(&mut self) {
self.vectors.clear();
unsafe { symbol_table_clear_vectors(self.sym) }
}
pub fn clear_local_constants(&mut self) {
unsafe { symbol_table_clear_local_constants(self.sym) }
}
pub fn clear_functions(&mut self) {
unsafe { symbol_table_clear_functions(self.sym) }
}
pub fn variable_count(&self) -> usize {
unsafe { symbol_table_variable_count(self.sym) as usize }
}
pub fn stringvar_count(&self) -> usize {
unsafe { symbol_table_stringvar_count(self.sym) as usize }
}
pub fn vector_count(&self) -> usize {
unsafe { symbol_table_vector_count(self.sym) as usize }
}
pub fn function_count(&self) -> usize {
unsafe { symbol_table_function_count(self.sym) as usize }
}
pub fn add_constants(&mut self) -> bool {
unsafe { symbol_table_add_constants(self.sym) }
}
pub fn add_pi(&mut self) -> bool {
unsafe { symbol_table_add_pi(self.sym) }
}
pub fn add_epsilon(&mut self) -> bool {
unsafe { symbol_table_add_epsilon(self.sym) }
}
pub fn add_infinity(&mut self) -> bool {
unsafe { symbol_table_add_infinity(self.sym) }
}
pub fn get_variable_names(&self) -> Vec<String> {
unsafe {
let l = symbol_table_get_variable_list(self.sym);
let out = (*l)
.get_slice()
.iter()
.map(|s| string_from_ptr!(*s))
.collect();
string_array_free(l);
out
}
}
pub fn get_stringvar_names(&self) -> Vec<String> {
unsafe {
let l = symbol_table_get_stringvar_list(self.sym);
let out = (*l)
.get_slice()
.iter()
.map(|s| string_from_ptr!(*s))
.collect();
string_array_free(l);
out
}
}
pub fn get_vector_names(&self) -> Vec<String> {
unsafe {
let l = symbol_table_get_vector_list(self.sym);
let out = (*l)
.get_slice()
.iter()
.map(|s| string_from_ptr!(*s))
.collect();
string_array_free(l);
out
}
}
pub fn symbol_exists(&self, name: &str) -> Result<bool, InvalidName> {
let c_name = c_string(name)?;
let rv = unsafe { symbol_table_symbol_exists(self.sym, c_name.as_ptr()) };
Ok(rv)
}
pub fn is_constant_node(&self, name: &str) -> Result<bool, InvalidName> {
let c_name = c_string(name)?;
let rv = unsafe { symbol_table_is_constant_node(self.sym, c_name.as_ptr()) };
Ok(rv)
}
pub fn is_constant_string(&self, name: &str) -> Result<bool, InvalidName> {
let c_name = c_string(name)?;
let rv = unsafe { symbol_table_is_constant_string(self.sym, c_name.as_ptr()) };
Ok(rv)
}
}
macro_rules! func_impl {
($name:ident, $n:expr, $sys_func:ident, $clone_func:ident, $free_closure:ident, $free_cpp_func:ident,
$($x:ident: $ty:ty),*) => {
impl SymbolTable {
#[doc = $n]
pub fn $name<F>(&mut self, name: &str, func: F) -> Result<bool, InvalidName>
where F: Fn($($ty),*) -> c_double + Clone
{
extern fn wrapper<F>(closure: *mut c_void, $($x: $ty),*) -> c_double
where F: Fn($($ty),*) -> c_double {
unsafe {
let opt_closure: Option<Box<F>> = mem::transmute(closure);
opt_closure.map(|f| f($($x),*)).unwrap()
}
}
let func_box = Box::new(func);
let func_ptr = Box::into_raw(func_box) as *mut _ as *mut c_void;
let c_name = c_string(name)?;
let result = unsafe {
$sys_func(self.sym, c_name.as_ptr(), wrapper::<F>, func_ptr)
};
let is_new = self.validate_added(name, result.0, ())?.is_some();
if is_new {
self.funcs.push(FuncData {
name: name.to_string(),
cpp_func: result.1,
rust_closure: func_ptr,
clone_func: $clone_func::<F>,
free_cpp_func: $free_cpp_func,
free_closure_func: $free_closure::<F>,
});
}
Ok(is_new)
}
}
fn $clone_func<F>(name: &str, closure_ptr: *mut c_void, new_symbols: &mut SymbolTable)
-> Result<bool, InvalidName>
where F: Fn($($ty),*) -> c_double + Clone
{
let mut opt_closure: Option<Box<F>> = unsafe { mem::transmute(closure_ptr) };
let res = new_symbols.$name(name, *opt_closure.as_mut().unwrap().clone());
mem::forget(opt_closure); res
}
fn $free_closure<F>(closure_ptr: *mut c_void)
where F: Fn($($ty),*) -> c_double + Clone
{
let _: Option<Box<F>> = unsafe { mem::transmute(closure_ptr) };
}
}
}
func_impl!(
add_func1,
"1",
symbol_table_add_func1,
clone_func1,
free_func_closure1,
symbol_table_free_func1,
a: c_double
);
func_impl!(
add_func2,
"2",
symbol_table_add_func2,
clone_func2,
free_func_closure2,
symbol_table_free_func2,
a: c_double,
b: c_double
);
func_impl!(
add_func3,
"3",
symbol_table_add_func3,
clone_func3,
free_func_closure3,
symbol_table_free_func3,
a: c_double,
b: c_double,
c: c_double
);
func_impl!(
add_func4,
"4",
symbol_table_add_func4,
clone_func4,
free_func_closure4,
symbol_table_free_func4,
a: c_double,
b: c_double,
c: c_double,
d: c_double
);
func_impl!(
add_func5,
"5",
symbol_table_add_func5,
clone_func5,
free_func_closure5,
symbol_table_free_func5,
a: c_double,
b: c_double,
c: c_double,
d: c_double,
e: c_double
);
func_impl!(
add_func6,
"6",
symbol_table_add_func6,
clone_func6,
free_func_closure6,
symbol_table_free_func6,
a: c_double,
b: c_double,
c: c_double,
d: c_double,
e: c_double,
f: c_double
);
func_impl!(
add_func7,
"7",
symbol_table_add_func7,
clone_func7,
free_func_closure7,
symbol_table_free_func7,
a: c_double,
b: c_double,
c: c_double,
d: c_double,
e: c_double,
f: c_double,
g: c_double
);
func_impl!(
add_func8,
"8",
symbol_table_add_func8,
clone_func8,
free_func_closure8,
symbol_table_free_func8,
a: c_double,
b: c_double,
c: c_double,
d: c_double,
e: c_double,
f: c_double,
g: c_double,
h: c_double
);
func_impl!(
add_func9,
"9",
symbol_table_add_func9,
clone_func9,
free_func_closure9,
symbol_table_free_func9,
a: c_double,
b: c_double,
c: c_double,
d: c_double,
e: c_double,
f: c_double,
g: c_double,
h: c_double,
i: c_double
);
func_impl!(
add_func10,
"10",
symbol_table_add_func10,
clone_func10,
free_func_closure10,
symbol_table_free_func10,
a: c_double,
b: c_double,
c: c_double,
d: c_double,
e: c_double,
f: c_double,
g: c_double,
h: c_double,
i: c_double,
j: c_double
);
impl Default for exprtk::SymbolTable {
fn default() -> Self {
Self::new()
}
}
impl Drop for SymbolTable {
fn drop(&mut self) {
for f in &self.funcs {
unsafe {
(f.free_cpp_func)(f.cpp_func);
(f.free_closure_func)(f.rust_closure);
}
}
unsafe { symbol_table_destroy(self.sym) };
}
}
impl fmt::Debug for SymbolTable {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let varnames = self.get_variable_names();
write!(f,
"SymbolTable {{ values: {}, constants: {}, strings: {}, vectors: {:?}, functions: {} }}",
format!("[{}]", varnames
.iter()
.filter(|n| !self.is_constant_node(n).unwrap())
.map(|n| format!("\"{}\": {}", n, self.value_from_name(n).unwrap()))
.collect::<Vec<_>>()
.join(", ")
),
format!("[{}]", varnames
.iter()
.filter(|n| self.is_constant_node(n).unwrap())
.map(|n| format!("\"{}\": {}", n, self.value_from_name(n).unwrap()))
.collect::<Vec<_>>()
.join(", ")
),
format!("[{}]", self.get_stringvar_names()
.iter()
.map(|n| format!("\"{}\": \"{}\"", n,
self.string(self.get_string_id(n).unwrap().unwrap()).get())
)
.collect::<Vec<_>>()
.join(", ")
),
format!("[{}]", self.get_vector_names()
.iter()
.map(|n| format!("\"{}\": {:?}", n, self.vector(self.get_vec_id(n).unwrap().unwrap())))
.collect::<Vec<_>>()
.join(", ")
),
format!("[{}]", self.funcs
.iter()
.map(|f| f.name.to_string())
.collect::<Vec<_>>()
.join(", ")
),
)
}
}
impl Clone for SymbolTable {
fn clone(&self) -> SymbolTable {
let mut s = Self::new();
for n in self.get_variable_names() {
let v = self.value_from_name(&n).unwrap();
if self.is_constant_node(&n).unwrap() {
s.add_constant(&n, v).unwrap();
} else {
s.add_variable(&n, v).unwrap();
}
}
for n in self.get_stringvar_names() {
let v = self.string(self.get_string_id(&n).unwrap().unwrap()).get();
s.add_stringvar(&n, &v).unwrap();
}
for n in self.get_vector_names() {
let v = self.vector(self.get_vec_id(&n).unwrap().unwrap());
s.add_vector(&n, v).unwrap();
}
for f in &self.funcs {
(f.clone_func)(&f.name, f.rust_closure, &mut s).unwrap();
}
s
}
}
pub struct StringValue(*mut CppString);
impl StringValue {
pub fn new(value: &str) -> StringValue {
let s =
unsafe { cpp_string_create(value.as_ptr() as *const c_char, value.len() as size_t) };
StringValue(s)
}
pub fn set(&mut self, value: &str) {
unsafe {
cpp_string_set(
self.0,
value.as_ptr() as *const c_char,
value.len() as size_t,
)
}
}
pub fn get(&self) -> &str {
unsafe { CStr::from_ptr(cpp_string_get(self.0)) }
.to_str()
.unwrap()
}
}
impl Drop for StringValue {
fn drop(&mut self) {
unsafe { cpp_string_free(self.0) };
}
}
impl fmt::Debug for StringValue {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "StringValue {{ {} }}", self.get())
}
}