Express functions as trait objects 🚄

This commit is contained in:
Laurenz 2019-04-11 17:36:21 +02:00
parent 98c3788cf1
commit a51e7a0758
2 changed files with 116 additions and 17 deletions

View File

@ -1,5 +1,6 @@
//! Tokenization and parsing of source code into syntax trees. //! Tokenization and parsing of source code into syntax trees.
use std::collections::HashMap;
use std::fmt; use std::fmt;
use std::iter::Peekable; use std::iter::Peekable;
use std::mem::swap; use std::mem::swap;
@ -208,7 +209,7 @@ impl<'s> Tokens<'s> {
pub struct Parser<'s, T> where T: Iterator<Item=Token<'s>> { pub struct Parser<'s, T> where T: Iterator<Item=Token<'s>> {
tokens: Peekable<T>, tokens: Peekable<T>,
state: ParserState, state: ParserState,
stack: Vec<Function<'s>>, stack: Vec<FuncInvocation>,
tree: SyntaxTree<'s>, tree: SyntaxTree<'s>,
} }
@ -296,9 +297,13 @@ impl<'s, T> Parser<'s, T> where T: Iterator<Item=Token<'s>> {
}, },
PS::Function => { PS::Function => {
let name = match token { let name = if let Token::Word(word) = token {
Token::Word(word) if word.is_identifier() => word, match Ident::new(word) {
_ => return self.err("expected identifier"), Some(ident) => ident,
None => return self.err("invalid identifier"),
}
} else {
return self.err("expected identifier");
}; };
self.advance(); self.advance();
@ -306,9 +311,15 @@ impl<'s, T> Parser<'s, T> where T: Iterator<Item=Token<'s>> {
return self.err("expected closing bracket"); return self.err("expected closing bracket");
} }
let mut func = Function { let header = FuncHeader {
name, name,
body: None, args: vec![],
kwargs: HashMap::new(),
};
let func = FuncInvocation {
header,
body: unimplemented!(),
}; };
// This function has a body. // This function has a body.

View File

@ -1,5 +1,10 @@
//! Tokenized and syntax tree representations of source code. //! 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. /// A logical unit of the incoming text stream.
#[derive(Debug, Copy, Clone, Eq, PartialEq)] #[derive(Debug, Copy, Clone, Eq, PartialEq)]
@ -32,7 +37,7 @@ pub enum Token<'s> {
} }
/// A tree representation of the source. /// A tree representation of the source.
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, PartialEq)]
pub struct SyntaxTree<'s> { pub struct SyntaxTree<'s> {
/// The children. /// The children.
pub nodes: Vec<Node<'s>>, pub nodes: Vec<Node<'s>>,
@ -47,7 +52,7 @@ impl<'s> SyntaxTree<'s> {
} }
/// A node in the abstract syntax tree. /// A node in the abstract syntax tree.
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, PartialEq)]
pub enum Node<'s> { pub enum Node<'s> {
/// Whitespace between other nodes. /// Whitespace between other nodes.
Space, Space,
@ -62,15 +67,98 @@ pub enum Node<'s> {
/// A literal word. /// A literal word.
Word(&'s str), Word(&'s str),
/// A function invocation. /// A function invocation.
Func(Function<'s>), Func(FuncInvocation),
} }
/// A node representing a function invocation. /// A complete function invocation consisting of header and body.
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, PartialEq)]
pub struct Function<'s> { pub struct FuncInvocation {
/// The name of the function. pub header: FuncHeader,
pub name: &'s str, pub body: Box<dyn Function>,
/// Some syntax tree if the function had a body (second set of brackets), }
/// otherwise nothing.
pub body: Option<SyntaxTree<'s>>, /// Contains header information of a function invocation.
#[derive(Debug, Clone, PartialEq)]
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
}
} }