summaryrefslogtreecommitdiff
path: root/src/syntax
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2019-10-30 20:13:28 +0100
committerLaurenz <laurmaedje@gmail.com>2019-10-30 20:13:28 +0100
commitccc4639c7d4dfe039d469d16236ac5ad121f4a07 (patch)
tree950829c7bf8c5771bdf608c01a7a7b6b6614df56 /src/syntax
parentb4be25e43b1ee9da924d13b7f2e8289f12bd2c3b (diff)
Improve documentation comments 📜
Diffstat (limited to 'src/syntax')
-rw-r--r--src/syntax/mod.rs51
-rw-r--r--src/syntax/parsing.rs86
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)
})