diff --git a/parser/src/ast.rs b/parser/src/ast.rs index 2c50171..a003af4 100644 --- a/parser/src/ast.rs +++ b/parser/src/ast.rs @@ -1,6 +1,8 @@ +use std::fmt::{Debug, Formatter}; + use dbg_pls::DebugPls; -use crate::{Span, Spanned}; +use crate::Spanned; #[derive(Debug, DebugPls)] pub enum TypeSpecifier { @@ -24,13 +26,45 @@ pub enum TypeSpecifier { pub type Ident = Spanned; -#[derive(Debug, Default, DebugPls)] +#[derive(Default)] pub struct DeclAttr { pub is_extern: bool, pub is_static: bool, pub is_thread_local: bool, } +impl Debug for DeclAttr { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let mut d = f.debug_set(); + if self.is_extern { + d.entry(&"extern"); + } + if self.is_static { + d.entry(&"static"); + } + if self.is_thread_local { + d.entry(&"thread_local"); + } + d.finish() + } +} + +impl DebugPls for DeclAttr { + fn fmt(&self, f: dbg_pls::Formatter<'_>) { + let mut d = f.debug_set(); + if self.is_extern { + d = d.entry(&"extern"); + } + if self.is_static { + d = d.entry(&"static"); + } + if self.is_thread_local { + d = d.entry(&"thread_local"); + } + d.finish(); + } +} + #[derive(Debug, DebugPls)] pub struct DeclSpec { pub ty: TypeSpecifier, @@ -55,12 +89,18 @@ pub struct NormalDecl { pub init_declarators: Vec>, } +#[derive(Debug, DebugPls)] +pub struct FunctionParamDecl { + pub decl_spec: Spanned, + pub declarator: Spanned, +} + #[derive(Debug, DebugPls)] pub enum DirectDeclarator { Ident(Ident), WithParams { ident: Ident, - params: Vec, + params: Vec, }, } @@ -70,18 +110,6 @@ pub struct Declarator { pub pointer: bool, } -#[derive(Debug, DebugPls)] -pub struct FunctionParamDecl { - pub decl_spec: DeclSpec, - pub declarator: Declarator, -} - -#[derive(Debug, DebugPls)] -pub enum FunctionParams { - Void(Span), - List(Vec>), -} - #[derive(Debug, DebugPls)] pub struct FunctionDef { pub declaration: Decl, diff --git a/parser/src/parser.rs b/parser/src/parser.rs index b34f653..e874d18 100644 --- a/parser/src/parser.rs +++ b/parser/src/parser.rs @@ -3,7 +3,7 @@ use peekmore::PeekMoreIterator; use crate::{ ast::{ Decl, DeclAttr, DeclSpec, Declarator, DirectDeclarator, ExternalDecl, FunctionDef, - FunctionParams, Ident, InitDecl, NormalDecl, TypeSpecifier, + FunctionParamDecl, Ident, InitDecl, NormalDecl, TypeSpecifier, }, pre::Punctuator as Punct, token::{Keyword as Kw, Token as Tok}, @@ -154,14 +154,14 @@ where // ----------------------- /// (6.7) declaration: - /// declaration-specifiers init-declarator-listopt ; + /// declaration-specifiers init-declarator-list.opt ; /// static_assert-declaration fn declaration(&mut self) -> Result> { if let Some((tok, span)) = eat!(self, Tok::Kw(Kw::StaticAssert)) { return Err(ParserError::unsupported(span, &tok)); } - let (decl_spec, span) = self.declaration_specifiers()?; + let (decl_spec, span) = self.decl_specifiers()?; let init_declarators = self.init_declarator_list()?; let init_declarators_span = Span::span_of_spanned_list(&init_declarators); @@ -187,11 +187,7 @@ where fn init_declarator_list(&mut self) -> Result>> { let mut init_decls = Vec::new(); let mut first = true; - loop { - println!("LOOOOP"); - if !self.is_peek_tok_start_of_declarator() && !self.is_peek_comma() { - break; - } + while self.is_peek_tok_start_of_declarator() || self.is_peek_comma() { if !first { expect!(self, Tok::Punct(Punct::Comma)); } @@ -217,7 +213,7 @@ where /// type-qualifier declaration-specifiers.opt /// function-specifier declaration-specifiers.opt /// alignment-specifier declaration-specifiers.opt - fn declaration_specifiers(&mut self) -> Result> { + fn decl_specifiers(&mut self) -> Result> { let mut decl_attr = DeclAttr::default(); let &(_, initial_span) = self.peek_t()?; let (ty, span) = loop { @@ -299,48 +295,72 @@ where /// facing. For example: `int uwu` vs `int uwu()`. The parentheses indicate a function /// declaration. Therefore, we have no idea what we're parsing before entering this function. fn declarator(&mut self) -> Result> { - if let Some((_, span)) = eat!(self, Tok::Punct(Punct::Asterisk)) { - let (decl, span2) = self.direct_declarator()?; - - Ok(( - Declarator { - decl, - pointer: true, - }, - span.extend(span2), - )) + let pointer_span = if let Some((_, span)) = eat!(self, Tok::Punct(Punct::Asterisk)) { + Some(span) } else { - let (decl, span) = self.direct_declarator()?; + None + }; - Ok(( - Declarator { - decl, - pointer: false, - }, - span, - )) - } + let (decl, span) = self.direct_declarator()?; + + let declarator = Declarator { + decl, + pointer: pointer_span.is_some(), + }; + + let span = pointer_span.map(|s| s.extend(span)).unwrap_or(span); + + Ok((declarator, span)) } /// direct-declarator: /// identifier /// ( declarator ) - /// direct-declarator \[ type-qualifier-listopt assignment-expressionopt ] - /// direct-declarator \[ static type-qualifier-listopt assignment-expression ] + /// direct-declarator \[ type-qualifier-list.opt assignment-expression.opt ] + /// direct-declarator \[ static type-qualifier-list.opt assignment-expression ] /// direct-declarator \[ type-qualifier-list static assignment-expression ] - /// direct-declarator \[ type-qualifier-listopt * ] + /// direct-declarator \[ type-qualifier-list.opt * ] /// direct-declarator ( parameter-type-list ) - /// direct-declarator ( identifier-listopt ) + /// direct-declarator ( identifier-list.opt ) fn direct_declarator(&mut self) -> Result> { let (ident, span) = self.ident()?; if (eat!(self, Tok::Punct(Punct::ParenOpen))).is_some() { + let mut params = Vec::new(); + let mut first = true; + + while self.is_peek_tok_start_of_ty() || self.is_peek_comma() { + if first { + // the wrong way around because borrowing + if let (Tok::Punct(Punct::ParenClose), _) = self.peek_t_n(1)? { + if let &(ref tok @ Tok::Kw(Kw::Void), span) = self.peek_t()? { + return Err(ParserError::unsupported(span, tok)); + } + } + } + + if !first { + expect!(self, Tok::Punct(Punct::Comma)); + } + first = false; + + let decl_spec = self.decl_specifiers()?; + // abstract declarator actually + let declarator = self.declarator()?; + + let function_param_decl = FunctionParamDecl { + decl_spec, + declarator, + }; + params.push(function_param_decl); + } + // nothing in the params supported yet. expect!(self, Tok::Punct(Punct::ParenClose)); return Ok(( DirectDeclarator::WithParams { ident: (ident, span), - params: Vec::new(), + params, }, span, )); @@ -384,22 +404,6 @@ where } Ok(decls) } - - fn function_param_declaration_list(&mut self) -> Result { - // If the declarator includes a parameter type list, the declaration of each parameter shall - // include an identifier, except for the special case of a parameter list consisting of a single - // parameter of type void, in which case there shall not be an identifier. No declaration list - // shall follow. - if let &(Tok::Kw(Kw::Void), span) = self.peek_t()? { - if let (Tok::Punct(Punct::ParenClose), _) = self.peek_t_n(1)? { - self.next_t()?; - self.next_t()?; - return Ok(FunctionParams::Void(span)); - } - } - - todo!() - } } #[cfg(test)] diff --git a/parser/src/parser/snapshots/parser__parser__tests__empty_function_with_params.snap b/parser/src/parser/snapshots/parser__parser__tests__empty_function_with_params.snap new file mode 100644 index 0000000..c62ab7e --- /dev/null +++ b/parser/src/parser/snapshots/parser__parser__tests__empty_function_with_params.snap @@ -0,0 +1,85 @@ +--- +source: parser/src/parser/tests.rs +expression: parsed +--- +Ok( + [ + ( + FunctionDef( + FunctionDef { + declaration: Normal( + NormalDecl { + decl_spec: DeclSpec { + ty: Int, + attrs: {}, + }, + init_declarators: [ + ( + InitDecl { + declarator: Declarator { + decl: WithParams { + ident: ( + "uwu", + 5..8, + ), + params: [ + FunctionParamDecl { + decl_spec: ( + DeclSpec { + ty: Long, + attrs: {}, + }, + 9..13, + ), + declarator: ( + Declarator { + decl: Ident( + ( + "owo", + 14..17, + ), + ), + pointer: false, + }, + 14..17, + ), + }, + FunctionParamDecl { + decl_spec: ( + DeclSpec { + ty: Int, + attrs: {}, + }, + 19..22, + ), + declarator: ( + Declarator { + decl: Ident( + ( + "qwq", + 23..26, + ), + ), + pointer: false, + }, + 23..26, + ), + }, + ], + }, + pointer: false, + }, + init: None, + }, + 5..8, + ), + ], + }, + ), + body: [], + }, + ), + 1..30, + ), + ], +) diff --git a/parser/src/parser/snapshots/parser__parser__tests__empty_funky_attributes_no_params_function.snap b/parser/src/parser/snapshots/parser__parser__tests__empty_funky_attributes_no_params_function.snap index 0e873fa..f413ca1 100644 --- a/parser/src/parser/snapshots/parser__parser__tests__empty_funky_attributes_no_params_function.snap +++ b/parser/src/parser/snapshots/parser__parser__tests__empty_funky_attributes_no_params_function.snap @@ -11,10 +11,9 @@ Ok( NormalDecl { decl_spec: DeclSpec { ty: Int, - attrs: DeclAttr { - is_extern: true, - is_static: false, - is_thread_local: true, + attrs: { + "extern", + "thread_local", }, }, init_declarators: [ diff --git a/parser/src/parser/snapshots/parser__parser__tests__empty_void_function.snap b/parser/src/parser/snapshots/parser__parser__tests__empty_void_function.snap index 8ef8cb4..d062102 100644 --- a/parser/src/parser/snapshots/parser__parser__tests__empty_void_function.snap +++ b/parser/src/parser/snapshots/parser__parser__tests__empty_void_function.snap @@ -11,11 +11,7 @@ Ok( NormalDecl { decl_spec: DeclSpec { ty: Void, - attrs: DeclAttr { - is_extern: false, - is_static: false, - is_thread_local: false, - }, + attrs: {}, }, init_declarators: [ ( diff --git a/parser/src/parser/snapshots/parser__parser__tests__global_variable_declarations.snap b/parser/src/parser/snapshots/parser__parser__tests__global_variable_declarations.snap index 955566c..d3c59e6 100644 --- a/parser/src/parser/snapshots/parser__parser__tests__global_variable_declarations.snap +++ b/parser/src/parser/snapshots/parser__parser__tests__global_variable_declarations.snap @@ -10,11 +10,7 @@ Ok( NormalDecl { decl_spec: DeclSpec { ty: Int, - attrs: DeclAttr { - is_extern: false, - is_static: false, - is_thread_local: false, - }, + attrs: {}, }, init_declarators: [ ( @@ -44,10 +40,8 @@ Ok( NormalDecl { decl_spec: DeclSpec { ty: Double, - attrs: DeclAttr { - is_extern: false, - is_static: false, - is_thread_local: true, + attrs: { + "thread_local", }, }, init_declarators: [ @@ -87,5 +81,36 @@ Ok( ), 11..40, ), + ( + Decl( + Normal( + NormalDecl { + decl_spec: DeclSpec { + ty: Int, + attrs: {}, + }, + init_declarators: [ + ( + InitDecl { + declarator: Declarator { + decl: WithParams { + ident: ( + "function", + 68..76, + ), + params: [], + }, + pointer: false, + }, + init: None, + }, + 68..76, + ), + ], + }, + ), + ), + 64..76, + ), ], ) diff --git a/parser/src/parser/tests.rs b/parser/src/parser/tests.rs index 83d7feb..56ae862 100644 --- a/parser/src/parser/tests.rs +++ b/parser/src/parser/tests.rs @@ -3,7 +3,7 @@ use std::fmt::Debug; use super::{Parser, Tok}; use crate::Span; -fn lex_and_pre<'src>(src: &'src str) -> impl Iterator, Span)> + 'src { +fn lex_and_pre(src: &str) -> impl Iterator, Span)> + '_ { let pre_tokens = crate::pre::preprocess_tokens(src); crate::token::pre_tokens_to_tokens(pre_tokens) } @@ -28,38 +28,40 @@ macro_rules! parse_test { #[test] fn empty_void_function() { - let src = r#" + parse_test!( + r#" void uwu() {} - "#; - - parse_test!(src); + "# + ); } #[test] fn empty_funky_attributes_no_params_function() { - let src = r#" + parse_test!( + r#" extern volatile _Thread_local int uwu() {} - "#; - - parse_test!(src); + "# + ); } #[test] -#[ignore = "fix declarator mess"] fn empty_function_with_params() { - let src = r#" -int uwu(long owo, unsigned qwq) {} - "#; - - parse_test!(src); + parse_test!( + r#" +int uwu(long owo, int qwq) {} + "# + ); } #[test] fn global_variable_declarations() { - let src = r#" + parse_test!( + r#" int test; _Thread_local double uwu, owo; - "#; - parse_test!(src); +// oh no, a function +int function(); + "# + ); }