diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/color.rs | 4 | ||||
| -rw-r--r-- | src/eval/mod.rs | 2 | ||||
| -rw-r--r-- | src/library/utility.rs | 43 | ||||
| -rw-r--r-- | src/parse/mod.rs | 8 | ||||
| -rw-r--r-- | src/parse/tokens.rs | 56 | ||||
| -rw-r--r-- | src/pretty.rs | 2 | ||||
| -rw-r--r-- | src/syntax/expr.rs | 4 | ||||
| -rw-r--r-- | src/syntax/token.rs | 4 | ||||
| -rw-r--r-- | src/syntax/visit.rs | 1 |
9 files changed, 44 insertions, 80 deletions
diff --git a/src/color.rs b/src/color.rs index c3ab5aa9..124c2042 100644 --- a/src/color.rs +++ b/src/color.rs @@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize}; /// A color in a dynamic format. #[derive(Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)] pub enum Color { - /// An 8-bit RGBA color: `#423abaff`. + /// An 8-bit RGBA color. Rgba(RgbaColor), } @@ -28,7 +28,7 @@ impl Debug for Color { } } -/// An 8-bit RGBA color: `#423abaff`. +/// An 8-bit RGBA color. #[derive(Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)] pub struct RgbaColor { /// Red channel. diff --git a/src/eval/mod.rs b/src/eval/mod.rs index 8579025f..96ac87a9 100644 --- a/src/eval/mod.rs +++ b/src/eval/mod.rs @@ -16,7 +16,6 @@ use std::path::{Path, PathBuf}; use std::rc::Rc; use crate::cache::Cache; -use crate::color::Color; use crate::diag::{Diag, DiagSet, Pass}; use crate::geom::{Angle, Fractional, Length, Relative}; use crate::loading::{FileHash, Loader}; @@ -248,7 +247,6 @@ impl Eval for Expr { Self::Angle(_, v, unit) => Value::Angle(Angle::with_unit(v, unit)), Self::Percent(_, v) => Value::Relative(Relative::new(v / 100.0)), Self::Fractional(_, v) => Value::Fractional(Fractional::new(v)), - Self::Color(_, v) => Value::Color(Color::Rgba(v)), Self::Str(_, ref v) => Value::Str(v.clone()), Self::Ident(ref v) => match ctx.scopes.get(&v) { Some(slot) => slot.borrow().clone(), diff --git a/src/library/utility.rs b/src/library/utility.rs index 146fce9c..272183aa 100644 --- a/src/library/utility.rs +++ b/src/library/utility.rs @@ -1,4 +1,5 @@ use std::cmp::Ordering; +use std::str::FromStr; use crate::color::{Color, RgbaColor}; use crate::pretty::pretty; @@ -37,26 +38,32 @@ pub fn len(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { /// `rgb`: Create an RGB(A) color. pub fn rgb(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value { - let r = args.expect(ctx, "red component"); - let g = args.expect(ctx, "green component"); - let b = args.expect(ctx, "blue component"); - let a = args.eat(ctx); - - let mut clamp = |component: Option<Spanned<f64>>, default| { - component.map_or(default, |c| { - if c.v < 0.0 || c.v > 1.0 { - ctx.diag(warning!(c.span, "should be between 0.0 and 1.0")); + Value::Color(Color::Rgba( + if let Some(string) = args.eat::<Spanned<String>>(ctx) { + match RgbaColor::from_str(&string.v) { + Ok(color) => color, + Err(_) => { + ctx.diag(error!(string.span, "invalid color")); + return Value::Error; + } } - (c.v.max(0.0).min(1.0) * 255.0).round() as u8 - }) - }; + } else { + let r = args.expect(ctx, "red component"); + let g = args.expect(ctx, "green component"); + let b = args.expect(ctx, "blue component"); + let a = args.eat(ctx); + let mut clamp = |component: Option<Spanned<f64>>, default| { + component.map_or(default, |c| { + if c.v < 0.0 || c.v > 1.0 { + ctx.diag(warning!(c.span, "should be between 0.0 and 1.0")); + } + (c.v.max(0.0).min(1.0) * 255.0).round() as u8 + }) + }; - Value::Color(Color::Rgba(RgbaColor::new( - clamp(r, 0), - clamp(g, 0), - clamp(b, 0), - clamp(a, 255), - ))) + RgbaColor::new(clamp(r, 0), clamp(g, 0), clamp(b, 0), clamp(a, 255)) + }, + )) } /// `min`: The minimum of a sequence of values. diff --git a/src/parse/mod.rs b/src/parse/mod.rs index 0afcd88b..a56e451d 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -385,7 +385,6 @@ fn literal(p: &mut Parser) -> Option<Expr> { Token::Angle(val, unit) => Expr::Angle(span, val, unit), Token::Percent(p) => Expr::Percent(span, p), Token::Fraction(p) => Expr::Fractional(span, p), - Token::Color(color) => Expr::Color(span, color), Token::Str(token) => Expr::Str(span, { if !token.terminated { p.expected_at("quote", p.peek_span().end); @@ -672,10 +671,9 @@ fn if_expr(p: &mut Parser) -> Option<Expr> { // We are in code mode but still want to react to `#else` if the // outer mode is markup. - if match p.outer_mode() { - TokenMode::Markup => p.eat_if(Token::Invalid("#else")), - TokenMode::Code => p.eat_if(Token::Else), - } { + if (p.outer_mode() == TokenMode::Code || p.eat_if(Token::Invalid("#"))) + && p.eat_if(Token::Else) + { else_body = body(p); } diff --git a/src/parse/tokens.rs b/src/parse/tokens.rs index 4d90dded..522b3136 100644 --- a/src/parse/tokens.rs +++ b/src/parse/tokens.rs @@ -1,8 +1,6 @@ use std::fmt::{self, Debug, Formatter}; -use std::str::FromStr; use super::{is_newline, Scanner}; -use crate::color::RgbaColor; use crate::geom::{AngularUnit, LengthUnit}; use crate::syntax::*; @@ -71,9 +69,6 @@ impl<'s> Iterator for Tokens<'s> { '{' => Token::LeftBrace, '}' => Token::RightBrace, - // Headings, keywords, identifiers, colors. - '#' => self.hash(start), - // Whitespace. c if c.is_whitespace() => self.whitespace(c), @@ -104,6 +99,9 @@ impl<'s> Tokens<'s> { '-' => self.hyph(start), c if c == '.' || c.is_ascii_digit() => self.numbering(start, c), + // Headings, keywords and identifiers. + '#' => self.hash(start), + // Plain text. _ => self.text(start), } @@ -236,29 +234,17 @@ impl<'s> Tokens<'s> { } fn hash(&mut self, start: usize) -> Token<'s> { - match self.mode { - TokenMode::Markup => { - if self.s.check(is_id_start) { - let read = self.s.eat_while(is_id_continue); - if let Some(keyword) = keyword(read) { - keyword - } else { - Token::Ident(read) - } - } else if self.s.check(|c| c != '#' && !c.is_whitespace()) { - Token::Text(self.s.eaten_from(start)) - } else { - Token::Hashtag - } - } - TokenMode::Code => { - let read = self.s.eat_while(is_id_continue); - if let Ok(color) = RgbaColor::from_str(read) { - Token::Color(color) - } else { - Token::Invalid(self.s.eaten_from(start)) - } + if self.s.check(is_id_start) { + let read = self.s.eat_while(is_id_continue); + if let Some(keyword) = keyword(read) { + keyword + } else { + Token::Ident(read) } + } else if self.s.check(|c| c != '#' && !c.is_whitespace()) { + Token::Text(self.s.eaten_from(start)) + } else { + Token::Hashtag } } @@ -528,10 +514,6 @@ mod tests { Token::Math(MathToken { formula, display, terminated }) } - const fn Color(r: u8, g: u8, b: u8, a: u8) -> Token<'static> { - Token::Color(RgbaColor { r, g, b, a }) - } - const fn Str(string: &str, terminated: bool) -> Token { Token::Str(StrToken { string, terminated }) } @@ -583,7 +565,6 @@ mod tests { ('/', Some(Code), "(", LeftParen), ('/', Some(Code), ":", Colon), ('/', Some(Code), "+=", PlusEq), - ('/', Some(Code), "#123", Color(0x11, 0x22, 0x33, 0xff)), ]; macro_rules! t { @@ -927,13 +908,6 @@ mod tests { } #[test] - fn test_tokenize_color() { - t!(Code[" /"]: "#ABC" => Color(0xAA, 0xBB, 0xCC, 0xff)); - t!(Code[" /"]: "#6ae6dd" => Color(0x6a, 0xe6, 0xdd, 0xff)); - t!(Code[" /"]: "#8A083caf" => Color(0x8A, 0x08, 0x3c, 0xaf)); - } - - #[test] fn test_tokenize_strings() { // Test basic strings. t!(Code: "\"hi\"" => Str("hi", true)); @@ -999,13 +973,11 @@ mod tests { t!(Code: r"\:" => Invalid(r"\"), Colon); t!(Code: "meal⌚" => Ident("meal"), Invalid("⌚")); t!(Code[" /"]: r"\a" => Invalid(r"\"), Ident("a")); + t!(Code[" /"]: "#" => Invalid("#")); // Test invalid number suffixes. t!(Code[" /"]: "1foo" => Invalid("1foo")); t!(Code: "1p%" => Invalid("1p"), Invalid("%")); t!(Code: "1%%" => Percent(1.0), Invalid("%")); - - // Test invalid color. - t!(Code[" /"]: r"#letter" => Invalid(r"#letter")); } } diff --git a/src/pretty.rs b/src/pretty.rs index ccf4d88d..17609cea 100644 --- a/src/pretty.rs +++ b/src/pretty.rs @@ -205,7 +205,6 @@ impl Pretty for Expr { Self::Angle(_, v, u) => write!(p, "{}{}", v, u).unwrap(), Self::Percent(_, v) => write!(p, "{}%", v).unwrap(), Self::Fractional(_, v) => write!(p, "{}fr", v).unwrap(), - Self::Color(_, v) => v.pretty(p), Self::Str(_, v) => v.pretty(p), Self::Ident(v) => v.pretty(p), Self::Array(v) => v.pretty(p), @@ -687,7 +686,6 @@ mod tests { roundtrip("{14.1deg}"); roundtrip("{20%}"); roundtrip("{0.5fr}"); - roundtrip("{#abcdef}"); roundtrip(r#"{"hi"}"#); test_parse(r#"{"let's \" go"}"#, r#"{"let's \" go"}"#); roundtrip("{hi}"); diff --git a/src/syntax/expr.rs b/src/syntax/expr.rs index 26ec7f48..a8a5854a 100644 --- a/src/syntax/expr.rs +++ b/src/syntax/expr.rs @@ -1,7 +1,6 @@ use std::rc::Rc; use super::*; -use crate::color::RgbaColor; use crate::geom::{AngularUnit, LengthUnit}; /// An expression. @@ -28,8 +27,6 @@ pub enum Expr { Percent(Span, f64), /// A fraction unit literal: `1fr`. Fractional(Span, f64), - /// A color literal: `#ffccee`. - Color(Span, RgbaColor), /// A string literal: `"hello!"`. Str(Span, String), /// An identifier: `left`. @@ -81,7 +78,6 @@ impl Expr { Self::Angle(span, _, _) => span, Self::Percent(span, _) => span, Self::Fractional(span, _) => span, - Self::Color(span, _) => span, Self::Str(span, _) => span, Self::Ident(ref v) => v.span, Self::Array(ref v) => v.span, diff --git a/src/syntax/token.rs b/src/syntax/token.rs index 25062264..32a14d58 100644 --- a/src/syntax/token.rs +++ b/src/syntax/token.rs @@ -1,4 +1,3 @@ -use crate::color::RgbaColor; use crate::geom::{AngularUnit, LengthUnit}; /// A minimal semantic entity of source code. @@ -145,8 +144,6 @@ pub enum Token<'s> { Percent(f64), /// A fraction unit: `3fr`. Fraction(f64), - /// A color value: `#20d82a`. - Color(RgbaColor), /// A quoted string: `"..."`. Str(StrToken<'s>), /// Two slashes followed by inner contents, terminated with a newline: @@ -275,7 +272,6 @@ impl<'s> Token<'s> { Self::Angle(_, _) => "angle", Self::Percent(_) => "percentage", Self::Fraction(_) => "`fr` value", - Self::Color(_) => "color", Self::Str(_) => "string", Self::LineComment(_) => "line comment", Self::BlockComment(_) => "block comment", diff --git a/src/syntax/visit.rs b/src/syntax/visit.rs index 66c5f979..1184010b 100644 --- a/src/syntax/visit.rs +++ b/src/syntax/visit.rs @@ -124,7 +124,6 @@ impl_visitors! { Expr::Angle(_, _, _) => {} Expr::Percent(_, _) => {} Expr::Fractional(_, _) => {} - Expr::Color(_, _) => {} Expr::Str(_, _) => {} Expr::Ident(_) => {} Expr::Array(e) => v.visit_array(e), |
