Skip to content

Commit

Permalink
Parse many literals along side idents in names (#398)
Browse files Browse the repository at this point in the history
* Parse many literals along side idents in names

* Accept ints as literals

We will not accept floats because `123.123` is a float literal,
but `123 .123` is a int literal followed by a class called `123`.
This could be confusing so it will not be accepted.

Ints can have leading zeros, like `0123`, but this is not guarranteed by
the rust compiler to always work, which could cause future errors.
An example would be truncating `001` to `1`.

* Limit accepted literals using existing function

* Update error output for non-string-literal

* Test output of ints with specified type

This outputs exactly what is written, which is the obvious behaviour

* Use nightly version to generate output

Previous verison was not using nightly, causing errors in the automated
test that are using nightly

* Replace "byte_string" with "raw_string" in test

---------

Co-authored-by: Chris Wong <[email protected]>
  • Loading branch information
RedPhoenixQ and lambda-fairy committed Jan 4, 2024
1 parent 0de60b0 commit b3a98c9
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 34 deletions.
14 changes: 11 additions & 3 deletions maud/tests/basic_syntax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,11 +201,19 @@ fn raw_string_literals_in_attribute_names() {

#[test]
fn other_literals_in_attribute_names() {
let result =
html! { this b"byte_string"="false" 123="123" 2.5 true 'a'="a" b'b'="b" of-course {} };
let result = html! { this r#"raw_string"#="false" 123="123" 123usize "2.5" true of-course {} };
assert_eq!(
result.into_string(),
r#"<this byte_string="false" 123="123" 2.5 true a="a" b="b" of-course></this>"#
r#"<this raw_string="false" 123="123" 123usize 2.5 true of-course></this>"#
);
}

#[test]
fn idents_and_literals_in_names() {
let result = html! { custom:element-001 test:123-"test"="123" .m-2.p-2 {} };
assert_eq!(
result.into_string(),
r#"<custom:element-001 class="m-2 p-2" test:123-test="123"></custom:element-001>"#
);
}

Expand Down
24 changes: 6 additions & 18 deletions maud/tests/warnings/non-string-literal.stderr
Original file line number Diff line number Diff line change
@@ -1,41 +1,29 @@
error: literal must be double-quoted: `"42"`
--> $DIR/non-string-literal.rs:5:9
|
5 | 42
| ^^

error: literal must be double-quoted: `"42usize"`
--> $DIR/non-string-literal.rs:6:9
|
6 | 42usize
| ^^^^^^^

error: literal must be double-quoted: `"42.0"`
--> $DIR/non-string-literal.rs:7:9
--> tests/warnings/non-string-literal.rs:7:9
|
7 | 42.0
| ^^^^

error: literal must be double-quoted: `"a"`
--> $DIR/non-string-literal.rs:8:9
--> tests/warnings/non-string-literal.rs:8:9
|
8 | 'a'
| ^^^

error: expected string
--> $DIR/non-string-literal.rs:9:9
--> tests/warnings/non-string-literal.rs:9:9
|
9 | b"a"
| ^^^^

error: expected string
--> $DIR/non-string-literal.rs:10:9
--> tests/warnings/non-string-literal.rs:10:9
|
10 | b'a'
| ^^^^

error: attribute value must be a string
--> $DIR/non-string-literal.rs:13:24
--> tests/warnings/non-string-literal.rs:13:24
|
13 | input disabled=true;
| ^^^^
Expand All @@ -44,7 +32,7 @@ error: attribute value must be a string
= help: to toggle the attribute, use square brackets: `disabled[some_boolean_flag]`

error: attribute value must be a string
--> $DIR/non-string-literal.rs:14:24
--> tests/warnings/non-string-literal.rs:14:24
|
14 | input disabled=false;
| ^^^^^
Expand Down
37 changes: 24 additions & 13 deletions maud_macros/src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,13 @@ impl Parser {
}
// Boolean literals are idents, so `Lit::Bool` is handled in
// `markup`, not here.
Lit::Int(..) | Lit::Float(..) => {
Lit::Int(lit_int) => {
return ast::Markup::Literal {
content: lit_int.to_string(),
span: SpanRange::single_span(literal.span()),
};
}
Lit::Float(..) => {
emit_error!(literal, r#"literal must be double-quoted: `"{}"`"#, literal);
}
Lit::Char(lit_char) => {
Expand Down Expand Up @@ -702,27 +708,32 @@ impl Parser {
/// Parses an identifier, without dealing with namespaces.
fn try_name(&mut self) -> Option<TokenStream> {
let mut result = Vec::new();
match self.peek() {
Some(token @ TokenTree::Ident(_)) | Some(token @ TokenTree::Literal(_)) => {
self.advance();
result.push(token);
}
_ => return None,
};
let mut expect_ident = false;
let mut expect_ident_or_literal = true;
loop {
expect_ident = match self.peek() {
expect_ident_or_literal = match self.peek() {
Some(TokenTree::Punct(ref punct)) if punct.as_char() == '-' => {
self.advance();
result.push(TokenTree::Punct(punct.clone()));
true
}
Some(TokenTree::Ident(ref ident)) if expect_ident => {
Some(token @ TokenTree::Ident(_)) if expect_ident_or_literal => {
self.advance();
result.push(TokenTree::Ident(ident.clone()));
result.push(token);
false
}
_ => break,
Some(TokenTree::Literal(ref literal)) if expect_ident_or_literal => {
self.literal(literal.clone());
self.advance();
result.push(TokenTree::Literal(literal.clone()));
false
}
_ => {
if result.is_empty() {
return None;
} else {
break;
}
}
};
}
Some(result.into_iter().collect())
Expand Down

0 comments on commit b3a98c9

Please sign in to comment.