Skip to content
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

Faster lists #478

Merged
merged 2 commits into from
Jul 1, 2024
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
7 changes: 4 additions & 3 deletions numbat/src/ffi/currency.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
use super::macros::*;
use super::Args;
use super::Result;
use crate::currency::ExchangeRatesCache;
use crate::quantity::Quantity;
use crate::value::Value;

pub fn exchange_rate(args: &[Value]) -> Result<Value> {
let rate = string_arg!(args, 0);
pub fn exchange_rate(mut args: Args) -> Result<Value> {
let rate = string_arg!(args);

let exchange_rates = ExchangeRatesCache::new();

return_scalar!(exchange_rates.get_rate(rate).unwrap_or(f64::NAN))
return_scalar!(exchange_rates.get_rate(&rate).unwrap_or(f64::NAN))
}
31 changes: 16 additions & 15 deletions numbat/src/ffi/datetime.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use super::macros::*;
use super::Args;
use super::Result;
use crate::datetime;
use crate::quantity::Quantity;
Expand All @@ -8,56 +9,56 @@ use crate::RuntimeError;

use std::fmt::Write;

pub fn now(_args: &[Value]) -> Result<Value> {
pub fn now(_args: Args) -> Result<Value> {
let now = chrono::Local::now().fixed_offset();

return_datetime!(now)
}

pub fn datetime(args: &[Value]) -> Result<Value> {
let input = string_arg!(args, 0);
pub fn datetime(mut args: Args) -> Result<Value> {
let input = string_arg!(args);

let output = datetime::parse_datetime(input)
let output = datetime::parse_datetime(&input)
.ok_or(RuntimeError::DateParsingErrorUnknown)?
.fixed_offset();

return_datetime!(output)
}

pub fn format_datetime(args: &[Value]) -> Result<Value> {
let format = string_arg!(args, 0);
let dt = datetime_arg!(args, 1);
pub fn format_datetime(mut args: Args) -> Result<Value> {
let format = string_arg!(args);
let dt = datetime_arg!(args);

let mut output = String::new();
write!(output, "{}", dt.format(format)).map_err(|_| RuntimeError::DateFormattingError)?;
write!(output, "{}", dt.format(&format)).map_err(|_| RuntimeError::DateFormattingError)?;

return_string!(output)
}

pub fn get_local_timezone(_args: &[Value]) -> Result<Value> {
pub fn get_local_timezone(_args: Args) -> Result<Value> {
let local_tz = datetime::get_local_timezone_or_utc().to_string();

return_string!(local_tz)
}

pub fn tz(args: &[Value]) -> Result<Value> {
let tz = string_arg!(args, 0);
pub fn tz(mut args: Args) -> Result<Value> {
let tz = string_arg!(args);

Ok(Value::FunctionReference(FunctionReference::TzConversion(
tz.into(),
)))
}

pub fn unixtime(args: &[Value]) -> Result<Value> {
let input = datetime_arg!(args, 0);
pub fn unixtime(mut args: Args) -> Result<Value> {
let input = datetime_arg!(args);

let output = input.timestamp();

return_scalar!(output as f64)
}

pub fn from_unixtime(args: &[Value]) -> Result<Value> {
let timestamp = quantity_arg!(args, 0).unsafe_value().to_f64() as i64;
pub fn from_unixtime(mut args: Args) -> Result<Value> {
let timestamp = quantity_arg!(args).unsafe_value().to_f64() as i64;

let dt = chrono::DateTime::from_timestamp(timestamp, 0)
.ok_or(RuntimeError::DateTimeOutOfRange)?
Expand Down
12 changes: 7 additions & 5 deletions numbat/src/ffi/functions.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::collections::HashMap;
use std::sync::OnceLock;

use super::macros::*;
use super::{macros::*, Args};
use crate::{quantity::Quantity, value::Value, RuntimeError};

use super::{Callable, ForeignFunction, Result};
Expand Down Expand Up @@ -103,11 +103,13 @@ pub(crate) fn functions() -> &'static HashMap<String, ForeignFunction> {
})
}

fn error(args: &[Value]) -> Result<Value> {
Err(RuntimeError::UserError(args[0].unsafe_as_string().into()))
fn error(mut args: Args) -> Result<Value> {
Err(RuntimeError::UserError(
arg!(args).unsafe_as_string().into(),
))
}

fn unit_of(args: &[Value]) -> Result<Value> {
let input_unit = quantity_arg!(args, 0).unit().clone();
fn unit_of(mut args: Args) -> Result<Value> {
let input_unit = quantity_arg!(args).unit().clone();
return_quantity!(1.0, input_unit)
}
33 changes: 16 additions & 17 deletions numbat/src/ffi/lists.rs
Original file line number Diff line number Diff line change
@@ -1,40 +1,39 @@
use super::macros::*;
use super::Result;
use super::{Args, Result};
use crate::quantity::Quantity;
use crate::value::Value;
use crate::RuntimeError;

pub fn len(args: &[Value]) -> Result<Value> {
let list = list_arg!(args, 0);
pub fn len(mut args: Args) -> Result<Value> {
let list = list_arg!(args);

return_scalar!(list.len() as f64)
}

pub fn head(args: &[Value]) -> Result<Value> {
let list = list_arg!(args, 0);
pub fn head(mut args: Args) -> Result<Value> {
let mut list = list_arg!(args);

if let Some(first) = list.first() {
Ok(first.clone())
if let Some(first) = list.pop_front() {
Ok(first)
} else {
Err(RuntimeError::EmptyList)
}
}

pub fn tail(args: &[Value]) -> Result<Value> {
let mut list = list_arg!(args, 0);

if list.is_empty() {
Err(RuntimeError::EmptyList)
} else {
list.remove(0);
pub fn tail(mut args: Args) -> Result<Value> {
let mut list = list_arg!(args);

if list.remove(0).is_some() {
return_list!(list)
} else {
Err(RuntimeError::EmptyList)
}
}

pub fn cons(args: &[Value]) -> Result<Value> {
let mut list = list_arg!(args, 1).clone();
list.insert(0, args[0].clone());
pub fn cons(mut args: Args) -> Result<Value> {
let element = arg!(args);
let mut list = list_arg!(args);
list.insert(0, element);

return_list!(list)
}
5 changes: 3 additions & 2 deletions numbat/src/ffi/lookup.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
use super::macros::*;
use super::Args;
use super::Result;
use crate::quantity::Quantity;
use crate::typed_ast::DType;
use crate::value::Value;
use crate::RuntimeError;

pub fn _get_chemical_element_data_raw(args: &[Value]) -> Result<Value> {
pub fn _get_chemical_element_data_raw(mut args: Args) -> Result<Value> {
use crate::span::{SourceCodePositition, Span};
use crate::typed_ast::StructInfo;
use crate::typed_ast::Type;
use indexmap::IndexMap;
use mendeleev::{Electronvolt, GramPerCubicCentimeter, Kelvin, KiloJoulePerMole};
use std::sync::Arc;

let pattern = string_arg!(args, 0).to_lowercase();
let pattern = string_arg!(args).to_lowercase();

if let Some(element) = mendeleev::Element::list()
.iter()
Expand Down
27 changes: 17 additions & 10 deletions numbat/src/ffi/macros.rs
Original file line number Diff line number Diff line change
@@ -1,36 +1,43 @@
/// Some macros for writing FFI functions

macro_rules! arg {
($args:ident) => {
$args.pop_front().unwrap()
};
}
pub(crate) use arg;

macro_rules! quantity_arg {
($args:ident, $index:expr) => {
$args[$index].unsafe_as_quantity()
($args:ident) => {
arg!($args).unsafe_as_quantity()
};
}
pub(crate) use quantity_arg;

macro_rules! scalar_arg {
($args:ident, $index:expr) => {
quantity_arg!($args, $index).as_scalar().unwrap()
($args:ident) => {
quantity_arg!($args).as_scalar().unwrap()
};
}
pub(crate) use scalar_arg;

macro_rules! list_arg {
($args:ident, $index:expr) => {
$args[$index].unsafe_as_list()
($args:ident) => {
arg!($args).unsafe_as_list()
};
}
pub(crate) use list_arg;

macro_rules! string_arg {
($args:ident, $index:expr) => {
$args[$index].unsafe_as_string()
($args:ident) => {
arg!($args).unsafe_as_string()
};
}
pub(crate) use string_arg;

macro_rules! datetime_arg {
($args:ident, $index:expr) => {
$args[$index].unsafe_as_datetime()
($args:ident) => {
arg!($args).unsafe_as_datetime()
};
}
pub(crate) use datetime_arg;
Expand Down
35 changes: 18 additions & 17 deletions numbat/src/ffi/math.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
use super::macros::*;
use super::Args;
use super::Result;

use crate::quantity::Quantity;
use crate::value::Value;

pub fn mod_(args: &[Value]) -> Result<Value> {
let x = quantity_arg!(args, 0);
let y = quantity_arg!(args, 1);
pub fn mod_(mut args: Args) -> Result<Value> {
let x = quantity_arg!(args);
let y = quantity_arg!(args);

let x_value = x.unsafe_value().to_f64();
let y_value = y.convert_to(x.unit()).unwrap().unsafe_value().to_f64();
Expand All @@ -17,8 +18,8 @@ pub fn mod_(args: &[Value]) -> Result<Value> {
// A simple math function with signature 'Dim D. Fn[(D) -> D]', which only operates on the value of the quantity
macro_rules! simple_polymorphic_math_function {
($name:ident, $op:ident) => {
pub fn $name(args: &[Value]) -> Result<Value> {
let arg = quantity_arg!(args, 0);
pub fn $name(mut args: Args) -> Result<Value> {
let arg = quantity_arg!(args);

let value = arg.unsafe_value().to_f64();
return_quantity!(value.$op(), arg.unit().clone())
Expand All @@ -29,8 +30,8 @@ macro_rules! simple_polymorphic_math_function {
// Similar, but with signature 'Fn[(Scalar) -> Scalar]'
macro_rules! simple_scalar_math_function {
($name:ident, $op:ident) => {
pub fn $name(args: &[Value]) -> Result<Value> {
let value = scalar_arg!(args, 0).to_f64();
pub fn $name(mut args: Args) -> Result<Value> {
let value = scalar_arg!(args).to_f64();
return_scalar!(value.$op())
}
};
Expand All @@ -48,9 +49,9 @@ simple_scalar_math_function!(asin, asin);
simple_scalar_math_function!(acos, acos);
simple_scalar_math_function!(atan, atan);

pub fn atan2(args: &[Value]) -> Result<Value> {
let y = quantity_arg!(args, 0);
let x = quantity_arg!(args, 1);
pub fn atan2(mut args: Args) -> Result<Value> {
let y = quantity_arg!(args);
let x = quantity_arg!(args);

let y_value = y.unsafe_value().to_f64();
let x_value = x.convert_to(y.unit()).unwrap().unsafe_value().to_f64();
Expand All @@ -69,24 +70,24 @@ simple_scalar_math_function!(ln, ln);
simple_scalar_math_function!(log10, log10);
simple_scalar_math_function!(log2, log2);

pub fn gamma(args: &[Value]) -> Result<Value> {
let input = scalar_arg!(args, 0).to_f64();
pub fn gamma(mut args: Args) -> Result<Value> {
let input = scalar_arg!(args).to_f64();

return_scalar!(crate::gamma::gamma(input))
}

pub fn is_nan(args: &[Value]) -> Result<Value> {
let arg = quantity_arg!(args, 0);
pub fn is_nan(mut args: Args) -> Result<Value> {
let arg = quantity_arg!(args);

return_boolean!(arg.unsafe_value().to_f64().is_nan())
}

pub fn is_infinite(args: &[Value]) -> Result<Value> {
let arg = quantity_arg!(args, 0);
pub fn is_infinite(mut args: Args) -> Result<Value> {
let arg = quantity_arg!(args);

return_boolean!(arg.unsafe_value().to_f64().is_infinite())
}

pub fn random(_args: &[Value]) -> Result<Value> {
pub fn random(_args: Args) -> Result<Value> {
return_scalar!(rand::random::<f64>())
}
8 changes: 6 additions & 2 deletions numbat/src/ffi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ mod math;
mod procedures;
mod strings;

use std::collections::VecDeque;

use crate::interpreter::RuntimeError;
use crate::value::Value;
use crate::vm::ExecutionContext;
Expand All @@ -18,11 +20,13 @@ pub(crate) type ArityRange = std::ops::RangeInclusive<usize>;

type Result<T> = std::result::Result<T, RuntimeError>;

type BoxedFunction = Box<dyn Fn(&[Value]) -> Result<Value> + Send + Sync>;
pub(crate) type Args = VecDeque<Value>;

type BoxedFunction = Box<dyn Fn(Args) -> Result<Value> + Send + Sync>;

pub(crate) enum Callable {
Function(BoxedFunction),
Procedure(fn(&mut ExecutionContext, &[Value]) -> ControlFlow),
Procedure(fn(&mut ExecutionContext, Args) -> ControlFlow),
}

pub(crate) struct ForeignFunction {
Expand Down
Loading
Loading