Skip to content

Commit

Permalink
Support tuples and arrays in path parser (#17)
Browse files Browse the repository at this point in the history
  • Loading branch information
parasyte authored May 30, 2024
1 parent 680794d commit ba6980a
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 4 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "myn"
description = "Minimalist Rust syntax parsing for procedural macros"
version = "0.2.1"
version = "0.2.2"
authors = ["Jay Oster <[email protected]>"]
repository = "https://github.com/parasyte/myn"
edition = "2021"
Expand Down
82 changes: 80 additions & 2 deletions src/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,11 @@ impl TokenIterExt for TokenIter {

while let Some(tree) = self.peek() {
match tree {
TokenTree::Punct(punct) if punct.as_char() == ',' && nesting == 0 => break,
TokenTree::Punct(punct)
if [',', ';'].contains(&punct.as_char()) && nesting == 0 =>
{
break
}
TokenTree::Punct(punct) => {
let ch = punct.as_char();

Expand All @@ -84,7 +88,43 @@ impl TokenIterExt for TokenIter {
span.get_or_insert_with(|| ident.span());
path.push_str(&ident.to_string());
}
_ => return Err(spanned_error("Unexpected token", self.next().as_span())),
TokenTree::Group(group) => {
span.get_or_insert(group.span());
let mut stream = group.stream().into_token_iter();

match group.delimiter() {
Delimiter::Parenthesis => {
// Tuples are comma-separated paths.
path.push('(');
while stream.peek().is_some() {
let (inner, _span) = stream.parse_path()?;
path.push_str(&inner);
if stream.peek().is_some() {
stream.expect_punct(',')?;
path.push_str(", ");
}
}
if path.ends_with(' ') {
path.pop();
}
path.push(')');
}
Delimiter::Bracket => {
// Arrays are in `[path; size]` form.
path.push('[');
let (inner, _span) = stream.parse_path()?;
path.push_str(&inner);
stream.expect_punct(';')?;
path.push_str("; ");
path.push_str(&stream.try_lit()?.to_string());
path.push(']');
}
_ => return Err(spanned_error("Unexpected token", group.span())),
}
}
TokenTree::Literal(_) => {
return Err(spanned_error("Unexpected token", self.next().as_span()))
}
}

self.next();
Expand Down Expand Up @@ -192,6 +232,44 @@ mod tests {
use super::*;
use std::str::FromStr;

#[test]
fn test_tokeniter_parse_path() {
let mut input = TokenStream::from_str("foo::bar").unwrap().into_token_iter();
assert_eq!(input.parse_path().unwrap().0, "foo::bar");
assert!(input.next().is_none());

let mut input = TokenStream::from_str("foo::bar<baz>")
.unwrap()
.into_token_iter();
assert_eq!(input.parse_path().unwrap().0, "foo::bar<baz>");
assert!(input.next().is_none());

let mut input = TokenStream::from_str("foo::bar<()>")
.unwrap()
.into_token_iter();
assert_eq!(input.parse_path().unwrap().0, "foo::bar<()>");
assert!(input.next().is_none());

let mut input = TokenStream::from_str("foo::bar<(foo, bar::baz<T>)>")
.unwrap()
.into_token_iter();
assert_eq!(
input.parse_path().unwrap().0,
"foo::bar<(foo, bar::baz<T>)>"
);
assert!(input.next().is_none());

let mut input = TokenStream::from_str("foo<(bar, [i32; 4])>")
.unwrap()
.into_token_iter();
assert_eq!(input.parse_path().unwrap().0, "foo<(bar, [i32; 4])>");
assert!(input.next().is_none());

let mut input = TokenStream::from_str("(u8, )").unwrap().into_token_iter();
assert_eq!(input.parse_path().unwrap().0, "(u8,)");
assert!(input.next().is_none());
}

#[test]
fn test_tokeniter_expect_group() {
let mut input = TokenStream::from_str("{ foo }").unwrap().into_token_iter();
Expand Down

0 comments on commit ba6980a

Please sign in to comment.