mirror of
https://github.com/typst/typst
synced 2025-05-14 04:56:26 +08:00
Express functions as trait objects 🚄
This commit is contained in:
parent
98c3788cf1
commit
a51e7a0758
@ -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.
|
||||||
|
110
src/syntax.rs
110
src/syntax.rs
@ -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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user