summaryrefslogtreecommitdiff
path: root/src/parse
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2020-10-03 15:07:57 +0200
committerLaurenz <laurmaedje@gmail.com>2020-10-03 15:07:57 +0200
commit95bae5725cf6495644e2593f8492f1cd0e5bd3c1 (patch)
tree919dd90cac7623bcbbc09d9c92399eaa65e537f2 /src/parse
parent0fc25d732d7cbc37cf801645849d1060f2cec4a3 (diff)
Int, Float, Relative and Linear values 🍉
Diffstat (limited to 'src/parse')
-rw-r--r--src/parse/mod.rs5
-rw-r--r--src/parse/tests.rs48
-rw-r--r--src/parse/tokens.rs44
3 files changed, 51 insertions, 46 deletions
diff --git a/src/parse/mod.rs b/src/parse/mod.rs
index 42102bf5..916f2fdc 100644
--- a/src/parse/mod.rs
+++ b/src/parse/mod.rs
@@ -72,6 +72,7 @@ fn node(p: &mut Parser, at_start: bool) -> Option<Spanned<SynNode>> {
SynNode::Text(p.eaten_from(start).into())
}
}
+ Token::NonBreakingSpace => SynNode::Text("\u{00A0}".into()),
Token::Raw(token) => SynNode::Raw(raw(p, token)),
Token::UnicodeEscape(token) => SynNode::Text(unicode_escape(p, token, start)),
@@ -425,8 +426,10 @@ fn value(p: &mut Parser) -> Option<Expr> {
// Atomic values.
Token::Bool(b) => Expr::Lit(Lit::Bool(b)),
- Token::Number(f) => Expr::Lit(Lit::Float(f)),
+ Token::Int(i) => Expr::Lit(Lit::Int(i)),
+ Token::Float(f) => Expr::Lit(Lit::Float(f)),
Token::Length(l) => Expr::Lit(Lit::Length(l)),
+ Token::Percent(p) => Expr::Lit(Lit::Percent(p)),
Token::Hex(hex) => Expr::Lit(Lit::Color(color(p, hex, start))),
Token::Str(token) => Expr::Lit(Lit::Str(string(p, token))),
diff --git a/src/parse/tests.rs b/src/parse/tests.rs
index feff2b9a..4315fd2c 100644
--- a/src/parse/tests.rs
+++ b/src/parse/tests.rs
@@ -57,13 +57,13 @@ fn Id(ident: &str) -> Expr {
fn Bool(b: bool) -> Expr {
Expr::Lit(Lit::Bool(b))
}
-fn _Int(int: i64) -> Expr {
+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 {
+fn Percent(percent: f64) -> Expr {
Expr::Lit(Lit::Percent(percent))
}
fn Len(length: Length) -> Expr {
@@ -334,7 +334,7 @@ fn test_parse_function_names() {
t!("[ f]" => F!("f"));
// An invalid name.
- e!("[12]" => s(1, 3, "expected function name, found number"));
+ e!("[12]" => s(1, 3, "expected function name, found integer"));
e!("[ 🌎]" => s(3, 7, "expected function name, found invalid token"));
}
@@ -345,7 +345,7 @@ fn test_parse_chaining() {
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"; Float(400.0), Tree![
+ t!("[bold: 400, >> emph >> sub: 1cm]" => F!("bold"; Int(400), Tree![
F!("emph"; Tree!(F!("sub"; Len(Length::cm(1.0)))))
]));
@@ -374,7 +374,7 @@ fn test_parse_colon_starting_func_args() {
#[test]
fn test_parse_function_bodies() {
- t!("[val: 1][*Hi*]" => F!("val"; Float(1.0), Tree![B, T("Hi"), B]));
+ t!("[val: 1][*Hi*]" => F!("val"; Int(1), Tree![B, T("Hi"), B]));
e!(" [val][ */]" => s(8, 10, "unexpected end of block comment"));
// Raw in body.
@@ -406,7 +406,7 @@ fn test_parse_values() {
v!("false" => Bool(false));
v!("1.0e-4" => Float(1e-4));
v!("3.14" => Float(3.14));
- v!("50%" => Float(0.5));
+ v!("50%" => Percent(50.0));
v!("4.5cm" => Len(Length::cm(4.5)));
v!("12e1pt" => Len(Length::pt(12e1)));
v!("#f7a20500" => Color(RgbaColor::new(0xf7, 0xa2, 0x05, 0x00)));
@@ -440,43 +440,43 @@ fn test_parse_expressions() {
v!("(hi)" => Id("hi"));
// Operations.
- v!("-1" => Unary(Neg, Float(1.0)));
- v!("-- 1" => Unary(Neg, Unary(Neg, Float(1.0))));
+ v!("-1" => Unary(Neg, Int(1)));
+ v!("-- 1" => Unary(Neg, Unary(Neg, Int(1))));
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!("5 - 0.01" => Binary(Sub, Int(5), Float(0.01)));
+ v!("(3mm * 2)" => Binary(Mul, Len(Length::mm(3.0)), Int(2)));
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)" => 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))
+ Binary(Sub, Binary(Div, Int(5), Int(2)), Int(1))
));
v!("(6.3E+2+4* - 3.2pt)/2" => Binary(
Div,
Binary(Add, Float(6.3e2), Binary(
Mul,
- Float(4.0),
+ Int(4),
Unary(Neg, Len(Length::pt(3.2)))
)),
- Float(2.0)
+ Int(2)
));
// Associativity of multiplication and division.
- v!("3/4*5" => Binary(Mul, Binary(Div, Float(3.0), Float(4.0)), Float(5.0)));
+ v!("3/4*5" => Binary(Mul, Binary(Div, Int(3), Int(4)), Int(5)));
// Spanned.
ts!("[val: 1 + 3]" => s(0, 12, F!(
s(1, 4, "val"); s(6, 11, Binary(
s(8, 9, Add),
- s(6, 7, Float(1.0)),
- s(10, 11, Float(3.0))
+ s(6, 7, Int(1)),
+ s(10, 11, Int(3))
))
)));
// Span of parenthesized expression contains parens.
- ts!("[val: (1)]" => s(0, 10, F!(s(1, 4, "val"); s(6, 9, Float(1.0)))));
+ ts!("[val: (1)]" => s(0, 10, F!(s(1, 4, "val"); s(6, 9, Int(1)))));
// Invalid expressions.
v!("4pt--" => Len(Length::pt(4.0)));
@@ -494,8 +494,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![Float(1.0), Float(2.0)]);
- v!("(1, key=\"value\")" => Dict![Float(1.0), "key" => Str("value")]);
+ v!("(1, 2)" => Dict![Int(1), Int(2)]);
+ v!("(1, key=\"value\")" => Dict![Int(1), "key" => Str("value")]);
// Decorations.
d!("[val: key=hi]" => s(6, 9, DictKey));
@@ -513,7 +513,7 @@ fn test_parse_dicts() {
#[test]
fn test_parse_dicts_compute_func_calls() {
v!("empty()" => Call!("empty"));
- v!("add ( 1 , 2 )" => Call!("add"; Float(1.0), Float(2.0)));
+ v!("add ( 1 , 2 )" => Call!("add"; Int(1), Int(2)));
v!("items(\"fire\", #f93a6d)" => Call!("items";
Str("fire"), Color(RgbaColor::new(0xf9, 0x3a, 0x6d, 0xff))
));
@@ -522,7 +522,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"; Float(90.0), Float(102.0), Float(254.0)),
+ Call!("rgb"; Int(90), Int(102), Int(254)),
Str("solid"),
));
@@ -539,10 +539,10 @@ fn test_parse_dicts_compute_func_calls() {
fn test_parse_dicts_nested() {
v!("(1, ( ab=(), d = (3, 14pt) )), false" =>
Dict![
- Float(1.0),
+ Int(1),
Dict!(
"ab" => Dict![],
- "d" => Dict!(Float(3.0), Len(Length::pt(14.0))),
+ "d" => Dict!(Int(3), Len(Length::pt(14.0))),
),
],
Bool(false),
@@ -576,7 +576,7 @@ fn test_parse_dicts_errors() {
s(10, 11, "expected value, found equals sign"));
// Unexpected equals sign.
- v!("z=y=4" => "z" => Id("y"), Float(4.0));
+ v!("z=y=4" => "z" => Id("y"), Int(4));
e!("[val: z=y=4]" =>
s(9, 9, "expected comma"),
s(9, 10, "expected value, found equals sign"));
diff --git a/src/parse/tokens.rs b/src/parse/tokens.rs
index 77e7e92e..0f6fb378 100644
--- a/src/parse/tokens.rs
+++ b/src/parse/tokens.rs
@@ -87,8 +87,8 @@ impl<'s> Iterator for Tokens<'s> {
'*' if self.mode == Body => Token::Star,
'_' if self.mode == Body => Token::Underscore,
'#' if self.mode == Body => Token::Hashtag,
+ '~' if self.mode == Body => Token::NonBreakingSpace,
'`' if self.mode == Body => self.read_raw(),
- '~' if self.mode == Body => Token::Text("\u{00A0}"),
'\\' if self.mode == Body => self.read_escaped(),
// Syntactic elements in headers.
@@ -273,10 +273,12 @@ impl Debug for Tokens<'_> {
fn parse_expr(text: &str) -> Token<'_> {
if let Ok(b) = text.parse::<bool>() {
Token::Bool(b)
+ } else if let Ok(int) = text.parse::<i64>() {
+ Token::Int(int)
} else if let Ok(num) = text.parse::<f64>() {
- Token::Number(num)
- } else if let Some(num) = parse_percent(text) {
- Token::Number(num / 100.0)
+ Token::Float(num)
+ } else if let Some(percent) = parse_percent(text) {
+ Token::Percent(percent)
} else if let Ok(length) = text.parse::<Length>() {
Token::Length(length)
} else if is_ident(text) {
@@ -298,10 +300,10 @@ mod tests {
use crate::parse::tests::check;
use Token::{
- BlockComment as BC, Bool, Chain, Hex, Hyphen as Min, Ident as Id,
+ BlockComment as BC, Bool, Chain, Float, Hex, Hyphen as Min, Ident as Id, Int,
LeftBrace as LB, LeftBracket as L, LeftParen as LP, Length as Len,
- LineComment as LC, Number as Num, Plus, RightBrace as RB, RightBracket as R,
- RightParen as RP, Slash, Space as S, Star, Text as T, *,
+ LineComment as LC, NonBreakingSpace as Nbsp, Percent, Plus, RightBrace as RB,
+ RightBracket as R, RightParen as RP, Slash, Space as S, Star, Text as T, *,
};
fn Str(string: &str, terminated: bool) -> Token {
@@ -337,7 +339,7 @@ mod tests {
t!(Body, " \n\t \n " => S(2));
t!(Body, "\n\r" => S(2));
t!(Body, " \r\r\n \x0D" => S(3));
- t!(Body, "a~b" => T("a"), T("\u{00A0}"), T("b"));
+ t!(Body, "a~b" => T("a"), Nbsp, T("b"));
}
#[test]
@@ -424,24 +426,24 @@ mod tests {
t!(Header, ">main" => Invalid(">main"));
t!(Header, "🌓, 🌍," => Invalid("🌓"), Comma, S(0), Invalid("🌍"), Comma);
t!(Header, "{abc}" => LB, Id("abc"), RB);
- t!(Header, "(1,2)" => LP, Num(1.0), Comma, Num(2.0), RP);
+ t!(Header, "(1,2)" => LP, Int(1), Comma, Int(2), RP);
t!(Header, "12_pt, 12pt" => Invalid("12_pt"), Comma, S(0), Len(Length::pt(12.0)));
t!(Header, "f: arg >> g" => Id("f"), Colon, S(0), Id("arg"), S(0), Chain, S(0), Id("g"));
- t!(Header, "=3.14" => Equals, Num(3.14));
+ t!(Header, "=3.14" => Equals, Float(3.14));
t!(Header, "arg, _b, _1" => Id("arg"), Comma, S(0), Id("_b"), Comma, S(0), Id("_1"));
t!(Header, "a:b" => Id("a"), Colon, Id("b"));
t!(Header, "(){}:=," => LP, RP, LB, RB, Colon, Equals, Comma);
t!(Body, "c=d, " => T("c=d,"), S(0));
t!(Body, "a: b" => T("a:"), S(0), T("b"));
t!(Header, "a: true, x=1" => Id("a"), Colon, S(0), Bool(true), Comma, S(0),
- Id("x"), Equals, Num(1.0));
+ Id("x"), Equals, Int(1));
}
#[test]
fn tokenize_numeric_values() {
- t!(Header, "12.3e5" => Num(12.3e5));
- t!(Header, "120%" => Num(1.2));
- t!(Header, "12e4%" => Num(1200.0));
+ t!(Header, "12.3e5" => Float(12.3e5));
+ t!(Header, "120%" => Percent(120.0));
+ t!(Header, "12e4%" => Percent(120000.0));
t!(Header, "1e5in" => Len(Length::inches(100000.0)));
t!(Header, "2.3cm" => Len(Length::cm(2.3)));
t!(Header, "02.4mm" => Len(Length::mm(2.4)));
@@ -456,7 +458,7 @@ mod tests {
t!(Header, "\"hello" => Str("hello", false));
t!(Header, "\"hello world\"" => Str("hello world", true));
t!(Header, "\"hello\nworld\"" => Str("hello\nworld", true));
- t!(Header, r#"1"hello\nworld"false"# => Num(1.0), Str("hello\\nworld", true), Bool(false));
+ t!(Header, r#"1"hello\nworld"false"# => Int(1), Str("hello\\nworld", true), Bool(false));
t!(Header, r#""a\"bc""# => Str(r#"a\"bc"#, true));
t!(Header, r#""a\\"bc""# => Str(r#"a\\"#, true), Id("bc"), Str("", false));
t!(Header, r#""a\tbc"# => Str("a\\tbc", false));
@@ -466,12 +468,12 @@ mod tests {
#[test]
fn tokenize_math() {
t!(Header, "12e-3in" => Len(Length::inches(12e-3)));
- t!(Header, "-1" => Min, Num(1.0));
- t!(Header, "--1" => Min, Min, Num(1.0));
- t!(Header, "- 1" => Min, S(0), Num(1.0));
+ t!(Header, "-1" => Min, Int(1));
+ t!(Header, "--1" => Min, Min, Int(1));
+ t!(Header, "- 1" => Min, S(0), Int(1));
t!(Header, "6.1cm + 4pt,a=1*2" => Len(Length::cm(6.1)), S(0), Plus, S(0), Len(Length::pt(4.0)),
- Comma, Id("a"), Equals, Num(1.0), Star, Num(2.0));
- t!(Header, "(5 - 1) / 2.1" => LP, Num(5.0), S(0), Min, S(0), Num(1.0), RP,
- S(0), Slash, S(0), Num(2.1));
+ Comma, Id("a"), Equals, Int(1), Star, Int(2));
+ t!(Header, "(5 - 1) / 2.1" => LP, Int(5), S(0), Min, S(0), Int(1), RP,
+ S(0), Slash, S(0), Float(2.1));
}
}