mirror of
https://github.com/typst/typst
synced 2025-05-14 04:56:26 +08:00
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 std::ops::Deref;
|
||||||
|
|
||||||
use crate::syntax::*;
|
use crate::syntax::*;
|
||||||
use crate::func::{Scope, BodyTokens};
|
use crate::func::Scope;
|
||||||
use crate::utility::{Splinor, Spline, Splined, StrExt};
|
use crate::utility::{Splinor, Spline, Splined, StrExt};
|
||||||
|
|
||||||
use unicode_segmentation::{UnicodeSegmentation, UWordBounds};
|
use unicode_segmentation::{UnicodeSegmentation, UWordBounds};
|
||||||
@ -225,8 +225,6 @@ enum ParserState {
|
|||||||
FirstNewline,
|
FirstNewline,
|
||||||
/// We wrote a newline.
|
/// We wrote a newline.
|
||||||
WroteNewline,
|
WroteNewline,
|
||||||
/// Inside a function header.
|
|
||||||
Function,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'s, T> Parser<'s, T> where T: Iterator<Item=Token<'s>> {
|
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.
|
/// 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;
|
use ParserState as PS;
|
||||||
|
|
||||||
while let Some(token) = self.tokens.peek() {
|
while let Some(&token) = self.tokens.peek() {
|
||||||
let token = *token;
|
|
||||||
|
|
||||||
// Skip over comments.
|
// Skip over comments.
|
||||||
if token == Token::Hashtag {
|
if token == Token::Hashtag {
|
||||||
self.skip_while(|&t| t != Token::Newline);
|
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())),
|
Token::Word(word) => self.append_consumed(Node::Word(word.to_owned())),
|
||||||
|
|
||||||
// Functions
|
// Functions
|
||||||
Token::LeftBracket => self.switch_consumed(PS::Function),
|
Token::LeftBracket => self.parse_function()?,
|
||||||
Token::RightBracket => {
|
Token::RightBracket => {
|
||||||
return Err(ParseError::new("unexpected closing bracket"));
|
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
|
// Should not happen
|
||||||
Token::Colon | Token::Equals | Token::Hashtag => unreachable!(),
|
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)
|
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.
|
/// Advance the iterator by one step.
|
||||||
fn advance(&mut self) {
|
fn advance(&mut self) {
|
||||||
self.tokens.next();
|
self.tokens.next();
|
||||||
@ -380,36 +375,34 @@ impl<'s, T> Parser<'s, T> where T: Iterator<Item=Token<'s>> {
|
|||||||
self.tree.nodes.push(node);
|
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.
|
/// Append a space if there is not one already.
|
||||||
fn append_space(&mut self) {
|
fn append_space(&mut self) {
|
||||||
if self.last() != Some(&Node::Space) {
|
if self.tree.nodes.last() != Some(&Node::Space) {
|
||||||
self.append(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.
|
/// Advance and append a space if there is not one already.
|
||||||
fn append_space_consumed(&mut self) {
|
fn append_space_consumed(&mut self) {
|
||||||
self.advance();
|
self.advance();
|
||||||
self.append_space();
|
self.append_space();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Switch the state.
|
|
||||||
fn switch(&mut self, state: ParserState) {
|
|
||||||
self.state = state;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Advance and switch the state.
|
/// Advance and switch the state.
|
||||||
fn switch_consumed(&mut self, state: ParserState) {
|
fn switch_consumed(&mut self, state: ParserState) {
|
||||||
self.advance();
|
self.advance();
|
||||||
self.state = state;
|
self.switch(state);
|
||||||
}
|
|
||||||
|
|
||||||
/// The last appended node of the tree.
|
|
||||||
fn last(&self) -> Option<&Node> {
|
|
||||||
self.tree.nodes.last()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Skip tokens until the condition is met.
|
/// Skip tokens until the condition is met.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user