Remove stack from parser ♻

This commit is contained in:
Laurenz 2019-04-29 11:03:17 +02:00
parent f279c52b50
commit 14c9ff571d
3 changed files with 105 additions and 113 deletions

View File

@ -3,68 +3,37 @@
use std::any::Any; use std::any::Any;
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt::Debug; use std::fmt::Debug;
use crate::syntax::{Token, FuncHeader, Expression}; use crate::syntax::{Token, FuncHeader, Expression};
use crate::parsing::ParseError; use crate::parsing::ParseResult;
/// An optional iterator over the tokens of a function body. /// An optional iterator over the tokens of a function body.
pub type BodyTokens<'a> = Option<Box<dyn Iterator<Item=Token<'a>> + 'a>>; pub type BodyTokens<'a> = Option<Box<dyn Iterator<Item=Token<'a>> + 'a>>;
/// Parser functions.
pub type ParseFunc = dyn Fn(&FuncHeader, BodyTokens<'_>, &Scope)
-> ParseResult<Box<dyn Function>>;
/// Types that act as functions. /// Types that act as functions.
/// ///
/// These types have to be able to parse tokens into themselves and store the /// These types have to be able to parse tokens into themselves and store the
/// relevant information from the parsing to do their role in typesetting later. /// relevant information from the parsing to do their role in typesetting later.
/// ///
/// `FunctionRequirements` is automatically implemented for types which /// The trait `FunctionBounds` is automatically implemented for types which can be
/// can be used as functions, that is they fulfill the bounds /// used as functions, that is they fulfill the bounds `Debug + PartialEq + 'static`.
/// `Debug + PartialEq + 'static`. pub trait Function: FunctionBounds {
pub trait Function: FunctionRequirements + 'static {
/// Parse the function. /// Parse the function.
fn parse(header: &FuncHeader, tokens: BodyTokens<'_>, scope: &Scope) fn parse(header: &FuncHeader, tokens: BodyTokens<'_>, scope: &Scope)
-> Result<Self, ParseError> where Self: Sized; -> ParseResult<Self> where Self: Sized;
/// Execute the function and optionally yield a return value. /// Execute the function and optionally yield a return value.
fn typeset(&self, header: &FuncHeader) -> Option<Expression>; fn typeset(&self, header: &FuncHeader) -> Option<Expression>;
} }
/// A helper trait that describes requirements for types implement [`Function`].
///
/// Automatically implemented for all types which fulfill to the bounds
/// `Debug + PartialEq + 'static`. There should be no need to implement this
/// manually.
pub trait FunctionRequirements: Debug {
/// Cast self into `Any`.
fn help_cast_as_any(&self) -> &dyn Any;
/// Compare self with another function.
fn help_eq(&self, other: &dyn Function) -> bool;
}
impl<T> FunctionRequirements for T where T: Debug + PartialEq + 'static {
fn help_cast_as_any(&self) -> &dyn Any {
self
}
fn help_eq(&self, other: &dyn Function) -> bool {
if let Some(other) = other.help_cast_as_any().downcast_ref::<Self>() {
self == other
} else {
false
}
}
}
impl PartialEq for dyn Function {
fn eq(&self, other: &dyn Function) -> bool {
self.help_eq(other)
}
}
/// A map from identifiers to functions. /// A map from identifiers to functions.
pub struct Scope { pub struct Scope {
parsers: HashMap<String, Box<dyn Fn(&FuncHeader, BodyTokens<'_>, &Scope) parsers: HashMap<String, Box<ParseFunc>>,
-> Result<Box<dyn Function>, ParseError>>>,
} }
impl Scope { impl Scope {
@ -85,9 +54,39 @@ impl Scope {
} }
/// Return the parser with the given name if there is one. /// Return the parser with the given name if there is one.
pub fn get_parser(&self, name: &str) pub fn get_parser(&self, name: &str) -> Option<&ParseFunc> {
-> Option<&dyn Fn(&FuncHeader, BodyTokens<'_>, &Scope)
-> Result<Box<dyn Function>, ParseError>> {
self.parsers.get(name).map(|x| &**x) self.parsers.get(name).map(|x| &**x)
} }
} }
/// A helper trait that describes requirements for types that can implement [`Function`].
///
/// Automatically implemented for all types which fulfill to the bounds
/// `Debug + PartialEq + 'static`. There should be no need to implement this manually.
pub trait FunctionBounds: Debug {
/// Cast self into `Any`.
fn help_cast_as_any(&self) -> &dyn Any;
/// Compare self with another function.
fn help_eq(&self, other: &dyn Function) -> bool;
}
impl<T> FunctionBounds for T where T: Debug + PartialEq + 'static {
fn help_cast_as_any(&self) -> &dyn Any {
self
}
fn help_eq(&self, other: &dyn Function) -> bool {
if let Some(other) = other.help_cast_as_any().downcast_ref::<Self>() {
self == other
} else {
false
}
}
}
impl PartialEq for dyn Function {
fn eq(&self, other: &dyn Function) -> bool {
self.help_eq(other)
}
}

