From a269c52d307eb77a5f7bdccfe32a43f0a366237c Mon Sep 17 00:00:00 2001 From: Connor Horman Date: Fri, 22 Sep 2023 00:11:45 -0400 Subject: [PATCH] feat(rust-parse): parse traits --- rust/src/ast.rs | 15 ++ rust/src/lex.rs | 662 +++++++++++++++++++++++++--------------------- rust/src/parse.rs | 217 ++++++++++++--- rust/src/sema.rs | 4 + 4 files changed, 555 insertions(+), 343 deletions(-) diff --git a/rust/src/ast.rs b/rust/src/ast.rs index ef36baa8..f7357ffd 100644 --- a/rust/src/ast.rs +++ b/rust/src/ast.rs @@ -63,6 +63,21 @@ pub enum ItemBody { Function(Spanned), ExternBlock(Spanned), MacroRules(Spanned), + Trait(Spanned), +} + +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub struct Auto; + +#[derive(Debug, Clone, Hash, PartialEq, Eq)] +pub struct TraitDef { + pub safety: Option>, + pub auto: Option>, + pub name: Spanned, + pub generics: Option>, + pub supertraits: Option>>, + pub where_clauses: Option>>>, + pub body: Vec>, } #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] diff --git a/rust/src/lex.rs b/rust/src/lex.rs index 2e56398e..8d17fd05 100644 --- a/rust/src/lex.rs +++ b/rust/src/lex.rs @@ -346,6 +346,7 @@ keywords! { as => As, async => Async, await => Await, + auto => Auto, become => Become, box => Box, break => Break, @@ -444,6 +445,58 @@ impl LexemeClass { } } + pub fn matches(&self, tok: Option<&Lexeme>) -> bool { + match (self, tok) { + ( + Self::Eof, + None + | Some(Lexeme { + body: LexemeBody::Eof, + .. + }), + ) => true, + ( + Self::Group(None), + Some(Lexeme { + body: LexemeBody::Group(_), + .. + }), + ) => true, + ( + Self::Group(Some(gty)), + Some(Lexeme { + body: LexemeBody::Group(g), + .. + }), + ) => gty == &g.ty, + ( + cl, + Some(Lexeme { + body: LexemeBody::Token(token), + .. + }), + ) => match (cl, token.ty) { + (Self::Character, TokenType::Character(_)) => true, + (Self::Lifetime, TokenType::Lifetime) => true, + (Self::Number, TokenType::Number) => true, + (Self::String, TokenType::String(_)) => true, + (Self::Punctuation(punct), TokenType::Punctuation) => { + Punctuation::from_token(&token.body) == *punct + } + ( + Self::Keyword(kw), + TokenType::Identifier(IdentifierType::Default | IdentifierType::Keyword), + ) => &token.body == kw.symbol(), + ( + Self::Identifier, + TokenType::Identifier(IdentifierType::Default | IdentifierType::Raw), + ) => true, + _ => false, + }, + _ => false, + } + } + pub fn is(&self, other: &Self) -> bool { self == other || (matches!(other, Self::Group(None)) && matches!(self, Self::Group(_))) } @@ -555,14 +608,15 @@ fn do_char(file: &mut Speekable>, start: Pos) -> Resu Ok(Token::new(TokenType::Character(CharType::Default), token) .with_span(Span::new_simple(start, end, file.file_name()))) } - Some((_, x)) if !x.is_xid_continue() => { - Ok(Token::new(TokenType::Lifetime, token) - .with_span(Span::new_simple(start, pos, file.file_name()))) - } - None => { - Ok(Token::new(TokenType::Lifetime, token) - .with_span(Span::new_simple(start, pos, file.file_name()))) - } + Some((_, x)) if !x.is_xid_continue() => Ok(Token::new(TokenType::Lifetime, token) + .with_span(Span::new_simple(start, pos, file.file_name()))), + None => Ok( + Token::new(TokenType::Lifetime, token).with_span(Span::new_simple( + start, + pos, + file.file_name(), + )), + ), Some(&(pos, x)) => { file.next(); token.push(x); @@ -575,8 +629,13 @@ fn do_char(file: &mut Speekable>, start: Pos) -> Resu end = pos; token.push(x); } - Ok(Token::new(TokenType::Lifetime, token) - .with_span(Span::new_simple(start, end, file.file_name()))) + Ok( + Token::new(TokenType::Lifetime, token).with_span(Span::new_simple( + start, + end, + file.file_name(), + )), + ) } } } @@ -608,324 +667,327 @@ fn do_str(file: &mut Speekable>) -> Result<(String, P fn do_lexeme(file: &mut Speekable>) -> Result { loop { match file.snext() { - Some((start, c)) => match c { - ' ' | '\n' => {} - '(' | '[' | '{' => { - let ty = GroupType::from_start_char(c); - let (body, end) = do_group(file, Some(ty.end_char()))?; - break Ok(Group { ty, body }.with_span(Span::new_simple( - start, - end, - file.file_name(), - ))); - } - '"' => { - let (str, end) = do_str(file)?; - break Ok(Token::new(TokenType::String(StringType::Default), str) - .with_span(Span::new_simple(start, end, file.file_name()))); - } - '0'..='9' => { - let mut id = String::from(c); - let mut end = start; - while let Some(&(pos, c)) = file.speek() { - if !c.is_xid_continue() { - break; - } else { - id.push(c); - end = pos; - file.next(); - } - } - break Ok( - Token::new(TokenType::Number, id).with_span(Span::new_simple( + Some((start, c)) => { + match c { + ' ' | '\n' => {} + '(' | '[' | '{' => { + let ty = GroupType::from_start_char(c); + let (body, end) = do_group(file, Some(ty.end_char()))?; + break Ok(Group { ty, body }.with_span(Span::new_simple( start, end, file.file_name(), - )), - ); - } - x if x.is_xid_start() || x == '_' => { - let mut id = String::from(x); - let mut end = start; - let mut ty = TokenType::Identifier(IdentifierType::Default); - while let Some(&(pos, c)) = file.speek() { - if !c.is_xid_continue() { - break; - } else { - id.push(c); - end = pos; - file.next(); + ))); + } + '"' => { + let (str, end) = do_str(file)?; + break Ok(Token::new(TokenType::String(StringType::Default), str) + .with_span(Span::new_simple(start, end, file.file_name()))); + } + '0'..='9' => { + let mut id = String::from(c); + let mut end = start; + while let Some(&(pos, c)) = file.speek() { + if !c.is_xid_continue() { + break; + } else { + id.push(c); + end = pos; + file.next(); + } } + break Ok( + Token::new(TokenType::Number, id).with_span(Span::new_simple( + start, + end, + file.file_name(), + )), + ); } - if id == "r" || id == "rb" { - match file.peek() { - Some('#') => { - id.push('#'); + x if x.is_xid_start() || x == '_' => { + let mut id = String::from(x); + let mut end = start; + let mut ty = TokenType::Identifier(IdentifierType::Default); + while let Some(&(pos, c)) = file.speek() { + if !c.is_xid_continue() { + break; + } else { + id.push(c); + end = pos; file.next(); - while let Some(&(pos, c)) = file.speek() { - if !c.is_xid_continue() { - break; - } else { - id.push(c); - end = pos; - file.next(); + } + } + if id == "r" || id == "rb" { + match file.peek() { + Some('#') => { + id.push('#'); + file.next(); + while let Some(&(pos, c)) = file.speek() { + if !c.is_xid_continue() { + break; + } else { + id.push(c); + end = pos; + file.next(); + } } + ty = TokenType::Identifier(IdentifierType::Raw); } - ty = TokenType::Identifier(IdentifierType::Raw); + Some('"') => todo!(), + _ => {} } - Some('"') => todo!(), - _ => {} - } - } else if id == "b" { - if file.peek() == Some(&'"') { - file.next(); - let (str, end) = do_str(file)?; - break Ok(Token::new(TokenType::String(StringType::Byte), id + &str) + } else if id == "b" { + if file.peek() == Some(&'"') { + file.next(); + let (str, end) = do_str(file)?; + break Ok(Token::new( + TokenType::String(StringType::Byte), + id + &str, + ) .with_span(Span::new_simple(start, end, file.file_name()))); - } else if file.peek() == Some(&'\'') { - file.next(); - let mut result = do_char(file, start)?; - match &mut result.body { - LexemeBody::Token(Token { ty: TokenType::Character(ref mut char_ty), .. }) => { - *char_ty = CharType::Byte; - }, - LexemeBody::Token(_) => { - todo!("validation error for \"byte lifetimes\""); + } else if file.peek() == Some(&'\'') { + file.next(); + let mut result = do_char(file, start)?; + match &mut result.body { + LexemeBody::Token(Token { + ty: TokenType::Character(ref mut char_ty), + .. + }) => { + *char_ty = CharType::Byte; + } + LexemeBody::Token(_) => { + todo!("validation error for \"byte lifetimes\""); + } + _ => unreachable!("do_char returns a Token always"), } - _ => unreachable!("do_char returns a Token always"), + break Ok(result); } - break Ok(result); } + break Ok(Token::new(ty, id).with_span(Span::new_simple( + start, + end, + file.file_name(), + ))); } - break Ok(Token::new(ty, id).with_span(Span::new_simple( - start, - end, - file.file_name(), - ))); - } - '/' => { - let (tok, end, ty) = match file.speek() { - Some(&(pos, '/')) => { - file.next(); - let mut tok = String::from("//"); - let mut end = pos; - while let Some((pos, c)) = file.snext() { - if c == '\n' { - break; + '/' => { + let (tok, end, ty) = match file.speek() { + Some(&(pos, '/')) => { + file.next(); + let mut tok = String::from("//"); + let mut end = pos; + while let Some((pos, c)) = file.snext() { + if c == '\n' { + break; + } + tok.push(c); + end = pos; } - tok.push(c); - end = pos; + (tok, end, TokenType::CommentSingle) } - (tok, end, TokenType::CommentSingle) - } - Some(&(pos, '*')) => { - file.next(); - let mut tok = String::from("/*"); - let mut end = pos; - let mut star = false; - while let Some((pos, c)) = file.snext() { - tok.push(c); - end = pos; - if c == '/' && star { - break; + Some(&(pos, '*')) => { + file.next(); + let mut tok = String::from("/*"); + let mut end = pos; + let mut star = false; + while let Some((pos, c)) = file.snext() { + tok.push(c); + end = pos; + if c == '/' && star { + break; + } + star = c == '*'; } - star = c == '*'; + (tok, end, TokenType::CommentMulti) } - (tok, end, TokenType::CommentMulti) - } - Some(&(end, '=')) => { - file.next(); - ("/=".into(), end, TokenType::Punctuation) - } - _ => ("/".into(), start, TokenType::Punctuation), - }; - break Ok(Token::new(ty, tok).with_span(Span::new_simple( - start, - end, - file.file_name(), - ))); - } - '\'' => break do_char(file, start), - '.' => { - let (punct, end) = match file.speek() { - Some(&(end, '.')) => { - file.next(); - match file.speek() { - Some(&(end, '.')) => { - file.next(); - ("...", end) - } - Some(&(end, '=')) => { - file.next(); - ("..=", end) + Some(&(end, '=')) => { + file.next(); + ("/=".into(), end, TokenType::Punctuation) + } + _ => ("/".into(), start, TokenType::Punctuation), + }; + break Ok(Token::new(ty, tok).with_span(Span::new_simple( + start, + end, + file.file_name(), + ))); + } + '\'' => break do_char(file, start), + '.' => { + let (punct, end) = match file.speek() { + Some(&(end, '.')) => { + file.next(); + match file.speek() { + Some(&(end, '.')) => { + file.next(); + ("...", end) + } + Some(&(end, '=')) => { + file.next(); + ("..=", end) + } + _ => ("..", end), } - _ => ("..", end), } - } - _ => (".", start), - }; - break Ok(Token::punct(punct).with_span(Span::new_simple( - start, - end, - file.file_name(), - ))); - } - '<' => { - let (punct, end) = match file.speek() { - Some(&(end, '<')) => { - file.next(); - match file.speek() { - Some(&(end, '=')) => { - file.next(); - ("<<=", end) + _ => (".", start), + }; + break Ok(Token::punct(punct).with_span(Span::new_simple( + start, + end, + file.file_name(), + ))); + } + '<' => { + let (punct, end) = match file.speek() { + Some(&(end, '<')) => { + file.next(); + match file.speek() { + Some(&(end, '=')) => { + file.next(); + ("<<=", end) + } + _ => ("<<", end), } - _ => ("<<", end), } - } - Some(&(end, '=')) => { - file.next(); - ("<=", end) - } - _ => ("<", start), - }; - break Ok(Token::punct(punct).with_span(Span::new_simple( - start, - end, - file.file_name(), - ))); - } - '>' => { - let (punct, end) = match file.speek() { - Some(&(end, '>')) => { - file.next(); - match file.speek() { - Some(&(end, '=')) => { - file.next(); - (">>=", end) + Some(&(end, '=')) => { + file.next(); + ("<=", end) + } + _ => ("<", start), + }; + break Ok(Token::punct(punct).with_span(Span::new_simple( + start, + end, + file.file_name(), + ))); + } + '>' => { + let (punct, end) = match file.speek() { + Some(&(end, '>')) => { + file.next(); + match file.speek() { + Some(&(end, '=')) => { + file.next(); + (">>=", end) + } + _ => (">>", end), } - _ => (">>", end), } - } - Some(&(end, '=')) => { - file.next(); - (">=", end) - } - _ => (">", start), - }; - break Ok(Token::punct(punct).with_span(Span::new_simple( - start, - end, - file.file_name(), - ))); - } - '|' => { - let (punct, end) = match file.speek() { - Some(&(end, '|')) => ("||", end), - Some(&(end, '=')) => { - file.next(); - ("|=", end) - } - _ => ("|", start), - }; - break Ok(Token::punct(punct).with_span(Span::new_simple( - start, - end, - file.file_name(), - ))); - } - ':' => { - let (punct, end) = match file.speek() { - Some(&(end, ':')) => { - file.next(); - ("::", end) - } - _ => (":", start), - }; - break Ok(Token::punct(punct).with_span(Span::new_simple( - start, - end, - file.file_name(), - ))); - } - '=' => { - let (punct, end) = match file.speek() { - Some(&(end, '=')) => { - file.next(); - ("==", end) - } - Some(&(end, '>')) => { - file.next(); - ("=>", end) - } - _ => ("=", start), - }; - break Ok(Token::punct(punct).with_span(Span::new_simple( - start, - end, - file.file_name(), - ))); - } - '&' => { - let (punct, end) = match file.speek() { - Some(&(end, '=')) => { - file.next(); - ("&=", end) - } - Some(&(end, '&')) => { - file.next(); - ("&&", end) - } - _ => ("&", start), - }; - break Ok(Token::punct(punct).with_span(Span::new_simple( - start, - end, - file.file_name(), - ))); - } - '+' | '*' | '!' => { - let (punct, end) = match file.speek() { - Some(&(end, '=')) => { - file.next(); - ("=", end) - } - _ => ("", start), - }; - break Ok( - Token::punct(String::from(c) + punct).with_span(Span::new_simple( + Some(&(end, '=')) => { + file.next(); + (">=", end) + } + _ => (">", start), + }; + break Ok(Token::punct(punct).with_span(Span::new_simple( start, end, file.file_name(), - )), - ); - } - '-' => { - let (punct, end) = match file.speek() { - Some(&(end, '>')) => { - file.next(); - ("->", end) - } - Some(&(end, '=')) => { - file.next(); - ("-=", end) - } - _ => ("-", start), - }; - break Ok(Token::punct(punct).with_span(Span::new_simple( - start, - end, - file.file_name(), - ))); - } - ';' | '#' | ',' | '@' => { - break Ok(Token::punct(String::from(c)).with_span(Span::new_simple( - start, - start, - file.file_name(), - ))); + ))); + } + '|' => { + let (punct, end) = match file.speek() { + Some(&(end, '|')) => ("||", end), + Some(&(end, '=')) => { + file.next(); + ("|=", end) + } + _ => ("|", start), + }; + break Ok(Token::punct(punct).with_span(Span::new_simple( + start, + end, + file.file_name(), + ))); + } + ':' => { + let (punct, end) = match file.speek() { + Some(&(end, ':')) => { + file.next(); + ("::", end) + } + _ => (":", start), + }; + break Ok(Token::punct(punct).with_span(Span::new_simple( + start, + end, + file.file_name(), + ))); + } + '=' => { + let (punct, end) = match file.speek() { + Some(&(end, '=')) => { + file.next(); + ("==", end) + } + Some(&(end, '>')) => { + file.next(); + ("=>", end) + } + _ => ("=", start), + }; + break Ok(Token::punct(punct).with_span(Span::new_simple( + start, + end, + file.file_name(), + ))); + } + '&' => { + let (punct, end) = match file.speek() { + Some(&(end, '=')) => { + file.next(); + ("&=", end) + } + Some(&(end, '&')) => { + file.next(); + ("&&", end) + } + _ => ("&", start), + }; + break Ok(Token::punct(punct).with_span(Span::new_simple( + start, + end, + file.file_name(), + ))); + } + '+' | '*' | '!' => { + let (punct, end) = match file.speek() { + Some(&(end, '=')) => { + file.next(); + ("=", end) + } + _ => ("", start), + }; + break Ok(Token::punct(String::from(c) + punct) + .with_span(Span::new_simple(start, end, file.file_name()))); + } + '-' => { + let (punct, end) = match file.speek() { + Some(&(end, '>')) => { + file.next(); + ("->", end) + } + Some(&(end, '=')) => { + file.next(); + ("-=", end) + } + _ => ("-", start), + }; + break Ok(Token::punct(punct).with_span(Span::new_simple( + start, + end, + file.file_name(), + ))); + } + ';' | '#' | ',' | '@' => { + break Ok(Token::punct(String::from(c)).with_span(Span::new_simple( + start, + start, + file.file_name(), + ))); + } + x => Err(Error::UnrecognizedChar(x, start))?, } - x => Err(Error::UnrecognizedChar(x, start))?, - }, + } None => Err(Error::UnexpectedEof(file.last_pos()))?, } } diff --git a/rust/src/parse.rs b/rust/src/parse.rs index 38bc0ef4..4a0971e1 100644 --- a/rust/src/parse.rs +++ b/rust/src/parse.rs @@ -4,13 +4,13 @@ use peekmore::{PeekMore, PeekMoreIterator}; use crate::{ ast::{ - AsyncBlock, Attr, AttrInput, BinaryOp, Block, CaptureSpec, Closure, ClosureParam, + AsyncBlock, Attr, AttrInput, Auto, BinaryOp, Block, CaptureSpec, Closure, ClosureParam, CompoundBlock, ConstParam, Constructor, ConstructorExpr, Expr, ExternBlock, FieldInit, Function, GenericBound, GenericParam, GenericParams, Item, ItemBody, ItemValue, Label, LetStatement, Lifetime, LifetimeParam, Literal, LiteralKind, Mod, Param, Path, PathSegment, - Pattern, SimplePath, SimplePathSegment, Spanned, Statement, StructCtor, StructField, - StructKind, TupleCtor, TupleField, Type, TypeParam, UnaryOp, UserType, UserTypeBody, - Visibility, WhereClause, + Pattern, Safety, SimplePath, SimplePathSegment, Spanned, Statement, StructCtor, + StructField, StructKind, TraitDef, TupleCtor, TupleField, Type, TypeParam, UnaryOp, + UserType, UserTypeBody, Visibility, WhereClause, }, interning::Symbol, lex::{ @@ -123,14 +123,23 @@ impl<'a, T: Iterator> IntoRewinder<'a> for &'a mut PeekMoreIterat } } +pub fn expect( + tree: &mut PeekMoreIterator>, + expected: &[LexemeClass], +) -> Result<()> { + // Note: Intentionally forgetting this + let mut tree = tree.into_rewinder(); + do_lexeme_classes(&mut tree, expected).map(drop) +} + pub fn do_lexeme_class( tree: &mut PeekMoreIterator>, expected: LexemeClass, ) -> Result { let mut tree = tree.into_rewinder(); let lexeme = tree.peek(); - let got = LexemeClass::of(lexeme); - if got.is(&expected) { + + if expected.matches(lexeme) { let result = lexeme.unwrap().clone(); tree.advance_cursor(); tree.accept(); @@ -142,7 +151,7 @@ pub fn do_lexeme_class( ); Err(Error { expected: vec![expected], - got, + got: LexemeClass::of(lexeme), span, }) } @@ -222,6 +231,17 @@ pub fn do_token_classes( Err(error.unwrap()) } +pub fn do_identifier>( + tree: &mut PeekMoreIterator, +) -> Result> { + let (span, tok) = do_lexeme_token(tree, LexemeClass::Identifier)?; + + Ok(Spanned { + span, + body: tok.body, + }) +} + pub fn do_alternation>( tree: &mut PeekMoreIterator, alternates: &[fn(&mut PeekMoreIterator) -> Result>], @@ -2549,41 +2569,155 @@ pub fn do_item_extern_block( }) } -pub fn do_item(tree: &mut PeekMoreIterator>) -> Result> { +pub fn do_item_trait( + tree: &mut PeekMoreIterator>, +) -> Result> { let mut tree = tree.into_rewinder(); - let vis = do_visibility(&mut tree).ok(); - let item = match do_item_mod(&mut tree) { - Ok(body) => body, - Err(a) => match do_item_value(&mut tree) { - Ok(body) => body, - Err(b) => match do_item_extern_crate(&mut tree) { - Ok(body) => body, - Err(c) => match do_item_use(&mut tree) { - Ok(body) => body, - Err(d) => match do_item_user_type(&mut tree) { - Ok(body) => body, - Err(e) => match do_item_fn(&mut tree) { - Ok(body) => body, - Err(f) => match do_item_extern_block(&mut tree) { - Ok(body) => body, - Err(g) => Err(a | b | c | d | e | f | g)?, - }, - }, - }, - }, + expect( + &mut tree, + &[keyword!(unsafe), keyword!(auto), keyword!(trait)], + )?; + let mut startspan = None; + + let safety = match do_lexeme_class(&mut tree, keyword!(unsafe)) { + Ok(tok) => { + startspan.get_or_insert(tok.span); + Some(Spanned { + body: Safety::Unsafe, + span: tok.span, + }) + } + Err(_) => None, + }; + + let auto = match do_lexeme_class(&mut tree, keyword!(auto)) { + Ok(tok) => { + startspan.get_or_insert(tok.span); + Some(Spanned { + body: Auto, + span: tok.span, + }) + } + Err(_) => None, + }; + + do_lexeme_class(&mut tree, keyword!(trait))?; + + let name = do_identifier(&mut tree)?; + + let startspan = startspan.unwrap_or(name.span); + + let generics = do_generic_params(&mut tree).ok(); + + let supertraits = match do_lexeme_token(&mut tree, punct!(:)) { + Ok(_) => { + let mut bounds_list = Vec::new(); + loop { + match do_type_bound(&mut tree) { + Ok(bound) => bounds_list.push(bound), + Err(e) => break, + } + + match do_lexeme_classes(&mut tree, &[punct!(+)]) { + Ok(_) => continue, + Err(e) => break, + } + } + Some(bounds_list) + } + Err(_) => None, + }; + + let where_clauses = do_where_clauses(&mut tree).ok(); + + let mut body = Vec::new(); + + let (group, gspan) = do_lexeme_group(&mut tree, Some(GroupType::Braces))?; + + let mut inner_tree = group.body.into_iter().peekmore(); + + loop { + match do_item_in_trait(&mut inner_tree) { + Ok(item) => body.push(item), + Err(e) => match do_lexeme_class(&mut inner_tree, LexemeClass::Eof) { + Ok(_) => break, + Err(d) => return Err(e | d), }, - }, + } + } + + let body = TraitDef { + safety, + auto, + name, + generics, + supertraits, + where_clauses, + body, }; + + let span = Span::between(startspan, gspan); + + tree.accept(); + + Ok(Spanned { + body: ItemBody::Trait(Spanned { span, body }), + span, + }) +} + +pub fn do_item_in_trait( + tree: &mut PeekMoreIterator>, +) -> Result> { + let mut tree = tree.into_rewinder(); + let mut attrs = Vec::new(); + loop { + match do_external_attr(&mut tree) { + Ok(attr) => attrs.push(attr), + Err(_) => break, + } + } + let vis = do_visibility(&mut tree).ok(); + let item = do_alternation(&mut tree, &[do_item_fn, do_item_value])?; let span = vis.as_ref().map_or(item.span, |Spanned { span, .. }| { Span::between(*span, item.span) }); tree.accept(); Ok(Spanned { - body: Item { - vis, - attrs: vec![], - item, - }, + body: Item { vis, attrs, item }, + span, + }) +} + +pub fn do_item(tree: &mut PeekMoreIterator>) -> Result> { + let mut tree = tree.into_rewinder(); + let mut attrs = Vec::new(); + loop { + match do_external_attr(&mut tree) { + Ok(attr) => attrs.push(attr), + Err(_) => break, + } + } + let vis = do_visibility(&mut tree).ok(); + let item = do_alternation( + &mut tree, + &[ + do_item_mod, + do_item_extern_block, + do_item_extern_crate, + do_item_fn, + do_item_value, + do_item_use, + do_item_user_type, + do_item_trait, + ], + )?; + let span = vis.as_ref().map_or(item.span, |Spanned { span, .. }| { + Span::between(*span, item.span) + }); + tree.accept(); + Ok(Spanned { + body: Item { vis, attrs, item }, span, }) } @@ -2599,15 +2733,12 @@ pub fn do_mod(tree: &mut PeekMoreIterator>) -> Resu tree.truncate_iterator_to_cursor(); match do_internal_attr(tree) { Ok(attr) => attrs.push(attr), - Err(x) => match do_external_attr(tree) { - Ok(attr) => external_attrs.push(attr), - Err(y) => match do_item(tree) { - Ok(mut item) => { - item.attrs.append(&mut external_attrs); - items.push(item); - } - Err(z) => Err(x | y | z)?, - }, + Err(x) => match do_item(tree) { + Ok(mut item) => { + item.attrs.append(&mut external_attrs); + items.push(item); + } + Err(z) => Err(x | z)?, }, } } diff --git a/rust/src/sema.rs b/rust/src/sema.rs index b718cac8..e7a913aa 100644 --- a/rust/src/sema.rs +++ b/rust/src/sema.rs @@ -2065,6 +2065,7 @@ fn collect_types(defs: &mut Definitions, curmod: DefId, md: &Spanned) ast::ItemBody::MacroRules(_) => { unreachable!("macros are expanded before semantic analysis") } + ast::ItemBody::Trait(_) => todo!("trait"), } } @@ -2413,6 +2414,7 @@ fn collect_values(defs: &mut Definitions, curmod: DefId, md: &Spanned) ast::ItemBody::MacroRules(_) => { unreachable!("macros are expanded before semantic analysis") } + ast::ItemBody::Trait(_) => todo!("trait"), } } @@ -2478,6 +2480,7 @@ pub fn convert_types(defs: &mut Definitions, curmod: DefId, md: &Spanned { unreachable!("macros are expanded before semantic analysis") } + ast::ItemBody::Trait(_) => todo!("trait"), } } @@ -2541,6 +2544,7 @@ pub fn convert_values(defs: &mut Definitions, curmod: DefId, md: &Spanned {} ast::ItemBody::MacroRules(_) => unreachable!(), + ast::ItemBody::Trait(_) => todo!("trait"), } }