Add named tuples and hex color tokens#1
Conversation
laurmaedje
left a comment
There was a problem hiding this comment.
I added some thoughts and comments, but I think this is already pretty good :)
| use std::fmt::{self, Write, Debug, Formatter}; | ||
| use std::iter::FromIterator; | ||
| use std::ops::Deref; | ||
| use std::u8; |
There was a problem hiding this comment.
Do you need that use std::u8; import? I think u8::from_str_radix is associated with the type, not the module.
There was a problem hiding this comment.
Does not seem to work without the import, so it has to stay :/
src/syntax/expr.rs
Outdated
| let permissable = &[3, 4, 6, 8]; | ||
|
|
||
| if !permissable.contains(&len) { | ||
| return None; | ||
| } | ||
|
|
There was a problem hiding this comment.
I would suggest adding another let short = len == 3 || len == 4; and then checking long || short and returning None if that is false instead of the slice-contains.
src/syntax/expr.rs
Outdated
| let pos = elem * item_len; | ||
|
|
||
| if let Ok(val) = u8::from_str_radix( | ||
| &hex_str[pos..(pos+item_len)], 16) { |
There was a problem hiding this comment.
I think this can panic if hex_str turns out not to be ASCII if you index into a UTF-8 char. I suggest adding a hex_str.is_ascii() check at the start of the method.
src/syntax/expr.rs
Outdated
| let item_len = if long { 2 } else { 1 }; | ||
| let pos = elem * item_len; | ||
|
|
||
| if let Ok(val) = u8::from_str_radix( |
There was a problem hiding this comment.
This might be written more concisely as
let item = &hex_str[pos..(pos+item_len)];
values[elem] = u8::from_str_radix(item, 16).ok()?;| /// ``` | ||
| #[derive(Clone, PartialEq)] | ||
| pub struct NamedTuple { | ||
| pub name: Spanned<Ident>, |
There was a problem hiding this comment.
Maybe add a doc-comment, even though I guess it's pretty obvious.
src/syntax/expr.rs
Outdated
| impl Debug for NamedTuple { | ||
| fn fmt(&self, f: &mut Formatter) -> fmt::Result { | ||
| f.debug_struct("named tuple") | ||
| .field("name", &self.name) | ||
| .field("values", &self.tuple) | ||
| .finish() | ||
| } | ||
| } |
There was a problem hiding this comment.
This is pretty close to the output of derive(Debug). In that case, I think deriving would be simpler.
src/syntax/parsing.rs
Outdated
| let color_opt = RgbaColor::from_str(s); | ||
|
|
||
| if let Some(color) = color_opt { |
There was a problem hiding this comment.
Maybe write that RgbaColor::from_str(s) directly into the if let.
src/syntax/parsing.rs
Outdated
| } else { | ||
| // Heal color by assuming black | ||
| self.feedback.errors.push(err!(first.span; | ||
| "expected valid color, found invalid color #{}", s)); |
There was a problem hiding this comment.
I think adding the error message & healing here is a good idea, but the message might be slightly redundant. What do you think about adding it here, but keeping just "invalid color"?
There was a problem hiding this comment.
I have also introduced a healed flag on RgbaColor that indicates whether the color is a fallback, so that other methods can react more smartly (or not at all).
src/syntax/parsing.rs
Outdated
| let start = name.span.start.clone(); | ||
| let end = tuple.span.end.clone(); |
There was a problem hiding this comment.
Position should implement Copy, so I don't think you need to clone. But, in fact, there is also a convenience method Span::merge(name.span, tuple.span), which you can use here.
There was a problem hiding this comment.
Googled up on the difference between Clone and Copy traits in general and copy seems like the Right Thing To Do:tm: here,
src/syntax/tokens.rs
Outdated
|
|
||
| // This may be a hex expression | ||
| let hex_expr = if c == '#' && !body { | ||
| let payload = self.read_string_until(|n| { | ||
| match n { | ||
| '0'..='9' | 'a'..='f' | 'A'..='F' => false, | ||
| _ => true, | ||
| } | ||
| }, false, 0, 0).0; | ||
|
|
||
| Some(ExprHex(payload)) | ||
| } else { | ||
| None | ||
| }; | ||
|
|
There was a problem hiding this comment.
Since this starts with a clearly defined character (#), you should be able to write it earlier in match instead of writing it in the fallback case. For example, right after the string case á la
'#' if self.mode == Header => self.parse_hex_value(),and then factor the code out into that method. Also, I just noticed that there is a function in the standard library, so you can just do it like this:
ExprHex(self.read_string_until(|n| !n.is_digit(16), false, 0, 0).0)There was a problem hiding this comment.
There is also the thing that stopping when there is no hex digit might lead to a bit counter-intuitive error messages:
[page: background=#55z555]
^^^^
unexpected identifierWhere on might expect:
[page: background=#55z555]
^^^^^^^
invalid colorBut I'm also not sure how important that is and what the best way would be here. Maybe reading until there is a non-alphanumeric character would also be an option.
There was a problem hiding this comment.
Okay, it will now do is_ascii_alphanumeric in the tokenizer, that will hopefully create better error messages.
|
The new commit with the feedback incorporated is now pushed. |
Multi-container apps: add workaround for non amd64 machines
* feat: mod typst * chore: bump version * Avoid panic if a field doesn't have name --------- Co-authored-by: ParaN3xus <paran3xus007@gmail.com> Co-authored-by: ParaN3xus <136563585+ParaN3xus@users.noreply.github.com>
This Pull Request implements the specification for
cmyk(52.6, 16, 80.4, 41.1)#20d82aThis pull request includes comprehensive test cases for the new parsing features.
The request should be merged to provide the language groundwork for color usage and other styling applications.