summaryrefslogtreecommitdiff
path: root/src/syntax.rs
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2019-04-11 17:36:21 +0200
committerLaurenz <laurmaedje@gmail.com>2019-04-11 17:36:21 +0200
commita51e7a0758758d92ce3655896db6c56d5c1013cf (patch)
tree2a58558688a6c9a8527ad5ee754374e49d14ef82 /src/syntax.rs
parent98c3788cf150a31f34d5ef20e1fd375f4d79480c (diff)
Express functions as trait objects 🚄
Diffstat (limited to 'src/syntax.rs')
-rw-r--r--src/syntax.rs108
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
+ }
}