summaryrefslogtreecommitdiff
path: root/src/syntax
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2020-08-03 16:01:23 +0200
committerLaurenz <laurmaedje@gmail.com>2020-08-03 16:04:55 +0200
commitdbfb3d2ced91e56314dfabbb4df9a338926c0a7a (patch)
tree678264cb18f8abc81ebe28077f5aef2df4e5a4bd /src/syntax
parent5a8f2fb73ddafba9fdbe952385ae2676126183ae (diff)
Formatting, documentation and small improvements 🧽
Diffstat (limited to 'src/syntax')
-rw-r--r--src/syntax/decoration.rs32
-rw-r--r--src/syntax/expr.rs156
-rw-r--r--src/syntax/mod.rs20
-rw-r--r--src/syntax/parsing.rs116
-rw-r--r--src/syntax/scope.rs42
-rw-r--r--src/syntax/span.rs60
-rw-r--r--src/syntax/test.rs30
-rw-r--r--src/syntax/tokens.rs37
-rw-r--r--src/syntax/tree.rs18
-rw-r--r--src/syntax/value.rs30
10 files changed, 248 insertions, 293 deletions
diff --git a/src/syntax/decoration.rs b/src/syntax/decoration.rs
index 13a9ad36..a9097444 100644
--- a/src/syntax/decoration.rs
+++ b/src/syntax/decoration.rs
@@ -13,32 +13,16 @@ pub type Decorations = SpanVec<Decoration>;
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "serialize", serde(rename_all = "camelCase"))]
pub enum Decoration {
- /// A valid function name.
- /// ```typst
- /// [box]
- /// ^^^
- /// ```
- ValidFuncName,
- /// An invalid function name.
- /// ```typst
- /// [blabla]
- /// ^^^^^^
- /// ```
- InvalidFuncName,
- /// A key of a keyword argument.
- /// ```typst
- /// [box: width=5cm]
- /// ^^^^^
- /// ```
+ /// A valid, successfully resolved function name.
+ ResolvedFunc,
+ /// An invalid, unresolved function name.
+ UnresolvedFunc,
+ /// A key part of a keyword argument.
ArgumentKey,
- /// A key in an object.
- /// ```typst
- /// [box: padding={ left: 1cm, right: 2cm}]
- /// ^^^^ ^^^^^
- /// ```
+ /// A key part of a pair in an object.
ObjectKey,
- /// An italic word.
+ /// Text in italics.
Italic,
- /// A bold word.
+ /// Text in bold.
Bold,
}
diff --git a/src/syntax/expr.rs b/src/syntax/expr.rs
index 0a9ab149..a637f115 100644
--- a/src/syntax/expr.rs
+++ b/src/syntax/expr.rs
@@ -5,26 +5,26 @@ use std::ops::Deref;
use std::str::FromStr;
use std::u8;
-use crate::Feedback;
use crate::length::Length;
-use super::span::{Spanned, SpanVec};
+use crate::Feedback;
+use super::span::{SpanVec, Spanned};
use super::tokens::is_identifier;
use super::value::Value;
-/// An argument or return value.
+/// An expression.
#[derive(Clone, PartialEq)]
pub enum Expr {
/// An identifier: `ident`.
Ident(Ident),
/// A string: `"string"`.
Str(String),
+ /// A boolean: `true, false`.
+ Bool(bool),
/// A number: `1.2, 200%`.
Number(f64),
/// A length: `2cm, 5.2in`.
Length(Length),
- /// A bool: `true, false`.
- Bool(bool),
- /// A color value, including the alpha channel: `#f79143ff`.
+ /// A color value with alpha channel: `#f79143ff`.
Color(RgbaColor),
/// A tuple: `(false, 12cm, "hi")`.
Tuple(Tuple),
@@ -32,37 +32,38 @@ pub enum Expr {
NamedTuple(NamedTuple),
/// An object: `{ fit: false, width: 12pt }`.
Object(Object),
- /// An operator that negates the contained expression.
+ /// An operation that negates the contained expression.
Neg(Box<Spanned<Expr>>),
- /// An operator that adds the contained expressions.
+ /// An operation that adds the contained expressions.
Add(Box<Spanned<Expr>>, Box<Spanned<Expr>>),
- /// An operator that subtracts contained expressions.
+ /// An operation that subtracts the contained expressions.
Sub(Box<Spanned<Expr>>, Box<Spanned<Expr>>),
- /// An operator that multiplies the contained expressions.
+ /// An operation that multiplies the contained expressions.
Mul(Box<Spanned<Expr>>, Box<Spanned<Expr>>),
- /// An operator that divides the contained expressions.
+ /// An operation that divides the contained expressions.
Div(Box<Spanned<Expr>>, Box<Spanned<Expr>>),
}
impl Expr {
- /// A natural-language name of the type of this expression, e.g. "identifier".
+ /// A natural-language name of the type of this expression, e.g.
+ /// "identifier".
pub fn name(&self) -> &'static str {
use Expr::*;
match self {
- Ident(_) => "identifier",
- Str(_) => "string",
- Number(_) => "number",
- Length(_) => "length",
- Bool(_) => "bool",
- Color(_) => "color",
- Tuple(_) => "tuple",
+ Ident(_) => "identifier",
+ Str(_) => "string",
+ Bool(_) => "bool",
+ Number(_) => "number",
+ Length(_) => "length",
+ Color(_) => "color",
+ Tuple(_) => "tuple",
NamedTuple(_) => "named tuple",
- Object(_) => "object",
- Neg(_) => "negation",
- Add(_, _) => "addition",
- Sub(_, _) => "subtraction",
- Mul(_, _) => "multiplication",
- Div(_, _) => "division",
+ Object(_) => "object",
+ Neg(_) => "negation",
+ Add(_, _) => "addition",
+ Sub(_, _) => "subtraction",
+ Mul(_, _) => "multiplication",
+ Div(_, _) => "division",
}
}
}
@@ -73,9 +74,9 @@ impl Debug for Expr {
match self {
Ident(i) => i.fmt(f),
Str(s) => s.fmt(f),
+ Bool(b) => b.fmt(f),
Number(n) => n.fmt(f),
Length(s) => s.fmt(f),
- Bool(b) => b.fmt(f),
Color(c) => c.fmt(f),
Tuple(t) => t.fmt(f),
NamedTuple(t) => t.fmt(f),
@@ -89,22 +90,15 @@ impl Debug for Expr {
}
}
-/// A unicode identifier.
-///
-/// # Example
-/// ```typst
-/// [func: "hi", ident]
-/// ^^^^ ^^^^^
-/// ```
+/// An identifier as defined by unicode with a few extra permissible characters.
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Ident(pub String);
impl Ident {
- /// Create a new identifier from a string checking that it is a valid
- /// unicode identifier.
- pub fn new<S>(ident: S) -> Option<Ident> where S: AsRef<str> + Into<String> {
+ /// Create a new identifier from a string checking that it is a valid.
+ pub fn new(ident: impl AsRef<str> + Into<String>) -> Option<Self> {
if is_identifier(ident.as_ref()) {
- Some(Ident(ident.into()))
+ Some(Self(ident.into()))
} else {
None
}
@@ -139,36 +133,36 @@ pub struct RgbaColor {
pub b: u8,
/// Alpha channel.
pub a: u8,
- /// Indicates whether this is a user-provided value or a
- /// default value provided as a fail-over by the parser.
- /// This color may be overwritten if this property is true.
+ /// This is true if this value was provided as a fail-over by the parser
+ /// because the user-defined value was invalid. This color may be
+ /// overwritten if this property is true.
pub healed: bool,
}
impl RgbaColor {
/// Constructs a new color.
- pub fn new(r: u8, g: u8, b: u8, a: u8) -> RgbaColor {
- RgbaColor { r, g, b, a, healed: false }
+ pub fn new(r: u8, g: u8, b: u8, a: u8) -> Self {
+ Self { r, g, b, a, healed: false }
}
/// Constructs a new color with the healed property set to true.
- pub fn new_healed(r: u8, g: u8, b: u8, a: u8) -> RgbaColor {
- RgbaColor { r, g, b, a, healed: true }
+ pub fn new_healed(r: u8, g: u8, b: u8, a: u8) -> Self {
+ Self { r, g, b, a, healed: true }
}
}
impl FromStr for RgbaColor {
type Err = ParseColorError;
- /// Constructs a new color from a hex string like `7a03c2`.
- /// Do not specify a leading `#`.
- fn from_str(hex_str: &str) -> Result<RgbaColor, Self::Err> {
+ /// Constructs a new color from a hex string like `7a03c2`. Do not specify a
+ /// leading `#`.
+ fn from_str(hex_str: &str) -> Result<Self, Self::Err> {
if !hex_str.is_ascii() {
return Err(ParseColorError);
}
let len = hex_str.len();
- let long = len == 6 || len == 8;
+ let long = len == 6 || len == 8;
let short = len == 3 || len == 4;
let alpha = len == 4 || len == 8;
@@ -192,7 +186,7 @@ impl FromStr for RgbaColor {
}
}
- Ok(RgbaColor::new(values[0], values[1], values[2], values[3]))
+ Ok(Self::new(values[0], values[1], values[2], values[3]))
}
}
@@ -200,14 +194,12 @@ impl Debug for RgbaColor {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
if f.alternate() {
write!(
- f,
- "rgba({:02}, {:02}, {:02}, {:02})",
+ f, "rgba({:02}, {:02}, {:02}, {:02})",
self.r, self.g, self.b, self.a,
)?;
} else {
write!(
- f,
- "#{:02x}{:02x}{:02x}{:02x}",
+ f, "#{:02x}{:02x}{:02x}{:02x}",
self.r, self.g, self.b, self.a,
)?;
}
@@ -218,7 +210,7 @@ impl Debug for RgbaColor {
}
}
-/// The error returned when parsing a [`RgbaColor`] from a string fails.
+/// The error when parsing an `RgbaColor` fails.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct ParseColorError;
@@ -226,7 +218,7 @@ impl std::error::Error for ParseColorError {}
impl fmt::Display for ParseColorError {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- f.write_str("invalid color")
+ f.pad("invalid color")
}
}
@@ -241,8 +233,8 @@ pub struct Tuple(pub SpanVec<Expr>);
impl Tuple {
/// Create an empty tuple.
- pub fn new() -> Tuple {
- Tuple(vec![])
+ pub fn new() -> Self {
+ Self(vec![])
}
/// Add an element.
@@ -278,13 +270,13 @@ impl Tuple {
let mut i = 0;
std::iter::from_fn(move || {
while i < self.0.len() {
- let val = V::parse(self.0[i].clone(), &mut Feedback::new());
- if val.is_some() {
- self.0.remove(i);
- return val;
- } else {
- i += 1;
- }
+ let val = V::parse(self.0[i].clone(), &mut Feedback::new());
+ if val.is_some() {
+ self.0.remove(i);
+ return val;
+ } else {
+ i += 1;
+ }
}
None
})
@@ -305,16 +297,16 @@ impl Debug for Tuple {
/// ```
#[derive(Debug, Clone, PartialEq)]
pub struct NamedTuple {
- /// The name of the tuple and where it is in the user source.
+ /// The name of the tuple.
pub name: Spanned<Ident>,
/// The elements of the tuple.
pub tuple: Spanned<Tuple>,
}
impl NamedTuple {
- /// Create a named tuple from a tuple.
- pub fn new(name: Spanned<Ident>, tuple: Spanned<Tuple>) -> NamedTuple {
- NamedTuple { name, tuple }
+ /// Create a named tuple from a name and a tuple.
+ pub fn new(name: Spanned<Ident>, tuple: Spanned<Tuple>) -> Self {
+ Self { name, tuple }
}
}
@@ -338,24 +330,14 @@ pub struct Object(pub SpanVec<Pair>);
/// A key-value pair in an object.
#[derive(Debug, Clone, PartialEq)]
pub struct Pair {
- /// The key part.
- /// ```typst
- /// key: value
- /// ^^^
- /// ```
pub key: Spanned<Ident>,
- /// The value part.
- /// ```typst
- /// key: value
- /// ^^^^^
- /// ```
pub value: Spanned<Expr>,
}
impl Object {
/// Create an empty object.
- pub fn new() -> Object {
- Object(vec![])
+ pub fn new() -> Self {
+ Self(vec![])
}
/// Add a pair to object.
@@ -384,13 +366,13 @@ impl Object {
let mut i = 0;
std::iter::from_fn(move || {
while i < self.0.len() {
- let val = V::parse(self.0[i].v.value.clone(), &mut Feedback::new());
- if let Some(val) = val {
- let pair = self.0.remove(i);
- return Some((pair.v.key, val));
- } else {
- i += 1;
- }
+ let val = V::parse(self.0[i].v.value.clone(), &mut Feedback::new());
+ if let Some(val) = val {
+ let pair = self.0.remove(i);
+ return Some((pair.v.key, val));
+ } else {
+ i += 1;
+ }
}
None
})
diff --git a/src/syntax/mod.rs b/src/syntax/mod.rs
index 6b1f3d08..e1c9bbb0 100644
--- a/src/syntax/mod.rs
+++ b/src/syntax/mod.rs
@@ -4,19 +4,19 @@
#[macro_use]
mod test;
-/// Basic types used around the syntax side.
-pub mod prelude {
- pub use super::expr::*;
- pub use super::tree::{SyntaxTree, SyntaxNode, DynamicNode};
- pub use super::span::{SpanVec, Span, Spanned};
- pub use super::value::*;
-}
-
pub mod decoration;
pub mod expr;
-pub mod tree;
pub mod parsing;
-pub mod span;
pub mod scope;
+pub mod span;
pub mod tokens;
+pub mod tree;
pub mod value;
+
+/// Basic types used around the syntax side.
+pub mod prelude {
+ pub use super::expr::*;
+ pub use super::span::{Span, SpanVec, Spanned};
+ pub use super::tree::{DynamicNode, SyntaxNode, SyntaxTree};
+ pub use super::value::*;
+}
diff --git a/src/syntax/parsing.rs b/src/syntax/parsing.rs
index bcbcb8d4..5141e455 100644
--- a/src/syntax/parsing.rs
+++ b/src/syntax/parsing.rs
@@ -2,36 +2,34 @@
use std::str::FromStr;
-use crate::{Pass, Feedback};
+use crate::{Feedback, Pass};
use super::decoration::Decoration;
use super::expr::*;
use super::scope::Scope;
use super::span::{Pos, Span, Spanned};
-use super::tokens::{is_newline_char, Token, Tokens, TokenMode};
-use super::tree::{SyntaxTree, SyntaxNode, DynamicNode};
+use super::tokens::{is_newline_char, Token, TokenMode, Tokens};
+use super::tree::{DynamicNode, SyntaxNode, SyntaxTree};
-/// A function which parses a function call into a tree.
+/// A function which parses a function call into a dynamic node.
pub type CallParser = dyn Fn(FuncCall, &ParseState) -> Pass<Box<dyn DynamicNode>>;
/// Parse a function call.
pub trait ParseCall {
- /// A metadata type whose value is passed into the function parser. This
- /// allows a single function to do different things depending on the value
- /// that needs to be given when inserting the function into a
- /// [scope](crate::syntax::Scope).
+ /// Metadata whose value is passed to `parse`. This allows a single function
+ /// to do different things depending on the value that needs to be given
+ /// when inserting the function into a scope.
///
- /// For example, the functions `word.spacing`, `line.spacing` and
- /// `par.spacing` are actually all the same function
- /// [`ContentSpacingFunc`](crate::library::ContentSpacingFunc) with the
- /// metadata specifiy which content should be spaced.
+ /// For example, the functions `h` and `v` are built on the same type.
type Meta: Clone;
- /// Parse the header and body into this function given a context.
+ /// Parse the function call.
fn parse(
- header: FuncCall,
+ call: FuncCall,
state: &ParseState,
metadata: Self::Meta,
- ) -> Pass<Self> where Self: Sized;
+ ) -> Pass<Self>
+ where
+ Self: Sized;
}
/// An invocation of a function.
@@ -58,8 +56,8 @@ pub struct FuncArgs {
impl FuncArgs {
/// Create new empty function arguments.
- pub fn new() -> FuncArgs {
- FuncArgs {
+ pub fn new() -> Self {
+ Self {
pos: Tuple::new(),
key: Object::new(),
}
@@ -77,9 +75,7 @@ impl FuncArgs {
/// Either a positional or keyword argument.
#[derive(Debug, Clone, PartialEq)]
pub enum FuncArg {
- /// A positional argument.
Pos(Expr),
- /// A keyword argument.
Key(Pair),
}
@@ -116,26 +112,21 @@ pub fn parse(src: &str, offset: Pos, state: &ParseState) -> Pass<SyntaxTree> {
Token::Function { header, body, terminated } => {
let parsed = FuncParser::new(header, body, state).parse();
feedback.extend_offset(parsed.feedback, span.start);
-
if !terminated {
error!(@feedback, Span::at(span.end), "expected closing bracket");
}
-
parsed.output
}
Token::Star => SyntaxNode::ToggleBolder,
Token::Underscore => SyntaxNode::ToggleItalic,
Token::Backslash => SyntaxNode::Linebreak,
-
Token::Raw { raw, terminated } => {
if !terminated {
error!(@feedback, Span::at(span.end), "expected backtick");
}
-
SyntaxNode::Raw(unescape_raw(raw))
}
-
Token::Text(text) => SyntaxNode::Text(text.to_string()),
Token::LineComment(_) | Token::BlockComment(_) => continue,
@@ -153,17 +144,9 @@ pub fn parse(src: &str, offset: Pos, state: &ParseState) -> Pass<SyntaxTree> {
struct FuncParser<'s> {
state: &'s ParseState,
- /// ```typst
- /// [tokens][body]
- /// ^^^^^^
- /// ```
+ /// The tokens inside the header.
tokens: Tokens<'s>,
peeked: Option<Option<Spanned<Token<'s>>>>,
- /// The spanned body string if there is a body.
- /// ```typst
- /// [tokens][body]
- /// ^^^^
- /// ```
body: Option<Spanned<&'s str>>,
feedback: Feedback,
}
@@ -173,8 +156,8 @@ impl<'s> FuncParser<'s> {
header: &'s str,
body: Option<Spanned<&'s str>>,
state: &'s ParseState,
- ) -> FuncParser<'s> {
- FuncParser {
+ ) -> Self {
+ Self {
state,
// Start at column 1 because the opening bracket is also part of
// the function, but not part of the `header` string.
@@ -190,7 +173,7 @@ impl<'s> FuncParser<'s> {
let name = header.name.v.as_str();
let (parser, deco) = match self.state.scope.get_parser(name) {
// The function exists in the scope.
- Some(parser) => (parser, Decoration::ValidFuncName),
+ Some(parser) => (parser, Decoration::ResolvedFunc),
// The function does not exist in the scope. The parser that is
// returned here is a fallback parser which exists to make sure
@@ -199,7 +182,7 @@ impl<'s> FuncParser<'s> {
None => {
error!(@self.feedback, header.name.span, "unknown function");
let parser = self.state.scope.get_fallback_parser();
- (parser, Decoration::InvalidFuncName)
+ (parser, Decoration::UnresolvedFunc)
}
};
@@ -261,9 +244,8 @@ impl<'s> FuncParser<'s> {
self.skip_white();
let key = ident;
- self.feedback.decorations.push(
- Spanned::new(Decoration::ArgumentKey, key.span)
- );
+ self.feedback.decorations
+ .push(Spanned::new(Decoration::ArgumentKey, key.span));
let value = try_opt_or!(self.parse_expr(), {
self.expected("value");
@@ -399,9 +381,9 @@ impl FuncParser<'_> {
self.eat_span(Expr::Str(unescape_string(string)))
}
+ Token::ExprBool(b) => self.eat_span(Expr::Bool(b)),
Token::ExprNumber(n) => self.eat_span(Expr::Number(n)),
Token::ExprLength(s) => self.eat_span(Expr::Length(s)),
- Token::ExprBool(b) => self.eat_span(Expr::Bool(b)),
Token::ExprHex(s) => {
if let Ok(color) = RgbaColor::from_str(s) {
self.eat_span(Expr::Color(color))
@@ -411,7 +393,7 @@ impl FuncParser<'_> {
let healed = RgbaColor::new_healed(0, 0, 0, 255);
self.eat_span(Expr::Color(healed))
}
- },
+ }
// This could be a tuple or a parenthesized expression. We parse as
// a tuple in any case and coerce the tuple into a value if it is
@@ -500,9 +482,8 @@ impl FuncParser<'_> {
continue;
}
- self.feedback.decorations.push(
- Spanned::new(Decoration::ObjectKey, key.span)
- );
+ self.feedback.decorations
+ .push(Spanned::new(Decoration::ObjectKey, key.span));
self.skip_white();
let value = try_opt_or!(self.parse_expr(), {
@@ -622,7 +603,8 @@ impl<'s> FuncParser<'s> {
}
fn pos(&self) -> Pos {
- self.peeked.flatten()
+ self.peeked
+ .flatten()
.map(|s| s.span.start)
.unwrap_or_else(|| self.tokens.pos())
}
@@ -687,10 +669,10 @@ mod tests {
use super::*;
use Decoration::*;
- use Expr::{Number as Num, Length as Len, Bool};
+ use Expr::{Bool, Length as Len, Number as Num};
use SyntaxNode::{
- Space as S, ToggleItalic as Italic, ToggleBolder as Bold,
- Parbreak, Linebreak,
+ Space as S, Parbreak, Linebreak, ToggleItalic as Italic,
+ ToggleBolder as Bold,
};
/// Test whether the given string parses into
@@ -882,7 +864,7 @@ mod tests {
p!("🌎\n*/[n]" =>
[(0:0, 0:1, T("🌎")), (0:1, 1:0, S), (1:2, 1:5, func!((0:1, 0:2, "n")))],
[(1:0, 1:2, "unexpected end of block comment")],
- [(1:3, 1:4, ValidFuncName)],
+ [(1:3, 1:4, ResolvedFunc)],
);
}
@@ -905,12 +887,12 @@ mod tests {
p!("[hi]" =>
[func!("hi")],
[(0:1, 0:3, "unknown function")],
- [(0:1, 0:3, InvalidFuncName)],
+ [(0:1, 0:3, UnresolvedFunc)],
);
// A valid name.
- p!("[f]" => [func!("f")], [], [(0:1, 0:2, ValidFuncName)]);
- p!("[ f]" => [func!("f")], [], [(0:3, 0:4, ValidFuncName)]);
+ p!("[f]" => [func!("f")], [], [(0:1, 0:2, ResolvedFunc)]);
+ p!("[ f]" => [func!("f")], [], [(0:3, 0:4, ResolvedFunc)]);
// An invalid token for a name.
p!("[12]" => [func!("")], [(0:1, 0:3, "expected function name, found number")], []);
@@ -923,7 +905,7 @@ mod tests {
// Valid.
p!("[val: true]" =>
[func!["val": (Bool(true))]], [],
- [(0:1, 0:4, ValidFuncName)],
+ [(0:1, 0:4, ResolvedFunc)],
);
// No colon before arg.
@@ -936,7 +918,7 @@ mod tests {
p!("[val/🌎:$]" =>
[func!("val")],
[(0:4, 0:4, "expected colon")],
- [(0:1, 0:4, ValidFuncName)],
+ [(0:1, 0:4, ResolvedFunc)],
);
// String in invalid header without colon still parsed as string
@@ -1159,20 +1141,20 @@ mod tests {
// Correct
p!("[val: x=true]" =>
[func!("val": (), { "x" => Bool(true) })], [],
- [(0:6, 0:7, ArgumentKey), (0:1, 0:4, ValidFuncName)],
+ [(0:6, 0:7, ArgumentKey), (0:1, 0:4, ResolvedFunc)],
);
// Spacing around keyword arguments
p!("\n [val: \n hi \n = /* //\n */ \"s\n\"]" =>
[S, func!("val": (), { "hi" => Str("s\n") })], [],
- [(2:1, 2:3, ArgumentKey), (1:2, 1:5, ValidFuncName)],
+ [(2:1, 2:3, ArgumentKey), (1:2, 1:5, ResolvedFunc)],
);
// Missing value
p!("[val: x=]" =>
[func!("val")],
[(0:8, 0:8, "expected value")],
- [(0:6, 0:7, ArgumentKey), (0:1, 0:4, ValidFuncName)],
+ [(0:6, 0:7, ArgumentKey), (0:1, 0:4, ResolvedFunc)],
);
}
@@ -1180,7 +1162,7 @@ mod tests {
fn parse_multiple_mixed_arguments() {
p!("[val: 12pt, key=value]" =>
[func!("val": (Len(Length::pt(12.0))), { "key" => Id("value") })], [],
- [(0:12, 0:15, ArgumentKey), (0:1, 0:4, ValidFuncName)],
+ [(0:12, 0:15, ArgumentKey), (0:1, 0:4, ResolvedFunc)],
);
pval!("a , x=\"b\" , c" => (Id("a"), Id("c")), { "x" => Str("b") });
}
@@ -1197,7 +1179,7 @@ mod tests {
p!("[val: [hi]]" =>
[func!("val")],
[(0:6, 0:10, "expected argument, found function")],
- [(0:1, 0:4, ValidFuncName)],
+ [(0:1, 0:4, ResolvedFunc)],
);
}
@@ -1208,7 +1190,7 @@ mod tests {
[func!("val": (Bool(true), Id("you")), {})],
[(0:10, 0:10, "expected comma"),
(0:10, 0:11, "expected argument, found equals sign")],
- [(0:1, 0:4, ValidFuncName)],
+ [(0:1, 0:4, ResolvedFunc)],
);
// Unexpected equals.
@@ -1223,14 +1205,14 @@ mod tests {
[func!("val": (Id("key"), Num(12.0)), {})],
[(0:9, 0:9, "expected comma"),
(0:9, 0:10, "expected argument, found colon")],
- [(0:1, 0:4, ValidFuncName)],
+ [(0:1, 0:4, ResolvedFunc)],
);
// Invalid colon after unkeyable positional argument.
p!("[val: true:12]" => [func!("val": (Bool(true), Num(12.0)), {})],
[(0:10, 0:10, "expected comma"),
(0:10, 0:11, "expected argument, found colon")],
- [(0:1, 0:4, ValidFuncName)],
+ [(0:1, 0:4, ResolvedFunc)],
);
}
@@ -1274,13 +1256,13 @@ mod tests {
// Space before function
p!(" [val]" =>
[(0:0, 0:1, S), (0:1, 0:6, func!((0:1, 0:4, "val")))], [],
- [(0:2, 0:5, ValidFuncName)],
+ [(0:2, 0:5, ResolvedFunc)],
);
// Newline before function
p!(" \n\r\n[val]" =>
[(0:0, 2:0, Parbreak), (2:0, 2:5, func!((0:1, 0:4, "val")))], [],
- [(2:1, 2:4, ValidFuncName)],
+ [(2:1, 2:4, ResolvedFunc)],
);
// Content before function
@@ -1293,7 +1275,7 @@ mod tests {
(0:19, 0:20, T("🌎"))
],
[],
- [(0:7, 0:10, ValidFuncName)],
+ [(0:7, 0:10, ResolvedFunc)],
);
// Nested function
@@ -1308,7 +1290,7 @@ mod tests {
]))
],
[],
- [(0:2, 0:5, ValidFuncName), (1:6, 1:9, ValidFuncName)],
+ [(0:2, 0:5, ResolvedFunc), (1:6, 1:9, ResolvedFunc)],
);
}
}
diff --git a/src/syntax/scope.rs b/src/syntax/scope.rs
index 8fdad6a0..aac2b1b8 100644
--- a/src/syntax/scope.rs
+++ b/src/syntax/scope.rs
@@ -1,4 +1,4 @@
-//! Scopes containing function parsers.
+//! Mapping of function names to function parsers.
use std::collections::HashMap;
use std::fmt::{self, Debug, Formatter};
@@ -15,33 +15,31 @@ pub struct Scope {
impl Scope {
/// Create a new empty scope with a fallback parser that is invoked when no
/// match is found.
- pub fn new<F>() -> Scope
- where F: ParseCall<Meta=()> + DynamicNode + 'static {
- Scope {
+ pub fn new<F>() -> Self
+ where
+ F: ParseCall<Meta = ()> + DynamicNode + 'static
+ {
+ Self {
parsers: HashMap::new(),
fallback: make_parser::<F>(()),
}
}
- /// Create a new scope with the standard functions contained.
- pub fn with_std() -> Scope {
- crate::library::std()
- }
-
- /// Associate the given name with a type that is parseable into a function.
+ /// Associate the given function name with a dynamic node type.
pub fn add<F>(&mut self, name: &str)
- where F: ParseCall<Meta=()> + DynamicNode + 'static {
+ where
+ F: ParseCall<Meta = ()> + DynamicNode + 'static
+ {
self.add_with_meta::<F>(name, ());
}
- /// Add a parseable type with additional metadata that is given to the
- /// parser (other than the default of `()`).
+ /// Add a dynamic node type with additional metadata that is passed to the
+ /// parser.
pub fn add_with_meta<F>(&mut self, name: &str, metadata: <F as ParseCall>::Meta)
- where F: ParseCall + DynamicNode + 'static {
- self.parsers.insert(
- name.to_string(),
- make_parser::<F>(metadata),
- );
+ where
+ F: ParseCall + DynamicNode + 'static
+ {
+ self.parsers.insert(name.to_string(), make_parser::<F>(metadata));
}
/// Return the parser with the given name if there is one.
@@ -57,14 +55,14 @@ impl Scope {
impl Debug for Scope {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- f.debug_set()
- .entries(self.parsers.keys())
- .finish()
+ f.debug_set().entries(self.parsers.keys()).finish()
}
}
fn make_parser<F>(metadata: <F as ParseCall>::Meta) -> Box<CallParser>
-where F: ParseCall + DynamicNode + 'static {
+where
+ F: ParseCall + DynamicNode + 'static,
+{
Box::new(move |f, s| {
F::parse(f, s, metadata.clone())
.map(|tree| Box::new(tree) as Box<dyn DynamicNode>)
diff --git a/src/syntax/span.rs b/src/syntax/span.rs
index 9b3c7d24..af293718 100644
--- a/src/syntax/span.rs
+++ b/src/syntax/span.rs
@@ -36,13 +36,13 @@ pub struct Spanned<T> {
impl<T> Spanned<T> {
/// Create a new instance from a value and its span.
- pub fn new(v: T, span: Span) -> Spanned<T> {
- Spanned { v, span }
+ pub fn new(v: T, span: Span) -> Self {
+ Self { v, span }
}
/// Create a new instance from a value with the zero span.
- pub fn zero(v: T) -> Spanned<T> {
- Spanned { v, span: Span::ZERO }
+ pub fn zero(v: T) -> Self {
+ Self { v, span: Span::ZERO }
}
/// Access the value.
@@ -51,12 +51,12 @@ impl<T> Spanned<T> {
}
/// Map the value using a function while keeping the span.
- pub fn map<V, F>(self, f: F) -> Spanned<V> where F: FnOnce(T) -> V {
+ pub fn map<U>(self, f: impl FnOnce(T) -> U) -> Spanned<U> {
Spanned { v: f(self.v), span: self.span }
}
/// Maps the span while keeping the value.
- pub fn map_span<F>(mut self, f: F) -> Spanned<T> where F: FnOnce(Span) -> Span {
+ pub fn map_span(mut self, f: impl FnOnce(Span) -> Span) -> Self {
self.span = f(self.span);
self
}
@@ -91,35 +91,35 @@ pub struct Span {
impl Span {
/// The zero span.
- pub const ZERO: Span = Span { start: Pos::ZERO, end: Pos::ZERO };
+ pub const ZERO: Self = Self { start: Pos::ZERO, end: Pos::ZERO };
/// Create a new span from start and end positions.
- pub fn new(start: Pos, end: Pos) -> Span {
- Span { start, end }
+ pub fn new(start: Pos, end: Pos) -> Self {
+ Self { start, end }
}
/// Create a span including just a single position.
- pub fn at(pos: Pos) -> Span {
- Span { start: pos, end: pos }
+ pub fn at(pos: Pos) -> Self {
+ Self { start: pos, end: pos }
}
/// Create a new span with the earlier start and later end position.
- pub fn merge(a: Span, b: Span) -> Span {
- Span {
+ pub fn merge(a: Self, b: Self) -> Self {
+ Self {
start: a.start.min(b.start),
end: a.end.max(b.end),
}
}
/// Expand a span by merging it with another span.
- pub fn expand(&mut self, other: Span) {
- *self = Span::merge(*self, other)
+ pub fn expand(&mut self, other: Self) {
+ *self = Self::merge(*self, other)
}
}
impl Offset for Span {
fn offset(self, by: Pos) -> Self {
- Span {
+ Self {
start: self.start.offset(by),
end: self.end.offset(by),
}
@@ -144,31 +144,31 @@ pub struct Pos {
impl Pos {
/// The line 0, column 0 position.
- pub const ZERO: Pos = Pos { line: 0, column: 0 };
+ pub const ZERO: Self = Self { line: 0, column: 0 };
/// Create a new position from line and column.
- pub fn new(line: usize, column: usize) -> Pos {
- Pos { line, column }
+ pub fn new(line: usize, column: usize) -> Self {
+ Self { line, column }
}
}
impl Offset for Pos {
- fn offset(self, by: Pos) -> Self {
+ fn offset(self, by: Self) -> Self {
by + self
}
}
impl Add for Pos {
- type Output = Pos;
+ type Output = Self;
- fn add(self, rhs: Pos) -> Pos {
+ fn add(self, rhs: Self) -> Self {
if rhs.line == 0 {
- Pos {
+ Self {
line: self.line,
- column: self.column + rhs.column
+ column: self.column + rhs.column,
}
} else {
- Pos {
+ Self {
line: self.line + rhs.line,
column: rhs.column,
}
@@ -177,16 +177,16 @@ impl Add for Pos {
}
impl Sub for Pos {
- type Output = Pos;
+ type Output = Self;
- fn sub(self, rhs: Pos) -> Pos {
+ fn sub(self, rhs: Self) -> Self {
if self.line == rhs.line {
- Pos {
+ Self {
line: 0,
- column: self.column - rhs.column
+ column: self.column - rhs.column,
}
} else {
- Pos {
+ Self {
line: self.line - rhs.line,
column: self.column,
}
diff --git a/src/syntax/test.rs b/src/syntax/test.rs
index 504bc334..db7a2de2 100644
--- a/src/syntax/test.rs
+++ b/src/syntax/test.rs
@@ -2,15 +2,16 @@ use std::fmt::Debug;
use crate::func::parse_maybe_body;
use super::decoration::Decoration;
-use super::expr::{Expr, Ident, Tuple, NamedTuple, Object, Pair};
-use super::parsing::{FuncHeader, FuncArgs, FuncArg};
+use super::expr::{Expr, Ident, NamedTuple, Object, Pair, Tuple};
+use super::parsing::{FuncArg, FuncArgs, FuncHeader};
use super::span::Spanned;
use super::tokens::Token;
-use super::tree::{SyntaxTree, SyntaxNode, DynamicNode};
+use super::tree::{DynamicNode, SyntaxNode, SyntaxTree};
-/// Check whether the expected and found results are the same.
pub fn check<T>(src: &str, exp: T, found: T, cmp_spans: bool)
-where T: Debug + PartialEq + SpanlessEq {
+where
+ T: Debug + PartialEq + SpanlessEq,
+{
let cmp = if cmp_spans { PartialEq::eq } else { SpanlessEq::spanless_eq };
if !cmp(&exp, &found) {
println!("source: {:?}", src);
@@ -41,7 +42,7 @@ macro_rules! span_vec {
}
macro_rules! span_item {
- (($sl:tt:$sc:tt, $el:tt:$ec:tt, $v:expr)) => ({
+ (($sl:tt:$sc:tt, $el:tt:$ec:tt, $v:expr)) => {{
use $crate::syntax::span::{Pos, Span, Spanned};
Spanned {
span: Span::new(
@@ -50,7 +51,7 @@ macro_rules! span_item {
),
v: $v
}
- });
+ }};
($v:expr) => {
$crate::syntax::span::Spanned::zero($v)
@@ -70,7 +71,7 @@ function! {
let cloned = header.clone();
header.args.pos.0.clear();
header.args.key.0.clear();
- DebugFn {
+ Self {
header: cloned,
body: parse_maybe_body(body, state, f),
}
@@ -80,7 +81,7 @@ function! {
}
/// Compares elements by only looking at values and ignoring spans.
-pub trait SpanlessEq<Rhs=Self> {
+pub trait SpanlessEq<Rhs = Self> {
fn spanless_eq(&self, other: &Rhs) -> bool;
}
@@ -102,20 +103,21 @@ impl SpanlessEq for SyntaxNode {
impl SpanlessEq for DebugFn {
fn spanless_eq(&self, other: &DebugFn) -> bool {
self.header.spanless_eq(&other.header)
- && self.body.spanless_eq(&other.body)
+ && self.body.spanless_eq(&other.body)
}
}
impl SpanlessEq for FuncHeader {
fn spanless_eq(&self, other: &Self) -> bool {
- self.name.spanless_eq(&other.name) && self.args.spanless_eq(&other.args)
+ self.name.spanless_eq(&other.name)
+ && self.args.spanless_eq(&other.args)
}
}
impl SpanlessEq for FuncArgs {
fn spanless_eq(&self, other: &Self) -> bool {
self.key.spanless_eq(&other.key)
- && self.pos.spanless_eq(&other.pos)
+ && self.pos.spanless_eq(&other.pos)
}
}
@@ -154,7 +156,7 @@ impl SpanlessEq for Tuple {
impl SpanlessEq for NamedTuple {
fn spanless_eq(&self, other: &NamedTuple) -> bool {
self.name.v == other.name.v
- && self.tuple.v.spanless_eq(&other.tuple.v)
+ && self.tuple.v.spanless_eq(&other.tuple.v)
}
}
@@ -173,7 +175,7 @@ impl SpanlessEq for Pair {
impl<T: SpanlessEq> SpanlessEq for Vec<T> {
fn spanless_eq(&self, other: &Vec<T>) -> bool {
self.len() == other.len()
- && self.iter().zip(other).all(|(x, y)| x.spanless_eq(&y))
+ && self.iter().zip(other).all(|(x, y)| x.spanless_eq(&y))
}
}
diff --git a/src/syntax/tokens.rs b/src/syntax/tokens.rs
index 1ea11449..ef249471 100644
--- a/src/syntax/tokens.rs
+++ b/src/syntax/tokens.rs
@@ -9,7 +9,6 @@ use super::span::{Pos, Span, Spanned};
use Token::*;
use TokenMode::*;
-
/// A minimal semantic entity of source code.
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum Token<'s> {
@@ -71,14 +70,14 @@ pub enum Token<'s> {
/// a String. The escaping is done later in the parser.
string: &'s str,
/// Whether the closing quote was present.
- terminated: bool
+ terminated: bool,
},
+ /// A boolean in a function header: `true | false`.
+ ExprBool(bool),
/// A number in a function header: `3.14`.
ExprNumber(f64),
/// A length in a function header: `12pt`.
ExprLength(Length),
- /// A boolean in a function header: `true | false`.
- ExprBool(bool),
/// A hex value in a function header: `#20d82a`.
ExprHex(&'s str),
/// A plus in a function header, signifying the addition of expressions.
@@ -130,9 +129,9 @@ impl<'s> Token<'s> {
Equals => "equals sign",
ExprIdent(_) => "identifier",
ExprStr { .. } => "string",
+ ExprBool(_) => "bool",
ExprNumber(_) => "number",
ExprLength(_) => "length",
- ExprBool(_) => "bool",
ExprHex(_) => "hex value",
Plus => "plus",
Hyphen => "minus",
@@ -173,8 +172,8 @@ impl<'s> Tokens<'s> {
///
/// The first token's span starts an the given `offset` position instead of
/// the zero position.
- pub fn new(src: &'s str, offset: Pos, mode: TokenMode) -> Tokens<'s> {
- Tokens {
+ pub fn new(src: &'s str, offset: Pos, mode: TokenMode) -> Self {
+ Self {
src,
mode,
iter: src.chars().peekable(),
@@ -200,7 +199,7 @@ impl<'s> Iterator for Tokens<'s> {
type Item = Spanned<Token<'s>>;
/// Parse the next token in the source code.
- fn next(&mut self) -> Option<Spanned<Token<'s>>> {
+ fn next(&mut self) -> Option<Self::Item> {
let start = self.pos();
let first = self.eat()?;
@@ -366,7 +365,7 @@ impl<'s> Tokens<'s> {
}
let end = self.index();
- (&self.src[start .. end], terminated)
+ (&self.src[start..end], terminated)
}
fn read_string(&mut self) -> Token<'s> {
@@ -404,7 +403,7 @@ impl<'s> Tokens<'s> {
Some(c) if is_escapable(c) => {
let index = self.index();
self.eat();
- Text(&self.src[index .. index + c.len_utf8()])
+ Text(&self.src[index..index + c.len_utf8()])
}
Some(c) if c.is_whitespace() => Backslash,
Some(_) => Text("\\"),
@@ -442,13 +441,13 @@ impl<'s> Tokens<'s> {
/// Returns the string from the index where this was called offset by
/// `offset_start` to the end offset by `offset_end`. The end is before or
/// after the match depending on `eat_match`.
- fn read_string_until<F>(
+ fn read_string_until(
&mut self,
- mut f: F,
+ mut f: impl FnMut(char) -> bool,
eat_match: bool,
offset_start: isize,
offset_end: isize,
- ) -> (&'s str, bool) where F: FnMut(char) -> bool {
+ ) -> (&'s str, bool) {
let start = ((self.index() as isize) + offset_start) as usize;
let mut matched = false;
@@ -469,7 +468,7 @@ impl<'s> Tokens<'s> {
end = ((end as isize) + offset_end) as usize;
}
- (&self.src[start .. end], matched)
+ (&self.src[start..end], matched)
}
fn eat(&mut self) -> Option<char> {
@@ -493,7 +492,7 @@ impl<'s> Tokens<'s> {
fn parse_percentage(text: &str) -> Option<f64> {
if text.ends_with('%') {
- text[.. text.len() - 1].parse::<f64>().ok()
+ text[..text.len() - 1].parse::<f64>().ok()
} else {
None
}
@@ -503,7 +502,7 @@ fn parse_percentage(text: &str) -> Option<f64> {
pub fn is_newline_char(character: char) -> bool {
match character {
// Line Feed, Vertical Tab, Form Feed, Carriage Return.
- '\x0A' ..= '\x0D' => true,
+ '\x0A'..='\x0D' => true,
// Next Line, Line Separator, Paragraph Separator.
'\u{0085}' | '\u{2028}' | '\u{2029}' => true,
_ => false,
@@ -544,15 +543,15 @@ mod tests {
LeftParen as LP, RightParen as RP,
LeftBrace as LB, RightBrace as RB,
ExprIdent as Id,
+ ExprBool as Bool,
ExprNumber as Num,
ExprLength as Len,
- ExprBool as Bool,
ExprHex as Hex,
- Text as T,
Plus,
Hyphen as Min,
- Star,
Slash,
+ Star,
+ Text as T,
};
/// Test whether the given string tokenizes into the given list of tokens.
diff --git a/src/syntax/tree.rs b/src/syntax/tree.rs
index 41a03fae..28997e7c 100644
--- a/src/syntax/tree.rs
+++ b/src/syntax/tree.rs
@@ -6,7 +6,7 @@ use std::fmt::Debug;
use crate::layout::Layout;
use super::span::SpanVec;
-/// A list of nodes which forms a tree together with the nodes' children.
+/// A collection of nodes which form a tree together with the nodes' children.
pub type SyntaxTree = SpanVec<SyntaxNode>;
/// A syntax node, which encompasses a single logical entity of parsed source
@@ -27,7 +27,7 @@ pub enum SyntaxNode {
ToggleItalic,
/// Bolder was enabled / disabled.
ToggleBolder,
- /// A subtree, typically a function invocation.
+ /// A dynamic node, create through function invocations in source code.
Dyn(Box<dyn DynamicNode>),
}
@@ -65,13 +65,16 @@ pub trait DynamicNode: Debug + Layout {
impl dyn DynamicNode {
/// Downcast this dynamic node to a concrete node.
- pub fn downcast<N>(&self) -> Option<&N> where N: DynamicNode + 'static {
- self.as_any().downcast_ref::<N>()
+ pub fn downcast<T>(&self) -> Option<&T>
+ where
+ T: DynamicNode + 'static,
+ {
+ self.as_any().downcast_ref::<T>()
}
}
impl PartialEq for dyn DynamicNode {
- fn eq(&self, other: &dyn DynamicNode) -> bool {
+ fn eq(&self, other: &Self) -> bool {
self.dyn_eq(other)
}
}
@@ -82,7 +85,10 @@ impl Clone for Box<dyn DynamicNode> {
}
}
-impl<T> DynamicNode for T where T: Debug + PartialEq + Clone + Layout + 'static {
+impl<T> DynamicNode for T
+where
+ T: Debug + PartialEq + Clone + Layout + 'static,
+{
fn as_any(&self) -> &dyn Any {
self
}
diff --git a/src/syntax/value.rs b/src/syntax/value.rs
index 5c264ca0..b7211eaf 100644
--- a/src/syntax/value.rs
+++ b/src/syntax/value.rs
@@ -2,18 +2,20 @@
use fontdock::{FontStyle, FontWeight, FontWidth};
-use crate::Feedback;
use crate::layout::prelude::*;
use crate::length::{Length, ScaleLength};
use crate::paper::Paper;
-use super::span::Spanned;
+use crate::Feedback;
use super::expr::*;
+use super::span::Spanned;
/// Value types are used to extract values from functions, tuples and
/// objects. They represent the value part of an argument.
+///
+/// # Example
/// ```typst
-/// [func: value, key=value]
-/// ^^^^^ ^^^^^
+/// [func: 12pt, key="these are both values"]
+/// ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^
/// ```
pub trait Value: Sized {
/// Try to parse this value from an expression.
@@ -53,8 +55,8 @@ macro_rules! match_value {
match_value!(Expr, "expression", e => e);
match_value!(Ident, "identifier", Expr::Ident(i) => i);
match_value!(String, "string", Expr::Str(s) => s);
-match_value!(f64, "number", Expr::Number(n) => n);
match_value!(bool, "bool", Expr::Bool(b) => b);
+match_value!(f64, "number", Expr::Number(n) => n);
match_value!(Length, "length", Expr::Length(l) => l);
match_value!(Tuple, "tuple", Expr::Tuple(t) => t);
match_value!(Object, "object", Expr::Object(o) => o);
@@ -63,7 +65,7 @@ match_value!(ScaleLength, "number or length",
Expr::Number(scale) => ScaleLength::Scaled(scale),
);
-/// A value type that matches [`Expr::Ident`] and [`Expr::Str`] and implements
+/// A value type that matches identifiers and strings and implements
/// `Into<String>`.
pub struct StringLike(pub String);
@@ -101,7 +103,7 @@ macro_rules! ident_value {
}
ident_value!(Dir, "direction", |s| match s {
- "ltr" => Some(LTT),
+ "ltr" => Some(LTR),
"rtl" => Some(RTL),
"ttb" => Some(TTB),
"btt" => Some(BTT),
@@ -109,11 +111,11 @@ ident_value!(Dir, "direction", |s| match s {
});
ident_value!(SpecAlign, "alignment", |s| match s {
- "left" => Some(SpecAlign::Left),
- "right" => Some(SpecAlign::Right),
- "top" => Some(SpecAlign::Top),
- "bottom" => Some(SpecAlign::Bottom),
- "center" => Some(SpecAlign::Center),
+ "left" => Some(Self::Left),
+ "right" => Some(Self::Right),
+ "top" => Some(Self::Top),
+ "bottom" => Some(Self::Bottom),
+ "center" => Some(Self::Center),
_ => None,
});
@@ -127,7 +129,7 @@ impl Value for FontWeight {
const MIN: u16 = 100;
const MAX: u16 = 900;
- Some(FontWeight(if weight < MIN as f64 {
+ Some(Self(if weight < MIN as f64 {
error!(@f, expr.span, "the minimum font weight is {}", MIN);
MIN
} else if weight > MAX as f64 {
@@ -163,7 +165,7 @@ impl Value for FontWidth {
const MIN: u16 = 1;
const MAX: u16 = 9;
- FontWidth::new(if width < MIN as f64 {
+ Self::new(if width < MIN as f64 {
error!(@f, expr.span, "the minimum font width is {}", MIN);
MIN
} else if width > MAX as f64 {