summaryrefslogtreecommitdiff
path: root/vendor/logos-codegen/src/parser/nested.rs
diff options
context:
space:
mode:
authormo khan <mo@mokhan.ca>2025-07-02 18:36:06 -0600
committermo khan <mo@mokhan.ca>2025-07-02 18:36:06 -0600
commit8cdfa445d6629ffef4cb84967ff7017654045bc2 (patch)
tree22f0b0907c024c78d26a731e2e1f5219407d8102 /vendor/logos-codegen/src/parser/nested.rs
parent4351c74c7c5f97156bc94d3a8549b9940ac80e3f (diff)
chore: add vendor directory
Diffstat (limited to 'vendor/logos-codegen/src/parser/nested.rs')
-rw-r--r--vendor/logos-codegen/src/parser/nested.rs146
1 files changed, 146 insertions, 0 deletions
diff --git a/vendor/logos-codegen/src/parser/nested.rs b/vendor/logos-codegen/src/parser/nested.rs
new file mode 100644
index 00000000..44ecaeac
--- /dev/null
+++ b/vendor/logos-codegen/src/parser/nested.rs
@@ -0,0 +1,146 @@
+use proc_macro2::token_stream::IntoIter as TokenIter;
+use proc_macro2::{Ident, Literal, TokenStream, TokenTree};
+use quote::quote;
+
+use crate::util::{expect_punct, is_punct};
+
+pub enum NestedValue {
+ /// `name = ...`
+ Assign(TokenStream),
+ /// `name "literal"`
+ Literal(Literal),
+ /// `name(...)`
+ Group(TokenStream),
+ /// `name ident = ...`
+ KeywordAssign(Ident, TokenStream),
+}
+
+pub enum Nested {
+ /// Unnamed nested attribute, such as a string,
+ /// callback closure, or a lone ident/path
+ ///
+ /// Note: a lone ident will be Named with no value instead
+ Unnamed(TokenStream),
+ /// Named: name ...
+ Named(Ident, NestedValue),
+ /// Unexpected token,
+ Unexpected(TokenStream),
+}
+
+pub struct AttributeParser {
+ inner: TokenIter,
+}
+
+pub struct Empty;
+
+impl From<Empty> for TokenStream {
+ fn from(_: Empty) -> TokenStream {
+ TokenStream::new()
+ }
+}
+
+impl AttributeParser {
+ pub fn new(stream: TokenStream) -> Self {
+ AttributeParser {
+ inner: stream.into_iter(),
+ }
+ }
+
+ pub fn parsed<T>(&mut self) -> Option<syn::Result<T>>
+ where
+ T: syn::parse::Parse,
+ {
+ let tokens = self.collect_tail(TokenStream::new());
+
+ if tokens.is_empty() {
+ return None;
+ }
+
+ Some(syn::parse2(tokens))
+ }
+
+ fn next_tt(&mut self) -> Option<TokenTree> {
+ expect_punct(self.inner.next(), ',')
+ }
+
+ fn collect_tail<T>(&mut self, first: T) -> TokenStream
+ where
+ T: Into<TokenStream>,
+ {
+ let mut out = first.into();
+
+ while let Some(tt) = self.next_tt() {
+ out.extend(Some(tt));
+ }
+
+ out
+ }
+
+ fn parse_unnamed(&mut self, first: Ident, next: TokenTree) -> Nested {
+ let mut out = TokenStream::from(TokenTree::Ident(first));
+
+ out.extend(self.collect_tail(next));
+
+ Nested::Unnamed(out.into_iter().collect())
+ }
+
+ fn parse_assign(&mut self, name: Ident) -> Nested {
+ let value = self.collect_tail(Empty);
+
+ Nested::Named(name, NestedValue::Assign(value))
+ }
+
+ fn parse_literal(&mut self, name: Ident, lit: Literal) -> Nested {
+ // TODO: Error if there are any tokens following
+ let _ = self.collect_tail(Empty);
+
+ Nested::Named(name, NestedValue::Literal(lit))
+ }
+
+ fn parse_group(&mut self, name: Ident, group: TokenStream) -> Nested {
+ Nested::Named(name, NestedValue::Group(group))
+ }
+
+ fn parse_keyword(&mut self, keyword: Ident, name: Ident) -> Nested {
+ let error = expect_punct(self.next_tt(), '=');
+
+ match error {
+ Some(error) => {
+ let error = self.collect_tail(error);
+
+ Nested::Unexpected(error)
+ }
+ None => {
+ let value = self.collect_tail(Empty);
+
+ Nested::Named(keyword, NestedValue::KeywordAssign(name, value))
+ }
+ }
+ }
+}
+
+impl Iterator for AttributeParser {
+ type Item = Nested;
+
+ fn next(&mut self) -> Option<Nested> {
+ let first = self.inner.next()?;
+
+ let name = match first {
+ TokenTree::Ident(ident) => ident,
+ tt => {
+ let stream = self.collect_tail(tt);
+
+ return Some(Nested::Unnamed(stream.into_iter().collect()));
+ }
+ };
+
+ match self.next_tt() {
+ Some(tt) if is_punct(&tt, '=') => Some(self.parse_assign(name)),
+ Some(TokenTree::Literal(lit)) => Some(self.parse_literal(name, lit)),
+ Some(TokenTree::Group(group)) => Some(self.parse_group(name, group.stream())),
+ Some(TokenTree::Ident(next)) => Some(self.parse_keyword(name, next)),
+ Some(next) => Some(self.parse_unnamed(name, next)),
+ None => Some(Nested::Unnamed(quote!(#name))),
+ }
+ }
+}