From a51e7a0758758d92ce3655896db6c56d5c1013cf Mon Sep 17 00:00:00 2001 From: Laurenz Date: Thu, 11 Apr 2019 17:36:21 +0200 Subject: =?UTF-8?q?Express=20functions=20as=20trait=20objects=20?= =?UTF-8?q?=F0=9F=9A=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/syntax.rs | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 98 insertions(+), 10 deletions(-) (limited to 'src/syntax.rs') 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>, @@ -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, } -/// 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>, +pub struct FuncHeader { + pub name: Ident, + pub args: Vec, + pub kwargs: HashMap +} + +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; +} + +trait FunctionHelper { + fn help_as_any(&self) -> &dyn Any; + fn help_eq(&self, other: &dyn Function) -> bool; +} + +impl 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 == other + } else { + false + } + } +} + +impl PartialEq for &dyn Function { + fn eq(&self, other: &dyn Function) -> bool { + self.help_eq(other) + } +} + +impl PartialEq> for Box { + fn eq(&self, other: &Box) -> 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>(ident: S) -> Option { + 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 + } } -- cgit v1.2.3