summaryrefslogtreecommitdiff
path: root/src/parse
diff options
context:
space:
mode:
Diffstat (limited to 'src/parse')
-rw-r--r--src/parse/mod.rs148
-rw-r--r--src/parse/resolve.rs8
-rw-r--r--src/parse/tests.rs160
3 files changed, 173 insertions, 143 deletions
diff --git a/src/parse/mod.rs b/src/parse/mod.rs
index 75ca7eb4..7a0002d6 100644
--- a/src/parse/mod.rs
+++ b/src/parse/mod.rs
@@ -12,14 +12,13 @@ pub use tokens::*;
use std::str::FromStr;
-use super::*;
use crate::color::RgbaColor;
-use crate::compute::dict::SpannedEntry;
+use crate::compute::dict::DictKey;
use crate::syntax::*;
use crate::{Feedback, Pass};
/// Parse a string of source code.
-pub fn parse(src: &str) -> Pass<SyntaxTree> {
+pub fn parse(src: &str) -> Pass<SynTree> {
Parser::new(src).parse()
}
@@ -42,7 +41,7 @@ impl<'s> Parser<'s> {
}
}
- fn parse(mut self) -> Pass<SyntaxTree> {
+ fn parse(mut self) -> Pass<SynTree> {
let tree = self.parse_body_contents();
Pass::new(tree, self.feedback)
}
@@ -50,8 +49,8 @@ impl<'s> Parser<'s> {
// Typesetting content.
impl Parser<'_> {
- fn parse_body_contents(&mut self) -> SyntaxTree {
- let mut tree = SyntaxTree::new();
+ fn parse_body_contents(&mut self) -> SynTree {
+ let mut tree = SynTree::new();
self.at_block_or_line_start = true;
while !self.eof() {
@@ -63,7 +62,7 @@ impl Parser<'_> {
tree
}
- fn parse_node(&mut self) -> Option<Spanned<SyntaxNode>> {
+ fn parse_node(&mut self) -> Option<Spanned<SynNode>> {
let token = self.peek()?;
let end = Span::at(token.span.end);
@@ -83,11 +82,7 @@ impl Parser<'_> {
self.at_block_or_line_start = true;
}
- self.with_span(if n >= 2 {
- SyntaxNode::Parbreak
- } else {
- SyntaxNode::Spacing
- })
+ self.with_span(if n >= 2 { SynNode::Parbreak } else { SynNode::Spacing })
}
Token::LineComment(_) | Token::BlockComment(_) => {
@@ -99,15 +94,15 @@ impl Parser<'_> {
Token::LeftBracket => {
let call = self.parse_bracket_call(false);
self.at_block_or_line_start = false;
- call.map(SyntaxNode::Call)
+ call.map(|c| SynNode::Expr(Expr::Call(c)))
}
- Token::Star => self.with_span(SyntaxNode::ToggleBolder),
- Token::Underscore => self.with_span(SyntaxNode::ToggleItalic),
- Token::Backslash => self.with_span(SyntaxNode::Linebreak),
+ Token::Star => self.with_span(SynNode::ToggleBolder),
+ Token::Underscore => self.with_span(SynNode::ToggleItalic),
+ Token::Backslash => self.with_span(SynNode::Linebreak),
Token::Hashtag if was_at_block_or_line_start => {
- self.parse_heading().map(SyntaxNode::Heading)
+ self.parse_heading().map(SynNode::Heading)
}
Token::Raw { raw, backticks, terminated } => {
@@ -116,11 +111,11 @@ impl Parser<'_> {
}
let raw = resolve::resolve_raw(raw, backticks);
- self.with_span(SyntaxNode::Raw(raw))
+ self.with_span(SynNode::Raw(raw))
}
- Token::Text(text) => self.with_span(SyntaxNode::Text(text.to_string())),
- Token::Hashtag => self.with_span(SyntaxNode::Text("#".to_string())),
+ Token::Text(text) => self.with_span(SynNode::Text(text.to_string())),
+ Token::Hashtag => self.with_span(SynNode::Text("#".to_string())),
Token::UnicodeEscape { sequence, terminated } => {
if !terminated {
@@ -128,7 +123,7 @@ impl Parser<'_> {
}
if let Some(c) = resolve::resolve_hex(sequence) {
- self.with_span(SyntaxNode::Text(c.to_string()))
+ self.with_span(SynNode::Text(c.to_string()))
} else {
error!(@self.feedback, token.span, "invalid unicode escape sequence");
// TODO: Decide whether to render the escape sequence.
@@ -145,7 +140,7 @@ impl Parser<'_> {
})
}
- fn parse_heading(&mut self) -> Spanned<Heading> {
+ fn parse_heading(&mut self) -> Spanned<NodeHeading> {
let start = self.pos();
self.assert(Token::Hashtag);
@@ -167,7 +162,7 @@ impl Parser<'_> {
self.skip_ws();
- let mut tree = SyntaxTree::new();
+ let mut tree = SynTree::new();
while !self.eof() && !matches!(self.peekv(), Some(Token::Space(n)) if n >= 1) {
if let Some(node) = self.parse_node() {
tree.push(node);
@@ -175,13 +170,13 @@ impl Parser<'_> {
}
let span = Span::new(start, self.pos());
- Heading { level, tree }.span_with(span)
+ NodeHeading { level, contents: tree }.span_with(span)
}
}
// Function calls.
impl Parser<'_> {
- fn parse_bracket_call(&mut self, chained: bool) -> Spanned<CallExpr> {
+ fn parse_bracket_call(&mut self, chained: bool) -> Spanned<ExprCall> {
let before_bracket = self.pos();
if !chained {
self.start_group(Group::Bracket);
@@ -203,9 +198,9 @@ impl Parser<'_> {
Some(_) => {
self.expected_at("colon", name.span.end);
while self.eat().is_some() {}
- DictExpr::new()
+ LitDict::default()
}
- None => DictExpr::new(),
+ None => LitDict::default(),
};
self.end_group();
@@ -213,8 +208,9 @@ impl Parser<'_> {
let (has_chained_child, end) = if self.peek().is_some() {
let item = self.parse_bracket_call(true);
let span = item.span;
- let t = vec![item.map(SyntaxNode::Call)];
- args.push(SpannedEntry::val(Expr::Tree(t).span_with(span)));
+ let tree = vec![item.map(|c| SynNode::Expr(Expr::Call(c)))];
+ let expr = Expr::Lit(Lit::Content(tree));
+ args.0.push(LitDictEntry { key: None, value: expr.span_with(span) });
(true, span.end)
} else {
self.tokens.pop_mode();
@@ -227,40 +223,41 @@ impl Parser<'_> {
if self.check(Token::LeftBracket) && !has_chained_child {
self.start_group(Group::Bracket);
self.tokens.push_mode(TokenMode::Body);
-
let body = self.parse_body_contents();
-
self.tokens.pop_mode();
let body_span = self.end_group();
- let expr = Expr::Tree(body);
- args.push(SpannedEntry::val(expr.span_with(body_span)));
+ let expr = Expr::Lit(Lit::Content(body));
+ args.0.push(LitDictEntry {
+ key: None,
+ value: expr.span_with(body_span),
+ });
span.expand(body_span);
}
- CallExpr { name, args }.span_with(span)
+ ExprCall { name, args }.span_with(span)
}
- fn parse_paren_call(&mut self, name: Spanned<Ident>) -> Spanned<CallExpr> {
+ fn parse_paren_call(&mut self, name: Spanned<Ident>) -> Spanned<ExprCall> {
self.start_group(Group::Paren);
let args = self.parse_dict_contents().0;
let args_span = self.end_group();
let span = Span::merge(name.span, args_span);
- CallExpr { name, args }.span_with(span)
+ ExprCall { name, args }.span_with(span)
}
}
// Dicts.
impl Parser<'_> {
- fn parse_dict_contents(&mut self) -> (DictExpr, bool) {
- let mut dict = DictExpr::new();
+ fn parse_dict_contents(&mut self) -> (LitDict, bool) {
+ let mut dict = LitDict::default();
let mut comma_and_keyless = true;
while {
self.skip_ws();
!self.eof()
} {
- let (key, val) = if let Some(ident) = self.parse_ident() {
+ let (key, value) = if let Some(ident) = self.parse_ident() {
self.skip_ws();
match self.peekv() {
@@ -268,7 +265,7 @@ impl Parser<'_> {
self.eat();
self.skip_ws();
if let Some(value) = self.parse_expr() {
- (Some(ident), value)
+ (Some(ident.map(|id| DictKey::Str(id.0))), value)
} else {
self.expected("value");
continue;
@@ -280,7 +277,7 @@ impl Parser<'_> {
(None, call.map(Expr::Call))
}
- _ => (None, ident.map(Expr::Ident)),
+ _ => (None, ident.map(|id| Expr::Lit(Lit::Ident(id)))),
}
} else if let Some(value) = self.parse_expr() {
(None, value)
@@ -289,17 +286,16 @@ impl Parser<'_> {
continue;
};
- let behind = val.span.end;
- if let Some(key) = key {
+ if let Some(key) = &key {
comma_and_keyless = false;
- dict.insert(key.v.0, SpannedEntry::new(key.span, val));
self.feedback
.decorations
.push(Decoration::DictKey.span_with(key.span));
- } else {
- dict.push(SpannedEntry::val(val));
}
+ let behind = value.span.end;
+ dict.0.push(LitDictEntry { key, value });
+
if {
self.skip_ws();
self.eof()
@@ -311,27 +307,25 @@ impl Parser<'_> {
comma_and_keyless = false;
}
- let coercable = comma_and_keyless && !dict.is_empty();
+ let coercable = comma_and_keyless && !dict.0.is_empty();
(dict, coercable)
}
}
-type Binop = fn(Box<Spanned<Expr>>, Box<Spanned<Expr>>) -> Expr;
-
// Expressions and values.
impl Parser<'_> {
fn parse_expr(&mut self) -> Option<Spanned<Expr>> {
self.parse_binops("summand", Self::parse_term, |token| match token {
- Token::Plus => Some(Expr::Add),
- Token::Hyphen => Some(Expr::Sub),
+ Token::Plus => Some(BinOp::Add),
+ Token::Hyphen => Some(BinOp::Sub),
_ => None,
})
}
fn parse_term(&mut self) -> Option<Spanned<Expr>> {
self.parse_binops("factor", Self::parse_factor, |token| match token {
- Token::Star => Some(Expr::Mul),
- Token::Slash => Some(Expr::Div),
+ Token::Star => Some(BinOp::Mul),
+ Token::Slash => Some(BinOp::Div),
_ => None,
})
}
@@ -341,7 +335,7 @@ impl Parser<'_> {
&mut self,
operand_name: &str,
mut parse_operand: impl FnMut(&mut Self) -> Option<Spanned<Expr>>,
- mut parse_op: impl FnMut(Token) -> Option<Binop>,
+ mut parse_op: impl FnMut(Token) -> Option<BinOp>,
) -> Option<Spanned<Expr>> {
let mut left = parse_operand(self)?;
@@ -353,8 +347,12 @@ impl Parser<'_> {
if let Some(right) = parse_operand(self) {
let span = Span::merge(left.span, right.span);
- let v = op(Box::new(left), Box::new(right));
- left = v.span_with(span);
+ let expr = Expr::Binary(ExprBinary {
+ lhs: left.map(Box::new),
+ op: op.span_with(token.span),
+ rhs: right.map(Box::new),
+ });
+ left = expr.span_with(span);
self.skip_ws();
continue;
}
@@ -375,7 +373,11 @@ impl Parser<'_> {
self.skip_ws();
if let Some(factor) = self.parse_factor() {
let span = Span::merge(hyph.span, factor.span);
- Some(Expr::Neg(Box::new(factor)).span_with(span))
+ let expr = Expr::Unary(ExprUnary {
+ op: UnOp::Neg.span_with(hyph.span),
+ expr: factor.map(Box::new),
+ });
+ Some(expr.span_with(span))
} else {
error!(@self.feedback, hyph.span, "dangling minus");
None
@@ -396,7 +398,7 @@ impl Parser<'_> {
if self.check(Token::LeftParen) {
self.parse_paren_call(name).map(Expr::Call)
} else {
- name.map(Expr::Ident)
+ name.map(|n| Expr::Lit(Lit::Ident(n)))
}
}
@@ -404,21 +406,19 @@ impl Parser<'_> {
if !terminated {
self.expected_at("quote", span.end);
}
- self.with_span(Expr::Str(resolve::resolve_string(string)))
+ self.with_span(Expr::Lit(Lit::Str(resolve::resolve_string(string))))
}
- Token::Bool(b) => self.with_span(Expr::Bool(b)),
- Token::Number(n) => self.with_span(Expr::Number(n)),
- Token::Length(s) => self.with_span(Expr::Length(s)),
+ Token::Bool(b) => self.with_span(Expr::Lit(Lit::Bool(b))),
+ Token::Number(n) => self.with_span(Expr::Lit(Lit::Float(n))),
+ Token::Length(s) => self.with_span(Expr::Lit(Lit::Length(s))),
Token::Hex(s) => {
- if let Ok(color) = RgbaColor::from_str(s) {
- self.with_span(Expr::Color(color))
- } else {
+ let color = RgbaColor::from_str(s).unwrap_or_else(|_| {
// Heal color by assuming black.
error!(@self.feedback, span, "invalid color");
- let healed = RgbaColor::new_healed(0, 0, 0, 255);
- self.with_span(Expr::Color(healed))
- }
+ RgbaColor::new_healed(0, 0, 0, 255)
+ });
+ self.with_span(Expr::Lit(Lit::Color(color)))
}
// This could be a dictionary or a parenthesized expression. We
@@ -430,9 +430,9 @@ impl Parser<'_> {
let span = self.end_group();
let expr = if coercable {
- dict.into_values().next().expect("dict is coercable").val.v
+ dict.0.into_iter().next().expect("dict is coercable").value.v
} else {
- Expr::Dict(dict)
+ Expr::Lit(Lit::Dict(dict))
};
expr.span_with(span)
@@ -442,19 +442,17 @@ impl Parser<'_> {
Token::LeftBrace => {
self.start_group(Group::Brace);
self.tokens.push_mode(TokenMode::Body);
-
let tree = self.parse_body_contents();
-
self.tokens.pop_mode();
let span = self.end_group();
- Expr::Tree(tree).span_with(span)
+ Expr::Lit(Lit::Content(tree)).span_with(span)
}
// This is a bracketed function call.
Token::LeftBracket => {
let call = self.parse_bracket_call(false);
- let tree = vec![call.map(SyntaxNode::Call)];
- Expr::Tree(tree).span_with(span)
+ let tree = vec![call.map(|c| SynNode::Expr(Expr::Call(c)))];
+ Expr::Lit(Lit::Content(tree)).span_with(span)
}
_ => return None,
diff --git a/src/parse/resolve.rs b/src/parse/resolve.rs
index d4babd25..f9919373 100644
--- a/src/parse/resolve.rs
+++ b/src/parse/resolve.rs
@@ -1,7 +1,7 @@
//! Resolve strings and raw blocks.
use super::{is_newline, Scanner};
-use crate::syntax::{Ident, Raw};
+use crate::syntax::{Ident, NodeRaw};
/// Resolves all escape sequences in a string.
pub fn resolve_string(string: &str) -> String {
@@ -49,17 +49,17 @@ pub fn resolve_hex(sequence: &str) -> Option<char> {
}
/// Resolves the language tag and trims the raw text.
-pub fn resolve_raw(raw: &str, backticks: usize) -> Raw {
+pub fn resolve_raw(raw: &str, backticks: usize) -> NodeRaw {
if backticks > 1 {
let (tag, inner) = split_at_lang_tag(raw);
let (lines, had_newline) = trim_and_split_raw(inner);
- Raw {
+ NodeRaw {
lang: Ident::new(tag),
lines,
inline: !had_newline,
}
} else {
- Raw {
+ NodeRaw {
lang: None,
lines: split_lines(raw),
inline: true,
diff --git a/src/parse/tests.rs b/src/parse/tests.rs
index e516af32..302e93ee 100644
--- a/src/parse/tests.rs
+++ b/src/parse/tests.rs
@@ -6,33 +6,33 @@ use std::fmt::Debug;
use super::parse;
use crate::color::RgbaColor;
-use crate::compute::dict::SpannedEntry;
+use crate::compute::dict::DictKey;
use crate::length::Length;
use crate::syntax::*;
// ------------------------------ Construct Syntax Nodes ------------------------------ //
use Decoration::*;
-use SyntaxNode::{
+use SynNode::{
Linebreak as L, Parbreak as P, Spacing as S, ToggleBolder as B, ToggleItalic as I,
};
-fn T(text: &str) -> SyntaxNode {
- SyntaxNode::Text(text.to_string())
+fn T(text: &str) -> SynNode {
+ SynNode::Text(text.to_string())
}
macro_rules! H {
($level:expr, $($tts:tt)*) => {
- SyntaxNode::Heading(Heading {
+ SynNode::Heading(NodeHeading {
level: Spanned::zero($level),
- tree: Tree![@$($tts)*],
+ contents: Tree![@$($tts)*],
})
};
}
macro_rules! R {
($lang:expr, $inline:expr, $($line:expr),* $(,)?) => {{
- SyntaxNode::Raw(Raw {
+ SynNode::Raw(NodeRaw {
lang: $lang,
lines: vec![$($line.to_string()) ,*],
inline: $inline,
@@ -45,53 +45,73 @@ fn Lang(lang: &str) -> Option<Ident> {
}
macro_rules! F {
- ($($tts:tt)*) => { SyntaxNode::Call(Call!(@$($tts)*)) }
+ ($($tts:tt)*) => { SynNode::Expr(Expr::Call(Call!(@$($tts)*))) }
}
// ------------------------------- Construct Expressions ------------------------------ //
-use Expr::{Bool, Color, Length as Len, Number as Num};
+use BinOp::*;
+use UnOp::*;
fn Id(ident: &str) -> Expr {
- Expr::Ident(Ident(ident.to_string()))
+ Expr::Lit(Lit::Ident(Ident(ident.to_string())))
+}
+fn Bool(b: bool) -> Expr {
+ Expr::Lit(Lit::Bool(b))
+}
+fn _Int(int: i64) -> Expr {
+ Expr::Lit(Lit::Int(int))
+}
+fn Float(float: f64) -> Expr {
+ Expr::Lit(Lit::Float(float))
+}
+fn _Percent(percent: f64) -> Expr {
+ Expr::Lit(Lit::Percent(percent))
+}
+fn Len(length: Length) -> Expr {
+ Expr::Lit(Lit::Length(length))
+}
+fn Color(color: RgbaColor) -> Expr {
+ Expr::Lit(Lit::Color(color))
}
fn Str(string: &str) -> Expr {
- Expr::Str(string.to_string())
+ Expr::Lit(Lit::Str(string.to_string()))
}
macro_rules! Dict {
(@dict=$dict:expr,) => {};
(@dict=$dict:expr, $key:expr => $value:expr $(, $($tts:tt)*)?) => {{
let key = Into::<Spanned<&str>>::into($key);
- let val = Into::<Spanned<Expr>>::into($value);
- $dict.insert(key.v, SpannedEntry::new(key.span, val));
+ let key = key.map(Into::<DictKey>::into);
+ let value = Into::<Spanned<Expr>>::into($value);
+ $dict.0.push(LitDictEntry { key: Some(key), value });
Dict![@dict=$dict, $($($tts)*)?];
}};
(@dict=$dict:expr, $value:expr $(, $($tts:tt)*)?) => {
- let val = Into::<Spanned<Expr>>::into($value);
- $dict.push(SpannedEntry::val(val));
+ let value = Into::<Spanned<Expr>>::into($value);
+ $dict.0.push(LitDictEntry { key: None, value });
Dict![@dict=$dict, $($($tts)*)?];
};
(@$($tts:tt)*) => {{
#[allow(unused_mut)]
- let mut dict = DictExpr::new();
+ let mut dict = LitDict::default();
Dict![@dict=dict, $($tts)*];
dict
}};
- ($($tts:tt)*) => { Expr::Dict(Dict![@$($tts)*]) };
+ ($($tts:tt)*) => { Expr::Lit(Lit::Dict(Dict![@$($tts)*])) };
}
macro_rules! Tree {
(@$($node:expr),* $(,)?) => {
- vec![$(Into::<Spanned<SyntaxNode>>::into($node)),*]
+ vec![$(Into::<Spanned<SynNode>>::into($node)),*]
};
- ($($tts:tt)*) => { Expr::Tree(Tree![@$($tts)*]) };
+ ($($tts:tt)*) => { Expr::Lit(Lit::Content(Tree![@$($tts)*])) };
}
macro_rules! Call {
(@$name:expr $(; $($tts:tt)*)?) => {{
let name = Into::<Spanned<&str>>::into($name);
- CallExpr {
+ ExprCall {
name: name.map(|n| Ident(n.to_string())),
args: Dict![@$($($tts)*)?],
}
@@ -99,20 +119,22 @@ macro_rules! Call {
($($tts:tt)*) => { Expr::Call(Call![@$($tts)*]) };
}
-fn Neg<T: Into<Spanned<Expr>>>(e1: T) -> Expr {
- Expr::Neg(Box::new(e1.into()))
-}
-fn Add<T: Into<Spanned<Expr>>>(e1: T, e2: T) -> Expr {
- Expr::Add(Box::new(e1.into()), Box::new(e2.into()))
-}
-fn Sub<T: Into<Spanned<Expr>>>(e1: T, e2: T) -> Expr {
- Expr::Sub(Box::new(e1.into()), Box::new(e2.into()))
+fn Unary(op: impl Into<Spanned<UnOp>>, expr: impl Into<Spanned<Expr>>) -> Expr {
+ Expr::Unary(ExprUnary {
+ op: op.into(),
+ expr: expr.into().map(Box::new),
+ })
}
-fn Mul<T: Into<Spanned<Expr>>>(e1: T, e2: T) -> Expr {
- Expr::Mul(Box::new(e1.into()), Box::new(e2.into()))
-}
-fn Div<T: Into<Spanned<Expr>>>(e1: T, e2: T) -> Expr {
- Expr::Div(Box::new(e1.into()), Box::new(e2.into()))
+fn Binary(
+ op: impl Into<Spanned<BinOp>>,
+ lhs: impl Into<Spanned<Expr>>,
+ rhs: impl Into<Spanned<Expr>>,
+) -> Expr {
+ Expr::Binary(ExprBinary {
+ lhs: lhs.into().map(Box::new),
+ op: op.into(),
+ rhs: rhs.into().map(Box::new),
+ })
}
// ------------------------------------ Test Macros ----------------------------------- //
@@ -321,12 +343,12 @@ fn test_parse_function_names() {
#[test]
fn test_parse_chaining() {
// Things the parser has to make sense of
- t!("[hi: (5.0, 2.1 >> you]" => F!("hi"; Dict![Num(5.0), Num(2.1)], Tree![F!("you")]));
+ t!("[hi: (5.0, 2.1 >> you]" => F!("hi"; Dict![Float(5.0), Float(2.1)], Tree![F!("you")]));
t!("[box >>][Hi]" => F!("box"; Tree![T("Hi")]));
t!("[box >> pad: 1pt][Hi]" => F!("box"; Tree![
F!("pad"; Len(Length::pt(1.0)), Tree!(T("Hi")))
]));
- t!("[bold: 400, >> emph >> sub: 1cm]" => F!("bold"; Num(400.0), Tree![
+ t!("[bold: 400, >> emph >> sub: 1cm]" => F!("bold"; Float(400.0), Tree![
F!("emph"; Tree!(F!("sub"; Len(Length::cm(1.0)))))
]));
@@ -354,7 +376,7 @@ fn test_parse_colon_starting_func_args() {
#[test]
fn test_parse_function_bodies() {
- t!("[val: 1][*Hi*]" => F!("val"; Num(1.0), Tree![B, T("Hi"), B]));
+ t!("[val: 1][*Hi*]" => F!("val"; Float(1.0), Tree![B, T("Hi"), B]));
e!(" [val][ */]" => s(8, 10, "unexpected end of block comment"));
// Raw in body.
@@ -384,9 +406,9 @@ fn test_parse_values() {
v!("\"hi\"" => Str("hi"));
v!("true" => Bool(true));
v!("false" => Bool(false));
- v!("1.0e-4" => Num(1e-4));
- v!("3.14" => Num(3.14));
- v!("50%" => Num(0.5));
+ v!("1.0e-4" => Float(1e-4));
+ v!("3.14" => Float(3.14));
+ v!("50%" => Float(0.5));
v!("4.5cm" => Len(Length::cm(4.5)));
v!("12e1pt" => Len(Length::pt(12e1)));
v!("#f7a20500" => Color(RgbaColor::new(0xf7, 0xa2, 0x05, 0x00)));
@@ -411,7 +433,7 @@ fn test_parse_values() {
s(13, 13, "expected closing bracket"));
// Spanned.
- ts!("[val: 1.4]" => s(0, 10, F!(s(1, 4, "val"); s(6, 9, Num(1.4)))));
+ ts!("[val: 1.4]" => s(0, 10, F!(s(1, 4, "val"); s(6, 9, Float(1.4)))));
}
#[test]
@@ -420,40 +442,50 @@ fn test_parse_expressions() {
v!("(hi)" => Id("hi"));
// Operations.
- v!("-1" => Neg(Num(1.0)));
- v!("-- 1" => Neg(Neg(Num(1.0))));
- v!("3.2in + 6pt" => Add(Len(Length::inches(3.2)), Len(Length::pt(6.0))));
- v!("5 - 0.01" => Sub(Num(5.0), Num(0.01)));
- v!("(3mm * 2)" => Mul(Len(Length::mm(3.0)), Num(2.0)));
- v!("12e-3cm/1pt" => Div(Len(Length::cm(12e-3)), Len(Length::pt(1.0))));
+ v!("-1" => Unary(Neg, Float(1.0)));
+ v!("-- 1" => Unary(Neg, Unary(Neg, Float(1.0))));
+ v!("3.2in + 6pt" => Binary(Add, Len(Length::inches(3.2)), Len(Length::pt(6.0))));
+ v!("5 - 0.01" => Binary(Sub, Float(5.0), Float(0.01)));
+ v!("(3mm * 2)" => Binary(Mul, Len(Length::mm(3.0)), Float(2.0)));
+ v!("12e-3cm/1pt" => Binary(Div, Len(Length::cm(12e-3)), Len(Length::pt(1.0))));
// More complex.
- v!("(3.2in + 6pt)*(5/2-1)" => Mul(
- Add(Len(Length::inches(3.2)), Len(Length::pt(6.0))),
- Sub(Div(Num(5.0), Num(2.0)), Num(1.0))
+ v!("(3.2in + 6pt)*(5/2-1)" => Binary(
+ Mul,
+ Binary(Add, Len(Length::inches(3.2)), Len(Length::pt(6.0))),
+ Binary(Sub, Binary(Div, Float(5.0), Float(2.0)), Float(1.0))
));
- v!("(6.3E+2+4* - 3.2pt)/2" => Div(
- Add(Num(6.3e2), Mul(Num(4.0), Neg(Len(Length::pt(3.2))))),
- Num(2.0)
+ v!("(6.3E+2+4* - 3.2pt)/2" => Binary(
+ Div,
+ Binary(Add, Float(6.3e2), Binary(
+ Mul,
+ Float(4.0),
+ Unary(Neg, Len(Length::pt(3.2)))
+ )),
+ Float(2.0)
));
// Associativity of multiplication and division.
- v!("3/4*5" => Mul(Div(Num(3.0), Num(4.0)), Num(5.0)));
+ v!("3/4*5" => Binary(Mul, Binary(Div, Float(3.0), Float(4.0)), Float(5.0)));
// Spanned.
ts!("[val: 1 + 3]" => s(0, 12, F!(
- s(1, 4, "val"); s(6, 11, Add(s(6, 7, Num(1.0)), s(10, 11, Num(3.0))))
+ s(1, 4, "val"); s(6, 11, Binary(
+ s(8, 9, Add),
+ s(6, 7, Float(1.0)),
+ s(10, 11, Float(3.0))
+ ))
)));
// Span of parenthesized expression contains parens.
- ts!("[val: (1)]" => s(0, 10, F!(s(1, 4, "val"); s(6, 9, Num(1.0)))));
+ ts!("[val: (1)]" => s(0, 10, F!(s(1, 4, "val"); s(6, 9, Float(1.0)))));
// Invalid expressions.
v!("4pt--" => Len(Length::pt(4.0)));
e!("[val: 4pt--]" => s(10, 11, "dangling minus"),
s(6, 10, "missing right summand"));
- v!("3mm+4pt*" => Add(Len(Length::mm(3.0)), Len(Length::pt(4.0))));
+ v!("3mm+4pt*" => Binary(Add, Len(Length::mm(3.0)), Len(Length::pt(4.0))));
e!("[val: 3mm+4pt*]" => s(10, 14, "missing right factor"));
}
@@ -464,8 +496,8 @@ fn test_parse_dicts() {
v!("(false)" => Bool(false));
v!("(true,)" => Dict![Bool(true)]);
v!("(key=val)" => Dict!["key" => Id("val")]);
- v!("(1, 2)" => Dict![Num(1.0), Num(2.0)]);
- v!("(1, key=\"value\")" => Dict![Num(1.0), "key" => Str("value")]);
+ v!("(1, 2)" => Dict![Float(1.0), Float(2.0)]);
+ v!("(1, key=\"value\")" => Dict![Float(1.0), "key" => Str("value")]);
// Decorations.
d!("[val: key=hi]" => s(6, 9, DictKey));
@@ -483,7 +515,7 @@ fn test_parse_dicts() {
#[test]
fn test_parse_dicts_compute_func_calls() {
v!("empty()" => Call!("empty"));
- v!("add ( 1 , 2 )" => Call!("add"; Num(1.0), Num(2.0)));
+ v!("add ( 1 , 2 )" => Call!("add"; Float(1.0), Float(2.0)));
v!("items(\"fire\", #f93a6d)" => Call!("items";
Str("fire"), Color(RgbaColor::new(0xf9, 0x3a, 0x6d, 0xff))
));
@@ -492,7 +524,7 @@ fn test_parse_dicts_compute_func_calls() {
v!("css(1pt, rgb(90, 102, 254), \"solid\")" => Call!(
"css";
Len(Length::pt(1.0)),
- Call!("rgb"; Num(90.0), Num(102.0), Num(254.0)),
+ Call!("rgb"; Float(90.0), Float(102.0), Float(254.0)),
Str("solid"),
));
@@ -501,7 +533,7 @@ fn test_parse_dicts_compute_func_calls() {
e!("[val: lang(δΈ­ζ–‡]" => s(17, 17, "expected closing paren"));
// Invalid name.
- v!("πŸ‘ (\"abc\", 13e-5)" => Dict!(Str("abc"), Num(13.0e-5)));
+ v!("πŸ‘ (\"abc\", 13e-5)" => Dict!(Str("abc"), Float(13.0e-5)));
e!("[val: πŸ‘ (\"abc\", 13e-5)]" => s(6, 10, "expected value, found invalid token"));
}
@@ -509,10 +541,10 @@ fn test_parse_dicts_compute_func_calls() {
fn test_parse_dicts_nested() {
v!("(1, ( ab=(), d = (3, 14pt) )), false" =>
Dict![
- Num(1.0),
+ Float(1.0),
Dict!(
"ab" => Dict![],
- "d" => Dict!(Num(3.0), Len(Length::pt(14.0))),
+ "d" => Dict!(Float(3.0), Len(Length::pt(14.0))),
),
],
Bool(false),
@@ -546,7 +578,7 @@ fn test_parse_dicts_errors() {
s(10, 11, "expected value, found equals sign"));
// Unexpected equals sign.
- v!("z=y=4" => Num(4.0), "z" => Id("y"));
+ v!("z=y=4" => "z" => Id("y"), Float(4.0));
e!("[val: z=y=4]" =>
s(9, 9, "expected comma"),
s(9, 10, "expected value, found equals sign"));