Refactor function parsing ♻
This commit is contained in:
parent
14c9ff571d
commit
383d8365cf
159
src/parsing.rs
159
src/parsing.rs
@ -7,7 +7,7 @@ use std::mem::swap;
|
||||
use std::ops::Deref;
|
||||
|
||||
use crate::syntax::*;
|
||||
use crate::func::{Scope, BodyTokens};
|
||||
use crate::func::Scope;
|
||||
use crate::utility::{Splinor, Spline, Splined, StrExt};
|
||||
|
||||
use unicode_segmentation::{UnicodeSegmentation, UWordBounds};
|
||||
@ -225,8 +225,6 @@ enum ParserState {
|
||||
FirstNewline,
|
||||
/// We wrote a newline.
|
||||
WroteNewline,
|
||||
/// Inside a function header.
|
||||
Function,
|
||||
}
|
||||
|
||||
impl<'s, T> Parser<'s, T> where T: Iterator<Item=Token<'s>> {
|
||||
@ -251,12 +249,10 @@ impl<'s, T> Parser<'s, T> where T: Iterator<Item=Token<'s>> {
|
||||
}
|
||||
|
||||
/// Parse into an abstract syntax tree.
|
||||
pub(crate) fn parse(mut self) -> ParseResult<SyntaxTree> {
|
||||
pub fn parse(mut self) -> ParseResult<SyntaxTree> {
|
||||
use ParserState as PS;
|
||||
|
||||
while let Some(token) = self.tokens.peek() {
|
||||
let token = *token;
|
||||
|
||||
while let Some(&token) = self.tokens.peek() {
|
||||
// Skip over comments.
|
||||
if token == Token::Hashtag {
|
||||
self.skip_while(|&t| t != Token::Newline);
|
||||
@ -291,7 +287,7 @@ impl<'s, T> Parser<'s, T> where T: Iterator<Item=Token<'s>> {
|
||||
Token::Word(word) => self.append_consumed(Node::Word(word.to_owned())),
|
||||
|
||||
// Functions
|
||||
Token::LeftBracket => self.switch_consumed(PS::Function),
|
||||
Token::LeftBracket => self.parse_function()?,
|
||||
Token::RightBracket => {
|
||||
return Err(ParseError::new("unexpected closing bracket"));
|
||||
},
|
||||
@ -304,72 +300,71 @@ impl<'s, T> Parser<'s, T> where T: Iterator<Item=Token<'s>> {
|
||||
// Should not happen
|
||||
Token::Colon | Token::Equals | Token::Hashtag => unreachable!(),
|
||||
},
|
||||
|
||||
PS::Function => {
|
||||
let name = if let Token::Word(word) = token {
|
||||
match Ident::new(word) {
|
||||
Some(ident) => ident,
|
||||
None => return Err(ParseError::new("invalid identifier")),
|
||||
}
|
||||
} else {
|
||||
return Err(ParseError::new("expected identifier"));
|
||||
};
|
||||
self.advance();
|
||||
|
||||
// Expect the header closing bracket.
|
||||
if self.tokens.next() != Some(Token::RightBracket) {
|
||||
return Err(ParseError::new("expected closing bracket"));
|
||||
}
|
||||
|
||||
// Store the header information of the function invocation.
|
||||
let header = FuncHeader {
|
||||
name: name.clone(),
|
||||
args: vec![],
|
||||
kwargs: HashMap::new(),
|
||||
};
|
||||
|
||||
// This function has a body.
|
||||
let mut tokens = if let Some(Token::LeftBracket) = self.tokens.peek() {
|
||||
self.advance();
|
||||
Some(FuncTokens::new(&mut self.tokens))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// A mutably borrowed view over the tokens.
|
||||
let borrow_tokens: BodyTokens<'_> = tokens.as_mut().map(|toks| {
|
||||
Box::new(toks) as Box<dyn Iterator<Item=Token<'_>>>
|
||||
});
|
||||
|
||||
// Run the parser over the tokens.
|
||||
let body = if let Some(parser) = self.scope.get_parser(&name) {
|
||||
parser(&header, borrow_tokens, &self.scope)?
|
||||
} else {
|
||||
return Err(ParseError::new(format!("unknown function: '{}'", &name)));
|
||||
};
|
||||
|
||||
// Expect the closing bracket if it had a body.
|
||||
if let Some(tokens) = tokens {
|
||||
if tokens.unexpected_end {
|
||||
return Err(ParseError::new("expected closing bracket"));
|
||||
}
|
||||
}
|
||||
|
||||
// Finally this function is parsed to the end.
|
||||
self.append(Node::Func(FuncCall {
|
||||
header,
|
||||
body,
|
||||
}));
|
||||
|
||||
self.switch(PS::Body);
|
||||
},
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Ok(self.tree)
|
||||
}
|
||||
|
||||
/// Parse a function from the current position.
|
||||
fn parse_function(&mut self) -> ParseResult<()> {
|
||||
// This should only be called if a left bracket was seen.
|
||||
debug_assert!(self.tokens.next() == Some(Token::LeftBracket));
|
||||
|
||||
// The next token should be the name of the function.
|
||||
let name = match self.tokens.next() {
|
||||
Some(Token::Word(word)) => {
|
||||
Ident::new(word).ok_or_else(|| ParseError::new("invalid identifier"))
|
||||
},
|
||||
_ => Err(ParseError::new("expected identifier")),
|
||||
}?;
|
||||
|
||||
// Now the header should be closed.
|
||||
if self.tokens.next() != Some(Token::RightBracket) {
|
||||
return Err(ParseError::new("expected closing bracket"));
|
||||
}
|
||||
|
||||
// Store the header information of the function invocation.
|
||||
let header = FuncHeader {
|
||||
name,
|
||||
args: vec![],
|
||||
kwargs: HashMap::new(),
|
||||
};
|
||||
|
||||
// Whether the function has a body.
|
||||
let has_body = self.tokens.peek() == Some(&Token::LeftBracket);
|
||||
if has_body {
|
||||
self.advance();
|
||||
}
|
||||
|
||||
// Now we want to parse this function dynamically.
|
||||
let parser = self.scope.get_parser(&header.name)
|
||||
.ok_or_else(|| ParseError::new(format!("unknown function: '{}'", &header.name)))?;
|
||||
|
||||
// Do the parsing dependend on whether the function has a body.
|
||||
let body = if has_body {
|
||||
let mut func_tokens = FuncTokens::new(&mut self.tokens);
|
||||
let borrowed = Box::new(&mut func_tokens) as Box<dyn Iterator<Item=Token<'_>>>;
|
||||
|
||||
let body = parser(&header, Some(borrowed), &self.scope)?;
|
||||
if func_tokens.unexpected_end {
|
||||
return Err(ParseError::new("expected closing bracket"));
|
||||
}
|
||||
|
||||
body
|
||||
} else {
|
||||
parser(&header, None, &self.scope)?
|
||||
};
|
||||
|
||||
// Finally this function is parsed to the end.
|
||||
self.append(Node::Func(FuncCall {
|
||||
header,
|
||||
body,
|
||||
}));
|
||||
|
||||
Ok(self.switch(ParserState::Body))
|
||||
}
|
||||
|
||||
/// Advance the iterator by one step.
|
||||
fn advance(&mut self) {
|
||||
self.tokens.next();
|
||||
@ -380,36 +375,34 @@ impl<'s, T> Parser<'s, T> where T: Iterator<Item=Token<'s>> {
|
||||
self.tree.nodes.push(node);
|
||||
}
|
||||
|
||||
/// Advance and return the given node.
|
||||
fn append_consumed(&mut self, node: Node) { self.advance(); self.append(node); }
|
||||
|
||||
/// Append a space if there is not one already.
|
||||
fn append_space(&mut self) {
|
||||
if self.last() != Some(&Node::Space) {
|
||||
if self.tree.nodes.last() != Some(&Node::Space) {
|
||||
self.append(Node::Space);
|
||||
}
|
||||
}
|
||||
|
||||
/// Switch the state.
|
||||
fn switch(&mut self, state: ParserState) {
|
||||
self.state = state;
|
||||
}
|
||||
|
||||
/// Advance and return the given node.
|
||||
fn append_consumed(&mut self, node: Node) {
|
||||
self.advance();
|
||||
self.append(node);
|
||||
}
|
||||
|
||||
/// Advance and append a space if there is not one already.
|
||||
fn append_space_consumed(&mut self) {
|
||||
self.advance();
|
||||
self.append_space();
|
||||
}
|
||||
|
||||
/// Switch the state.
|
||||
fn switch(&mut self, state: ParserState) {
|
||||
self.state = state;
|
||||
}
|
||||
|
||||
/// Advance and switch the state.
|
||||
fn switch_consumed(&mut self, state: ParserState) {
|
||||
self.advance();
|
||||
self.state = state;
|
||||
}
|
||||
|
||||
/// The last appended node of the tree.
|
||||
fn last(&self) -> Option<&Node> {
|
||||
self.tree.nodes.last()
|
||||
self.switch(state);
|
||||
}
|
||||
|
||||
/// Skip tokens until the condition is met.
|
||||
|
Loading…
x
Reference in New Issue
Block a user