diff options
| author | Laurenz <laurmaedje@gmail.com> | 2019-10-30 20:13:28 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2019-10-30 20:13:28 +0100 |
| commit | ccc4639c7d4dfe039d469d16236ac5ad121f4a07 (patch) | |
| tree | 950829c7bf8c5771bdf608c01a7a7b6b6614df56 /src/syntax | |
| parent | b4be25e43b1ee9da924d13b7f2e8289f12bd2c3b (diff) | |
Improve documentation comments 📜
Diffstat (limited to 'src/syntax')
| -rw-r--r-- | src/syntax/mod.rs | 51 | ||||
| -rw-r--r-- | src/syntax/parsing.rs | 86 |
2 files changed, 60 insertions, 77 deletions
diff --git a/src/syntax/mod.rs b/src/syntax/mod.rs index b46beb36..da8cdc80 100644 --- a/src/syntax/mod.rs +++ b/src/syntax/mod.rs @@ -1,6 +1,5 @@ -//! Tokenized and syntax tree representations of source code. +//! Tokenization and parsing of source code. -use std::collections::HashMap; use std::fmt::{self, Display, Formatter}; use crate::func::Function; @@ -17,8 +16,7 @@ pub use parsing::{parse, ParseContext, ParseError, ParseResult}; pub enum Token<'s> { /// One or more whitespace (non-newline) codepoints. Space, - /// A line feed (`\n`, `\r\n` and some more as defined by the Unicode - /// standard). + /// A line feed (`\n`, `\r\n` and some more as defined by the Unicode standard). Newline, /// A left bracket: `[`. LeftBracket, @@ -28,37 +26,36 @@ pub enum Token<'s> { /// header only). /// /// If a colon occurs outside of a function header, it will be tokenized as - /// a [Word](Token::Word). + /// [Text](Token::Text), just like the other tokens annotated with + /// _Function header only_. Colon, - /// An equals (`=`) sign assigning a function argument a value (Function - /// header only). + /// An equals (`=`) sign assigning a function argument a value (Function header only). Equals, /// A comma (`,`) separating two function arguments (Function header only). Comma, /// Quoted text as a string value (Function header only). Quoted(&'s str), - /// An underscore, indicating text in italics. + /// An underscore, indicating text in italics (Body only). Underscore, - /// A star, indicating bold text. + /// A star, indicating bold text (Body only). Star, - /// A backtick, indicating monospace text. + /// A backtick, indicating monospace text (Body only). Backtick, /// A line comment. LineComment(&'s str), /// A block comment. BlockComment(&'s str), - /// A star followed by a slash unexpectedly ending a block comment (the - /// comment was not started before, otherwise a - /// [BlockComment](Token::BlockComment) would be returned). + /// A star followed by a slash unexpectedly ending a block comment + /// (the comment was not started before, otherwise a + /// [BlockComment](Token::BlockComment would be returned). StarSlash, - /// Everything else is just text. + /// A unit of Plain text. Text(&'s str), } -/// A tree representation of the source. +/// A tree representation of source code. #[derive(Debug, PartialEq)] pub struct SyntaxTree { - /// The children. pub nodes: Vec<Node>, } @@ -70,10 +67,10 @@ impl SyntaxTree { } } -/// A node in the abstract syntax tree. +/// A node in the syntax tree. #[derive(Debug, PartialEq)] pub enum Node { - /// Whitespace between other nodes. + /// Whitespace. Space, /// A line feed. Newline, @@ -89,28 +86,22 @@ pub enum Node { Func(FuncCall), } -/// A function invocation consisting of header and body. +/// A function invocation, consisting of header and a dynamically parsed body. #[derive(Debug)] pub struct FuncCall { pub header: FuncHeader, pub body: Box<dyn Function>, } -impl PartialEq for FuncCall { - fn eq(&self, other: &FuncCall) -> bool { - (self.header == other.header) && (&self.body == &other.body) - } -} - /// Contains header information of a function invocation. #[derive(Debug, Clone, PartialEq)] pub struct FuncHeader { pub name: String, pub args: Vec<Expression>, - pub kwargs: HashMap<String, Expression>, + pub kwargs: Vec<(String, Expression)>, } -/// A value expression. +/// An argument or return value. #[derive(Debug, Clone, PartialEq)] pub enum Expression { Ident(String), @@ -120,6 +111,12 @@ pub enum Expression { Bool(bool), } +impl PartialEq for FuncCall { + fn eq(&self, other: &FuncCall) -> bool { + (self.header == other.header) && (&self.body == &other.body) + } +} + impl Display for Expression { fn fmt(&self, f: &mut Formatter) -> fmt::Result { use Expression::*; diff --git a/src/syntax/parsing.rs b/src/syntax/parsing.rs index c2287085..1e949729 100644 --- a/src/syntax/parsing.rs +++ b/src/syntax/parsing.rs @@ -1,6 +1,5 @@ -//! Parsing of source code into token streams and syntax trees. +//! Parsing of token streams into syntax trees. -use std::collections::HashMap; use unicode_xid::UnicodeXID; use crate::func::{Function, Scope}; @@ -20,7 +19,7 @@ pub struct ParseContext<'a> { pub scope: &'a Scope, } -/// Transforms token streams to syntax trees. +/// Transforms token streams into syntax trees. #[derive(Debug)] struct Parser<'s> { src: &'s str, @@ -35,14 +34,15 @@ struct Parser<'s> { enum ParserState { /// The base state of the parser. Body, - /// We saw one newline already. + /// We saw one newline already and are looking for another. FirstNewline, - /// We wrote a newline. + /// We saw at least two newlines and wrote one, thus not + /// writing another one for more newlines. WroteNewline, } impl<'s> Parser<'s> { - /// Create a new parser from the source and the context. + /// Create a new parser from the source code and the context. fn new(src: &'s str, ctx: ParseContext<'s>) -> Parser<'s> { Parser { src, @@ -53,9 +53,8 @@ impl<'s> Parser<'s> { } } - /// Parse the source into an abstract syntax tree. + /// Parse the source into a syntax tree. fn parse(mut self) -> ParseResult<SyntaxTree> { - // Loop through all the tokens. while self.tokens.peek().is_some() { self.parse_white()?; self.parse_body_part()?; @@ -66,27 +65,30 @@ impl<'s> Parser<'s> { /// Parse the next part of the body. fn parse_body_part(&mut self) -> ParseResult<()> { + use Token::*; + if let Some(token) = self.tokens.peek() { match token { - // Functions - Token::LeftBracket => self.parse_func()?, - Token::RightBracket => return Err(ParseError::new("unexpected closing bracket")), - - // Modifiers - Token::Underscore => self.append_consumed(Node::ToggleItalics), - Token::Star => self.append_consumed(Node::ToggleBold), - Token::Backtick => self.append_consumed(Node::ToggleMonospace), + // Functions. + LeftBracket => self.parse_func()?, + RightBracket => return Err(ParseError::new("unexpected closing bracket")), - // Normal text - Token::Text(word) => self.append_consumed(Node::Text(word.to_owned())), + // Modifiers. + Underscore => self.append_consumed(Node::ToggleItalics), + Star => self.append_consumed(Node::ToggleBold), + Backtick => self.append_consumed(Node::ToggleMonospace), - Token::Colon | Token::Equals => panic!("bad token for body: {:?}", token), + // Normal text. + Text(word) => self.append_consumed(Node::Text(word.to_owned())), // The rest is handled elsewhere or should not happen, because `Tokens` does not - // yield colons or equals in the body, but their text equivalents instead. - _ => panic!("unexpected token: {:?}", token), + // yield these in a body. + Space | Newline | LineComment(_) | BlockComment(_) | + Colon | Equals | Comma | Quoted(_) | StarSlash + => panic!("parse_body_part: unexpected token: {:?}", token), } } + Ok(()) } @@ -122,7 +124,7 @@ impl<'s> Parser<'s> { let mut header = FuncHeader { name, args: vec![], - kwargs: HashMap::new(), + kwargs: vec![], }; self.skip_white(); @@ -147,9 +149,9 @@ impl<'s> Parser<'s> { } /// Parse the arguments to a function. - fn parse_func_args(&mut self) -> ParseResult<(Vec<Expression>, HashMap<String, Expression>)> { + fn parse_func_args(&mut self) -> ParseResult<(Vec<Expression>, Vec<(String, Expression)>)> { let mut args = Vec::new(); - let kwargs = HashMap::new(); + let kwargs = Vec::new(); let mut comma = false; loop { @@ -448,38 +450,22 @@ mod tests { #[derive(Debug, PartialEq)] pub struct TreeFn(pub SyntaxTree); - impl Function for TreeFn { - fn parse(_: &FuncHeader, body: Option<&str>, ctx: ParseContext) -> ParseResult<Self> - where Self: Sized { - if let Some(src) = body { - parse(src, ctx).map(|tree| TreeFn(tree)) - } else { - Err(ParseError::new("expected body for tree fn")) - } - } + function! { + data: TreeFn, - fn layout(&self, _: LayoutContext) -> LayoutResult<CommandList> { - Ok(CommandList::new()) - } + parse(_args, body, ctx) { Ok(TreeFn(parse!(required: body, ctx))) } + layout(_, _) { Ok(commands![]) } } /// A testing function without a body. #[derive(Debug, PartialEq)] pub struct BodylessFn; - impl Function for BodylessFn { - fn parse(_: &FuncHeader, body: Option<&str>, _: ParseContext) -> ParseResult<Self> - where Self: Sized { - if body.is_none() { - Ok(BodylessFn) - } else { - Err(ParseError::new("unexpected body for bodyless fn")) - } - } + function! { + data: BodylessFn, - fn layout(&self, _: LayoutContext) -> LayoutResult<CommandList> { - Ok(CommandList::new()) - } + parse(_args, body, _ctx) { parse!(forbidden: body); Ok(BodylessFn) } + layout(_, _) { Ok(commands![]) } } } @@ -539,7 +525,7 @@ mod tests { header: FuncHeader { name: $name.to_string(), args: vec![], - kwargs: HashMap::new(), + kwargs: vec![], }, body: $body, } @@ -617,7 +603,7 @@ mod tests { header: FuncHeader { name: name.to_string(), args, - kwargs: HashMap::new(), + kwargs: vec![], }, body: Box::new(BodylessFn) }) |
