Source code
Revision control
Copy as Markdown
Other Tools
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
//! Parsing code for the ast
use quote::format_ident;
use syn::{
braced, parenthesized,
parse::{Parse, ParseStream},
token, Attribute, Ident, Token,
};
use super::ast::*;
impl Parse for Node {
fn parse(input: ParseStream) -> syn::Result<Self> {
let attrs = input.parse()?;
let vis = input.parse()?;
let lookahead = input.lookahead1();
if lookahead.peek(Token![struct]) {
let _: Token![struct] = input.parse()?;
let ident = input.parse()?;
let generics = input.parse()?;
let fields: Fields = input.parse()?;
if fields.not_named() {
let _: Token![;] = input.parse()?;
}
let mut wraps_field = None;
for f in fields.iter() {
if f.attrs.wraps {
if wraps_field.is_some() {
return Err(syn::Error::new(f.var_name.span(), "Multiple wraps"));
} else {
wraps_field = Some(f.clone());
}
}
}
let st = Struct {
fields,
wraps_field,
};
Ok(Self {
attrs,
vis,
ident,
generics,
def: NodeDef::Struct(st),
})
} else if lookahead.peek(Token![enum]) {
let _: Token![enum] = input.parse()?;
let ident = input.parse()?;
let generics = input.parse()?;
let content;
braced!(content in input);
let variants = content.parse_terminated(Variant::parse, Token![,])?;
Ok(Self {
attrs,
vis,
ident,
generics,
def: NodeDef::Enum(variants.into_iter().collect()),
})
} else {
Err(lookahead.error())
}
}
}
impl Parse for Attributes {
fn parse(input: ParseStream) -> syn::Result<Self> {
let parsed_attrs = input.call(Attribute::parse_outer)?;
Self::from_list(&parsed_attrs)
}
}
impl Attributes {
pub fn from_list(attrs: &[Attribute]) -> syn::Result<Self> {
let mut result = Attributes::default();
for attr in attrs {
if attr.path().is_ident("node") {
attr.parse_nested_meta(|meta| {
if meta.path.is_ident("from") {
let content;
parenthesized!(content in meta.input);
result.from = Some(content.parse()?);
return Ok(());
} else if meta.path.is_ident("wraps") {
result.wraps = true;
return Ok(());
}
Err(meta.error("unrecognized node attr"))
})?;
}
}
Ok(result)
}
}
impl Parse for Fields {
fn parse(input: ParseStream) -> syn::Result<Self> {
let lookahead = input.lookahead1();
if lookahead.peek(Token![,]) || lookahead.peek(Token![;]) || lookahead.peek(Token![=]) {
Ok(Self::Unit)
} else if lookahead.peek(token::Brace) {
let content;
braced!(content in input);
Ok(Self::Named(
content
.parse_terminated(Field::parse_named, Token![,])?
.into_iter()
.collect(),
))
} else if lookahead.peek(token::Paren) {
let content;
parenthesized!(content in input);
let mut counter = 0;
let mut fields = vec![];
while !content.is_empty() {
fields.push(Field::parse_unnamed(&content, counter)?);
counter += 1;
if content.is_empty() {
break;
}
let _: Token![,] = content.parse()?;
}
Ok(Self::Unnamed(fields))
} else {
Err(lookahead.error())
}
}
}
impl Parse for Variant {
fn parse(input: ParseStream) -> syn::Result<Self> {
let attrs = input.parse()?;
let vis = input.parse()?;
let ident = input.parse()?;
let fields = input.parse()?;
let mut discriminant = None;
if input.peek(Token![=]) {
let _: Token![=] = input.parse()?;
discriminant = Some(input.parse()?);
}
Ok(Self {
attrs,
vis,
ident,
fields,
discriminant,
})
}
}
impl Field {
fn parse_named(input: ParseStream) -> syn::Result<Self> {
let attrs = input.parse()?;
let vis = input.parse()?;
let ident: Ident = input.parse()?;
let _ = input.parse::<Token![:]>()?;
let ty = input.parse()?;
Ok(Self {
attrs,
vis,
ident: Some(ident.clone()),
ty,
var_name: ident,
})
}
fn parse_unnamed(input: ParseStream, index: usize) -> syn::Result<Self> {
Ok(Self {
attrs: input.parse()?,
vis: input.parse()?,
ident: None,
ty: input.parse()?,
var_name: format_ident!("var{index}"),
})
}
}