diff options
| author | Laurenz <laurmaedje@gmail.com> | 2019-04-11 17:36:21 +0200 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2019-04-11 17:36:21 +0200 |
| commit | a51e7a0758758d92ce3655896db6c56d5c1013cf (patch) | |
| tree | 2a58558688a6c9a8527ad5ee754374e49d14ef82 /src/syntax.rs | |
| parent | 98c3788cf150a31f34d5ef20e1fd375f4d79480c (diff) | |
Express functions as trait objects 🚄
Diffstat (limited to 'src/syntax.rs')
| -rw-r--r-- | src/syntax.rs | 108 |
1 files changed, 98 insertions, 10 deletions
diff --git a/src/syntax.rs b/src/syntax.rs index 46b84832..fdb71d14 100644 --- a/src/syntax.rs +++ b/src/syntax.rs @@ -1,5 +1,10 @@ //! Tokenized and syntax tree representations of source code. +use std::fmt::Debug; +use std::collections::HashMap; +use std::ops::Deref; +use crate::utility::StrExt; + /// A logical unit of the incoming text stream. #[derive(Debug, Copy, Clone, Eq, PartialEq)] @@ -32,7 +37,7 @@ pub enum Token<'s> { } /// A tree representation of the source. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, PartialEq)] pub struct SyntaxTree<'s> { /// The children. pub nodes: Vec<Node<'s>>, @@ -47,7 +52,7 @@ impl<'s> SyntaxTree<'s> { } /// A node in the abstract syntax tree. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, PartialEq)] pub enum Node<'s> { /// Whitespace between other nodes. Space, @@ -62,15 +67,98 @@ pub enum Node<'s> { /// A literal word. Word(&'s str), /// A function invocation. - Func(Function<'s>), + Func(FuncInvocation), +} + +/// A complete function invocation consisting of header and body. +#[derive(Debug, PartialEq)] +pub struct FuncInvocation { + pub header: FuncHeader, + pub body: Box<dyn Function>, } -/// A node representing a function invocation. +/// Contains header information of a function invocation. #[derive(Debug, Clone, PartialEq)] -pub struct Function<'s> { - /// The name of the function. - pub name: &'s str, - /// Some syntax tree if the function had a body (second set of brackets), - /// otherwise nothing. - pub body: Option<SyntaxTree<'s>>, +pub struct FuncHeader { + pub name: Ident, + pub args: Vec<Expression>, + pub kwargs: HashMap<Ident, Expression> +} + +use std::any::Any; + +/// Types that act as functions. +pub trait Function: Debug + FunctionHelper { + /// Parse the function. + fn parse() -> Self where Self: Sized; + + /// Execute the function and optionally yield a return value. + fn typeset(&self, header: &FuncHeader) -> Option<Expression>; +} + +trait FunctionHelper { + fn help_as_any(&self) -> &dyn Any; + fn help_eq(&self, other: &dyn Function) -> bool; +} + +impl<T> FunctionHelper for T where T: Clone + PartialEq + 'static { + fn help_as_any(&self) -> &dyn Any { + self + } + + fn help_eq(&self, other: &dyn Function) -> bool { + if let Some(other) = other.help_as_any().downcast_ref::<Self>() { + self == other + } else { + false + } + } +} + +impl PartialEq<dyn Function> for &dyn Function { + fn eq(&self, other: &dyn Function) -> bool { + self.help_eq(other) + } +} + +impl PartialEq<Box<dyn Function>> for Box<dyn Function> { + fn eq(&self, other: &Box<dyn Function>) -> bool { + &*self == &*other + } +} + +/// A potentially unevaluated expression. +#[derive(Debug, Clone, PartialEq)] +pub enum Expression {} + +/// A valid identifier. +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +pub struct Ident(String); + +impl Ident { + /// Create a new identifier if the string is a valid one. + #[inline] + pub fn new<S: Into<String>>(ident: S) -> Option<Ident> { + let ident = ident.into(); + if ident.is_identifier() { + Some(Ident(ident)) + } else { + None + } + } + + /// Consume self and return the underlying string. + #[inline] + pub fn into_inner(self) -> String { + self.0 + } +} + +impl Deref for Ident { + type Target = str; + + #[inline] + fn deref(&self) -> &str { + &*self.0 + } } |
