diff options
Diffstat (limited to 'src/parse')
| -rw-r--r-- | src/parse/mod.rs | 148 | ||||
| -rw-r--r-- | src/parse/resolve.rs | 8 | ||||
| -rw-r--r-- | src/parse/tests.rs | 160 |
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")); |
