summaryrefslogtreecommitdiff
path: root/src/eval/function.rs
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2022-01-31 17:57:20 +0100
committerLaurenz <laurmaedje@gmail.com>2022-02-01 12:26:13 +0100
commit6a6753cb69f7c29e857fd465eecf66a02ff76aa3 (patch)
treee157752f30f5c493ee045d98039cfd3a94cdff22 /src/eval/function.rs
parent20b1a38414101f842a6d9201133a5aaaa45a7cec (diff)
Better function representation
Diffstat (limited to 'src/eval/function.rs')
-rw-r--r--src/eval/function.rs228
1 files changed, 0 insertions, 228 deletions
diff --git a/src/eval/function.rs b/src/eval/function.rs
deleted file mode 100644
index 0edc1e78..00000000
--- a/src/eval/function.rs
+++ /dev/null
@@ -1,228 +0,0 @@
-use std::fmt::{self, Debug, Formatter, Write};
-use std::sync::Arc;
-
-use super::{Cast, EvalContext, Value};
-use crate::diag::{At, TypResult};
-use crate::syntax::{Span, Spanned};
-use crate::util::EcoString;
-
-/// An evaluatable function.
-#[derive(Clone)]
-pub struct Function(Arc<Inner<Func>>);
-
-/// The unsized structure behind the [`Arc`].
-struct Inner<T: ?Sized> {
- name: Option<EcoString>,
- func: T,
-}
-
-type Func = dyn Fn(&mut EvalContext, &mut Args) -> TypResult<Value>;
-
-impl Function {
- /// Create a new function from a rust closure.
- pub fn new<F>(name: Option<EcoString>, func: F) -> Self
- where
- F: Fn(&mut EvalContext, &mut Args) -> TypResult<Value> + 'static,
- {
- Self(Arc::new(Inner { name, func }))
- }
-
- /// The name of the function.
- pub fn name(&self) -> Option<&EcoString> {
- self.0.name.as_ref()
- }
-
- /// Call the function in the context with the arguments.
- pub fn call(&self, ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
- (&self.0.func)(ctx, args)
- }
-}
-
-impl Debug for Function {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- f.write_str("<function")?;
- if let Some(name) = self.name() {
- f.write_char(' ')?;
- f.write_str(name)?;
- }
- f.write_char('>')
- }
-}
-
-impl PartialEq for Function {
- fn eq(&self, other: &Self) -> bool {
- // We cast to thin pointers for comparison.
- std::ptr::eq(
- Arc::as_ptr(&self.0) as *const (),
- Arc::as_ptr(&other.0) as *const (),
- )
- }
-}
-
-/// Evaluated arguments to a function.
-#[derive(Clone, PartialEq)]
-pub struct Args {
- /// The span of the whole argument list.
- pub span: Span,
- /// The positional and named arguments.
- pub items: Vec<Arg>,
-}
-
-/// An argument to a function call: `12` or `draw: false`.
-#[derive(Clone, PartialEq)]
-pub struct Arg {
- /// The span of the whole argument.
- pub span: Span,
- /// The name of the argument (`None` for positional arguments).
- pub name: Option<EcoString>,
- /// The value of the argument.
- pub value: Spanned<Value>,
-}
-
-impl Args {
- /// Consume and cast the first positional argument.
- ///
- /// Returns a `missing argument: {what}` error if no positional argument is
- /// left.
- pub fn expect<T>(&mut self, what: &str) -> TypResult<T>
- where
- T: Cast<Spanned<Value>>,
- {
- match self.eat()? {
- Some(v) => Ok(v),
- None => bail!(self.span, "missing argument: {}", what),
- }
- }
-
- /// Consume and cast the first positional argument if there is one.
- pub fn eat<T>(&mut self) -> TypResult<Option<T>>
- where
- T: Cast<Spanned<Value>>,
- {
- for (i, slot) in self.items.iter().enumerate() {
- if slot.name.is_none() {
- let value = self.items.remove(i).value;
- let span = value.span;
- return T::cast(value).at(span).map(Some);
- }
- }
- Ok(None)
- }
-
- /// Find and consume the first castable positional argument.
- pub fn find<T>(&mut self) -> Option<T>
- where
- T: Cast<Spanned<Value>>,
- {
- for (i, slot) in self.items.iter().enumerate() {
- if slot.name.is_none() && T::is(&slot.value) {
- let value = self.items.remove(i).value;
- return T::cast(value).ok();
- }
- }
- None
- }
-
- /// Find and consume all castable positional arguments.
- pub fn all<T>(&mut self) -> impl Iterator<Item = T> + '_
- where
- T: Cast<Spanned<Value>>,
- {
- std::iter::from_fn(move || self.find())
- }
-
- /// Cast and remove the value for the given named argument, returning an
- /// error if the conversion fails.
- pub fn named<T>(&mut self, name: &str) -> TypResult<Option<T>>
- where
- T: Cast<Spanned<Value>>,
- {
- // We don't quit once we have a match because when multiple matches
- // exist, we want to remove all of them and use the last one.
- let mut i = 0;
- let mut found = None;
- while i < self.items.len() {
- if self.items[i].name.as_deref() == Some(name) {
- let value = self.items.remove(i).value;
- let span = value.span;
- found = Some(T::cast(value).at(span)?);
- } else {
- i += 1;
- }
- }
- Ok(found)
- }
-
- /// Take out all arguments into a new instance.
- pub fn take(&mut self) -> Self {
- Self {
- span: self.span,
- items: std::mem::take(&mut self.items),
- }
- }
-
- /// Return an "unexpected argument" error if there is any remaining
- /// argument.
- pub fn finish(self) -> TypResult<()> {
- if let Some(arg) = self.items.first() {
- bail!(arg.span, "unexpected argument");
- }
- Ok(())
- }
-
- /// Reinterpret these arguments as actually being an array index.
- pub fn into_index(self) -> TypResult<i64> {
- self.into_castable("index")
- }
-
- /// Reinterpret these arguments as actually being a dictionary key.
- pub fn into_key(self) -> TypResult<EcoString> {
- self.into_castable("key")
- }
-
- /// Reinterpret these arguments as actually being a single castable thing.
- fn into_castable<T>(self, what: &str) -> TypResult<T>
- where
- T: Cast<Value>,
- {
- let mut iter = self.items.into_iter();
- let value = match iter.next() {
- Some(Arg { name: None, value, .. }) => value.v.cast().at(value.span)?,
- None => {
- bail!(self.span, "missing {}", what);
- }
- Some(Arg { name: Some(_), span, .. }) => {
- bail!(span, "named pair is not allowed here");
- }
- };
-
- if let Some(arg) = iter.next() {
- bail!(arg.span, "only one {} is allowed", what);
- }
-
- Ok(value)
- }
-}
-
-impl Debug for Args {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- f.write_char('(')?;
- for (i, arg) in self.items.iter().enumerate() {
- arg.fmt(f)?;
- if i + 1 < self.items.len() {
- f.write_str(", ")?;
- }
- }
- f.write_char(')')
- }
-}
-
-impl Debug for Arg {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- if let Some(name) = &self.name {
- f.write_str(name)?;
- f.write_str(": ")?;
- }
- Debug::fmt(&self.value.v, f)
- }
-}