View File

@ -5,11 +5,13 @@ use std::fmt;
use std::iter::Peekable; use std::iter::Peekable;
use std::mem::swap; use std::mem::swap;
use std::ops::Deref; use std::ops::Deref;
use unicode_segmentation::{UnicodeSegmentation, UWordBounds};
use crate::syntax::*; use crate::syntax::*;
use crate::func::{Scope, BodyTokens}; use crate::func::{Scope, BodyTokens};
use crate::utility::{Splinor, Spline, Splined, StrExt}; use crate::utility::{Splinor, Spline, Splined, StrExt};
use unicode_segmentation::{UnicodeSegmentation, UWordBounds};
/// An iterator over the tokens of source code. /// An iterator over the tokens of source code.
#[derive(Clone)] #[derive(Clone)]
@ -211,7 +213,6 @@ pub struct Parser<'s, T> where T: Iterator<Item=Token<'s>> {
tokens: Peekable<T>, tokens: Peekable<T>,
scope: ParserScope<'s>, scope: ParserScope<'s>,
state: ParserState, state: ParserState,
stack: Vec<FuncInvocation>,
tree: SyntaxTree, tree: SyntaxTree,
} }
@ -228,23 +229,6 @@ enum ParserState {
Function, Function,
} }
/// An owned or shared scope.
enum ParserScope<'s> {
Owned(Scope),
Shared(&'s Scope)
}
impl Deref for ParserScope<'_> {
type Target = Scope;
fn deref(&self) -> &Scope {
match self {
ParserScope::Owned(scope) => &scope,
ParserScope::Shared(scope) => scope,
}
}
}
impl<'s, T> Parser<'s, T> where T: Iterator<Item=Token<'s>> { impl<'s, T> Parser<'s, T> where T: Iterator<Item=Token<'s>> {
/// Create a new parser from a type that emits results of tokens. /// Create a new parser from a type that emits results of tokens.
pub fn new(tokens: T) -> Parser<'s, T> { pub fn new(tokens: T) -> Parser<'s, T> {
@ -262,7 +246,6 @@ impl<'s, T> Parser<'s, T> where T: Iterator<Item=Token<'s>> {
tokens: tokens.peekable(), tokens: tokens.peekable(),
scope, scope,
state: ParserState::Body, state: ParserState::Body,
stack: vec![],
tree: SyntaxTree::new(), tree: SyntaxTree::new(),
} }
} }
@ -310,11 +293,7 @@ impl<'s, T> Parser<'s, T> where T: Iterator<Item=Token<'s>> {
// Functions // Functions
Token::LeftBracket => self.switch_consumed(PS::Function), Token::LeftBracket => self.switch_consumed(PS::Function),
Token::RightBracket => { Token::RightBracket => {
self.advance(); return Err(ParseError::new("unexpected closing bracket"));
match self.stack.pop() {
Some(func) => self.append(Node::Func(func)),
None => return Err(ParseError::new("unexpected closing bracket")),
}
}, },
// Modifiers // Modifiers
@ -366,20 +345,18 @@ impl<'s, T> Parser<'s, T> where T: Iterator<Item=Token<'s>> {
let body = if let Some(parser) = self.scope.get_parser(&name) { let body = if let Some(parser) = self.scope.get_parser(&name) {
parser(&header, borrow_tokens, &self.scope)? parser(&header, borrow_tokens, &self.scope)?
} else { } else {
let message = format!("unknown function: '{}'", &name); return Err(ParseError::new(format!("unknown function: '{}'", &name)));
return Err(ParseError::new(message));
}; };
// Expect the closing bracket if it had a body. // Expect the closing bracket if it had a body.
if let Some(tokens) = tokens { if let Some(tokens) = tokens {
println!("lulz");
if tokens.unexpected_end { if tokens.unexpected_end {
return Err(ParseError::new("expected closing bracket")); return Err(ParseError::new("expected closing bracket"));
} }
} }
// Finally this function is parsed to the end. // Finally this function is parsed to the end.
self.append(Node::Func(FuncInvocation { self.append(Node::Func(FuncCall {
header, header,
body, body,
})); }));
@ -390,10 +367,6 @@ impl<'s, T> Parser<'s, T> where T: Iterator<Item=Token<'s>> {
} }
} }
// if !self.stack.is_empty() {
// return Err(ParseError::new("expected closing bracket"));
// }
Ok(self.tree) Ok(self.tree)
} }
@ -402,13 +375,9 @@ impl<'s, T> Parser<'s, T> where T: Iterator<Item=Token<'s>> {
self.tokens.next(); self.tokens.next();
} }
/// Append a node to the top-of-stack function or the main tree itself. /// Append a node to the tree.
fn append(&mut self, node: Node) { fn append(&mut self, node: Node) {
self.tree.nodes.push(node); self.tree.nodes.push(node);
// match self.stack.last_mut() {
// Some(func) => func.body.as_mut().unwrap(),
// None => &mut self.tree,
// }.nodes.push(node);
} }
/// Advance and return the given node. /// Advance and return the given node.
@ -422,7 +391,10 @@ impl<'s, T> Parser<'s, T> where T: Iterator<Item=Token<'s>> {
} }
/// Advance and append a space if there is not one already. /// Advance and append a space if there is not one already.
fn append_space_consumed(&mut self) { self.advance(); self.append_space(); } fn append_space_consumed(&mut self) {
self.advance();
self.append_space();
}
/// Switch the state. /// Switch the state.
fn switch(&mut self, state: ParserState) { fn switch(&mut self, state: ParserState) {
@ -430,15 +402,14 @@ impl<'s, T> Parser<'s, T> where T: Iterator<Item=Token<'s>> {
} }
/// Advance and switch the state. /// Advance and switch the state.
fn switch_consumed(&mut self, state: ParserState) { self.advance(); self.state = state; } fn switch_consumed(&mut self, state: ParserState) {
self.advance();
self.state = state;
}
/// The last appended node of the top-of-stack function or of the main tree. /// The last appended node of the tree.
fn last(&self) -> Option<&Node> { fn last(&self) -> Option<&Node> {
self.tree.nodes.last() self.tree.nodes.last()
// match self.stack.last() {
// Some(func) => func.body.as_ref().unwrap(),
// None => &self.tree,
// }.nodes.last()
} }
/// Skip tokens until the condition is met. /// Skip tokens until the condition is met.
@ -452,6 +423,23 @@ impl<'s, T> Parser<'s, T> where T: Iterator<Item=Token<'s>> {
} }
} }
/// An owned or shared scope.
enum ParserScope<'s> {
Owned(Scope),
Shared(&'s Scope)
}
impl Deref for ParserScope<'_> {
type Target = Scope;
fn deref(&self) -> &Scope {
match self {
ParserScope::Owned(scope) => &scope,
ParserScope::Shared(scope) => scope,
}
}
}
/// A token iterator that that stops after the first unbalanced right paren. /// A token iterator that that stops after the first unbalanced right paren.
pub struct FuncTokens<'s, T> where T: Iterator<Item=Token<'s>> { pub struct FuncTokens<'s, T> where T: Iterator<Item=Token<'s>> {
tokens: T, tokens: T,
@ -505,9 +493,11 @@ impl ParseError {
} }
} }
/// The result type for parsing.
pub type ParseResult<T> = Result<T, ParseError>;
error_type! { error_type! {
err: ParseError, err: ParseError,
res: ParseResult,
show: f => f.write_str(&err.message), show: f => f.write_str(&err.message),
} }
@ -623,6 +613,7 @@ mod token_tests {
} }
} }
#[cfg(test)] #[cfg(test)]
mod parse_tests { mod parse_tests {
use super::*; use super::*;
@ -653,7 +644,8 @@ mod parse_tests {
struct BodylessFn; struct BodylessFn;
impl Function for BodylessFn { impl Function for BodylessFn {
fn parse(_: &FuncHeader, tokens: BodyTokens<'_>, _: &Scope) -> ParseResult<Self> where Self: Sized { fn parse(_: &FuncHeader, tokens: BodyTokens<'_>, _: &Scope)
-> ParseResult<Self> where Self: Sized {
if tokens.is_none() { if tokens.is_none() {
Ok(BodylessFn) Ok(BodylessFn)
} else { } else {
@ -672,7 +664,7 @@ mod parse_tests {
func!(@$name, Box::new(TreeFn($tree))) func!(@$name, Box::new(TreeFn($tree)))
}; };
(@$name:expr, $body:expr) => { (@$name:expr, $body:expr) => {
FuncInvocation { FuncCall {
header: FuncHeader { header: FuncHeader {
name: Ident::new($name).unwrap(), name: Ident::new($name).unwrap(),
args: vec![], args: vec![],
@ -707,7 +699,7 @@ mod parse_tests {
assert_eq!(Parser::new(Tokens::new(src)).parse().unwrap_err().message, err); assert_eq!(Parser::new(Tokens::new(src)).parse().unwrap_err().message, err);
} }
/// Test if the source parses into the error. /// Test with a scope if the source parses into the error.
fn test_err_scoped(scope: &Scope, src: &str, err: &str) { fn test_err_scoped(scope: &Scope, src: &str, err: &str) {
assert_eq!(Parser::with_scope(scope, Tokens::new(src)).parse().unwrap_err().message, err); assert_eq!(Parser::with_scope(scope, Tokens::new(src)).parse().unwrap_err().message, err);
} }
@ -735,10 +727,10 @@ mod parse_tests {
#[test] #[test]
fn parse_functions() { fn parse_functions() {
let mut scope = Scope::new(); let mut scope = Scope::new();
let tree_fns = ["modifier", "func", "links", "bodyempty", "nested"]; scope.add::<BodylessFn>("test");
let bodyless_fns = ["test", "end"]; scope.add::<BodylessFn>("end");
for func in &bodyless_fns { scope.add::<BodylessFn>(func); } scope.add::<TreeFn>("modifier");
for func in &tree_fns { scope.add::<TreeFn>(func); } scope.add::<TreeFn>("func");
test_scoped(&scope,"[test]", tree! [ F(func! { name => "test", body => None }) ]); test_scoped(&scope,"[test]", tree! [ F(func! { name => "test", body => None }) ]);
test_scoped(&scope, "This is an [modifier][example] of a function invocation.", tree! [ test_scoped(&scope, "This is an [modifier][example] of a function invocation.", tree! [
@ -746,13 +738,13 @@ mod parse_tests {
F(func! { name => "modifier", body => tree! [ W("example") ] }), S, F(func! { name => "modifier", body => tree! [ W("example") ] }), S,
W("of"), S, W("a"), S, W("function"), S, W("invocation"), W(".") W("of"), S, W("a"), S, W("function"), S, W("invocation"), W(".")
]); ]);
test_scoped(&scope, "[func][Hello][links][Here][end]", tree! [ test_scoped(&scope, "[func][Hello][modifier][Here][end]", tree! [
F(func! { F(func! {
name => "func", name => "func",
body => tree! [ W("Hello") ], body => tree! [ W("Hello") ],
}), }),
F(func! { F(func! {
name => "links", name => "modifier",
body => tree! [ W("Here") ], body => tree! [ W("Here") ],
}), }),
F(func! { F(func! {
@ -760,15 +752,15 @@ mod parse_tests {
body => None, body => None,
}), }),
]); ]);
test_scoped(&scope, "[bodyempty][]", tree! [ test_scoped(&scope, "[func][]", tree! [
F(func! { F(func! {
name => "bodyempty", name => "func",
body => tree! [], body => tree! [],
}) })
]); ]);
test_scoped(&scope, "[nested][[func][call]] outside", tree! [ test_scoped(&scope, "[modifier][[func][call]] outside", tree! [
F(func! { F(func! {
name => "nested", name => "modifier",
body => tree! [ body => tree! [
F(func! { F(func! {
name => "func", name => "func",
@ -784,19 +776,19 @@ mod parse_tests {
#[test] #[test]
fn parse_unicode() { fn parse_unicode() {
let mut scope = Scope::new(); let mut scope = Scope::new();
scope.add::<BodylessFn>("lib_parse"); scope.add::<BodylessFn>("func");
scope.add::<TreeFn>("func123"); scope.add::<TreeFn>("bold");
test_scoped(&scope, "[lib_parse] ⺐.", tree! [ test_scoped(&scope, "[func] ⺐.", tree! [
F(func! { F(func! {
name => "lib_parse", name => "func",
body => None, body => None,
}), }),
S, W(""), W(".") S, W(""), W(".")
]); ]);
test_scoped(&scope, "[func123][Hello 🌍!]", tree! [ test_scoped(&scope, "[bold][Hello 🌍!]", tree! [
F(func! { F(func! {
name => "func123", name => "bold",
body => tree! [ W("Hello"), S, W("🌍"), W("!") ], body => tree! [ W("Hello"), S, W("🌍"), W("!") ],
}) })
]); ]);

View File

@ -3,6 +3,7 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt::{self, Display, Formatter}; use std::fmt::{self, Display, Formatter};
use std::ops::Deref; use std::ops::Deref;
use crate::func::Function; use crate::func::Function;
use crate::utility::StrExt; use crate::utility::StrExt;
@ -68,18 +69,18 @@ pub enum Node {
/// A literal word. /// A literal word.
Word(String), Word(String),
/// A function invocation. /// A function invocation.
Func(FuncInvocation), Func(FuncCall),
} }
/// A complete function invocation consisting of header and body. /// A complete function invocation consisting of header and body.
#[derive(Debug)] #[derive(Debug)]
pub struct FuncInvocation { pub struct FuncCall {
pub header: FuncHeader, pub header: FuncHeader,
pub body: Box<dyn Function>, pub body: Box<dyn Function>,
} }
impl PartialEq for FuncInvocation { impl PartialEq for FuncCall {
fn eq(&self, other: &FuncInvocation) -> bool { fn eq(&self, other: &FuncCall) -> bool {
(self.header == other.header) && (&self.body == &other.body) (self.header == other.header) && (&self.body == &other.body)
} }
} }