diff --git a/parser/src/ast.rs b/parser/src/ast.rs index 2a5eb42..2c50171 100644 --- a/parser/src/ast.rs +++ b/parser/src/ast.rs @@ -1,8 +1,6 @@ use dbg_pls::DebugPls; -use crate::Span; - -pub type Spanned = (T, Span); +use crate::{Span, Spanned}; #[derive(Debug, DebugPls)] pub enum TypeSpecifier { @@ -40,16 +38,21 @@ pub struct DeclSpec { } #[derive(Debug, DebugPls)] -pub enum Declaration { - Normal(NormalDeclaration), +pub enum Decl { + Normal(NormalDecl), StaticAssert, } #[derive(Debug, DebugPls)] -pub struct NormalDeclaration { - pub decl_spec: DeclSpec, +pub struct InitDecl { pub declarator: Declarator, - pub initializer: Option<()>, + pub init: Option<()>, +} + +#[derive(Debug, DebugPls)] +pub struct NormalDecl { + pub decl_spec: DeclSpec, + pub init_declarators: Vec>, } #[derive(Debug, DebugPls)] @@ -57,7 +60,7 @@ pub enum DirectDeclarator { Ident(Ident), WithParams { ident: Ident, - params: Vec, + params: Vec, }, } @@ -74,15 +77,19 @@ pub struct FunctionParamDecl { } #[derive(Debug, DebugPls)] -pub enum FunctionParameters { +pub enum FunctionParams { Void(Span), - List(Vec>), + List(Vec>), } #[derive(Debug, DebugPls)] -pub struct FunctionDefinition { - pub decl_spec: Spanned, - pub name: Ident, - pub parameter_list: FunctionParameters, +pub struct FunctionDef { + pub declaration: Decl, pub body: Vec<()>, } + +#[derive(Debug, DebugPls)] +pub enum ExternalDecl { + Decl(Decl), + FunctionDef(FunctionDef), +} diff --git a/parser/src/lib.rs b/parser/src/lib.rs index f931b59..44dd2a9 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -8,6 +8,8 @@ mod parser; mod pre; mod token; +pub type Spanned = (T, Span); + #[derive(PartialEq, Eq, Clone, Copy, Default)] pub struct Span { pub start: usize, @@ -22,6 +24,16 @@ impl Span { pub fn extend(&self, rhs: Self) -> Self { Self::start_end(self.start, rhs.end) } + + pub fn extend_option(&self, rhs: Option) -> Self { + rhs.map(|s| self.extend(s)).unwrap_or(*self) + } + + pub fn span_of_spanned_list(list: &[Spanned]) -> Option { + list.iter().fold(None, |old_span, &(_, span)| { + Some(old_span.map(|s| s.extend(span)).unwrap_or(span)) + }) + } } impl dbg_pls::DebugPls for Span { diff --git a/parser/src/parser.rs b/parser/src/parser.rs index 110ea14..664e6a7 100644 --- a/parser/src/parser.rs +++ b/parser/src/parser.rs @@ -2,12 +2,12 @@ use peekmore::PeekMoreIterator; use crate::{ ast::{ - DeclAttr, DeclSpec, Declaration, Declarator, DirectDeclarator, FunctionDefinition, - FunctionParamDecl, FunctionParameters, Ident, Spanned, TypeSpecifier, + Decl, DeclAttr, DeclSpec, Declarator, DirectDeclarator, ExternalDecl, FunctionDef, + FunctionParams, Ident, InitDecl, NormalDecl, TypeSpecifier, }, pre::Punctuator as Punct, token::{Keyword as Kw, Token as Tok}, - Span, + Span, Spanned, }; #[derive(Debug)] @@ -89,6 +89,14 @@ fn is_tok_start_of_ty(tok: &Tok<'_>) -> bool { } } +/// Can be called for the start of a sequence of tokens that could be a type. +fn is_tok_start_of_declarator(tok: &Tok<'_>) -> bool { + matches!( + tok, + Tok::Ident(_) | Tok::Punct(Punct::ParenOpen | Punct::Asterisk) + ) +} + impl<'src, I> Parser<'src, I> where I: Iterator, Span)>, @@ -130,6 +138,17 @@ where } } + fn is_peek_tok_start_of_declarator(&mut self) -> bool { + match self.peek_t() { + Ok((tok, _)) => is_tok_start_of_declarator(tok), + Err(_) => false, + } + } + + fn is_peek_comma(&mut self) -> bool { + matches!(self.peek_t(), Ok((Tok::Punct(Punct::Comma), _))) + } + // ----------------------- // Declarations // ----------------------- @@ -137,25 +156,59 @@ where /// (6.7) declaration: /// declaration-specifiers init-declarator-listopt ; /// static_assert-declaration - fn declaration(&mut self) -> Result> { - if let &(tok @ Tok::Kw(Kw::StaticAssert), span) = self.peek_t()? { - self.next_t()?; + fn declaration(&mut self) -> Result> { + if let Some((tok, span)) = eat!(self, Tok::Kw(Kw::StaticAssert)) { return Err(ParserError::unsupported(span, &tok)); } - // first, some declaration-specifiers - let _decl_spec = self.declaration_specifiers()?; - // then (optionally), a declarator - // (6.7.6) declarator: - // pointer.opt direct-declarator - if let &(tok @ Tok::Punct(Punct::Asterisk), span) = self.peek_t()? { - self.next_t()?; - return Err(ParserError::unsupported(span, &tok)); + let (decl_spec, span) = self.declaration_specifiers()?; + + let init_declarators = self.init_declarator_list()?; + let init_declarators_span = Span::span_of_spanned_list(&init_declarators); + + let span = span.extend_option(init_declarators_span); + + Ok(( + Decl::Normal(NormalDecl { + decl_spec, + init_declarators, + }), + span, + )) + } + + /// init-declarator-list: + /// init-declarator + /// init-declarator-list , init-declarator + /// + /// init-declarator: + /// declarator + /// declarator = initializer + 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; + } + if !first { + expect!(self, Tok::Punct(Punct::Comma)); + } + first = false; + + let (declarator, span) = self.declarator()?; + if let Some((token, span)) = eat!(self, Tok::Punct(Punct::Eq)) { + return Err(ParserError::unsupported(span, &token)); + } + let init_decl = InitDecl { + declarator, + init: None, + }; + init_decls.push((init_decl, span)); } - // then (optionally), an initializer - - todo!("this doesn't work like this") + Ok(init_decls) } /// (6.7) declaration-specifiers: @@ -282,7 +335,15 @@ where let (ident, span) = self.ident()?; if (eat!(self, Tok::Punct(Punct::ParenOpen))).is_some() { - todo!("haha, no parentheses for you!") + // nothing in the params supported yet. + expect!(self, Tok::Punct(Punct::ParenClose)); + return Ok(( + DirectDeclarator::WithParams { + ident: (ident, span), + params: Vec::new(), + }, + span, + )); } Ok((DirectDeclarator::Ident((ident, span)), span)) @@ -295,58 +356,26 @@ where /// (6.9) external-declaration: /// function-definition /// declaration - fn external_declaration(&mut self) -> Result> { - if let Some((token, span)) = eat!(self, Tok::Kw(Kw::StaticAssert)) { - return Err(ParserError::unsupported(span, &token)); + fn external_declaration(&mut self) -> Result> { + let (declaration, span) = self.declaration()?; + + // the declaration might be a function definition + if eat!(self, Tok::Punct(Punct::BraceOpen)).is_some() { + let span2 = expect!(self, Tok::Punct(Punct::BraceClose)); + + Ok(( + ExternalDecl::FunctionDef(FunctionDef { + declaration, + body: Vec::new(), + }), + span.extend(span2), + )) + } else { + Ok((ExternalDecl::Decl(declaration), span)) } - - let decl_spec = self.declaration_specifiers()?; - - // TODO: We just assume that it's a function, that's terrible! - - self.function_definition(decl_spec) } - /// (6.9.1) function-definition: - /// declaration-specifiers declarator declaration-list.opt compound-statement - /// IMPORTANT TODO DO NOT FORGET THIS IS MISSION CRITICAL - /// THERE ARE RULES FOR parameter-type-list - /// WE ARE IN direct-declarator HERE - /// USE THIS - /// DO NOT DO THIS WRONGLY - /// C IS ONLY HALF HAS SHITTY AS IT SOUNDS - /// OK BUT HALF IS STILL A LOT - fn function_definition( - &mut self, - decl_spec: Spanned, - ) -> Result> { - let _oh_fuck = self.declarator()?; - - let declarator = self.ident()?; - - let decl_spec_span = decl_spec.1; - - expect!(self, Tok::Punct(Punct::ParenOpen)); - - let declaration_list = self.function_param_declaration_list()?; - - expect!(self, Tok::Punct(Punct::ParenClose)); - - expect!(self, Tok::Punct(Punct::BraceOpen)); - - let def = FunctionDefinition { - decl_spec, - name: declarator, - parameter_list: declaration_list, - body: Vec::new(), - }; - - let last = expect!(self, Tok::Punct(Punct::BraceClose)); - - Ok((def, decl_spec_span.extend(last))) - } - - fn function_param_declaration_list(&mut self) -> Result { + 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 @@ -355,36 +384,11 @@ where if let (Tok::Punct(Punct::ParenClose), _) = self.peek_t_n(1)? { self.next_t()?; self.next_t()?; - return Ok(FunctionParameters::Void(span)); + return Ok(FunctionParams::Void(span)); } } - let mut params = Vec::new(); - - if self.is_peek_tok_start_of_ty() { - let (decl_spec, span1) = self.declaration_specifiers()?; - let (declarator, span2) = self.declarator()?; - let param = FunctionParamDecl { - decl_spec, - declarator, - }; - - params.push((param, span1.extend(span2))); - } - - while self.is_peek_tok_start_of_ty() { - expect!(self, Tok::Punct(Punct::Comma)); - let (decl_spec, span1) = self.declaration_specifiers()?; - let (declarator, span2) = self.declarator()?; - let param = FunctionParamDecl { - decl_spec, - declarator, - }; - - params.push((param, span1.extend(span2))); - } - - Ok(FunctionParameters::List(todo!())) + todo!() } } 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 1b6d7f9..2db9212 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 @@ -4,27 +4,41 @@ expression: parsed --- Ok( ( - FunctionDefinition { - decl_spec: ( - DeclSpec { - ty: Int, - attrs: DeclAttr { - is_extern: true, - is_static: false, - is_thread_local: true, + FunctionDef( + FunctionDef { + declaration: Normal( + NormalDecl { + decl_spec: DeclSpec { + ty: Int, + attrs: DeclAttr { + is_extern: true, + is_static: false, + is_thread_local: true, + }, + }, + init_declarators: [ + ( + InitDecl { + declarator: Declarator { + decl: WithParams { + ident: ( + "uwu", + 35..38, + ), + params: [], + }, + pointer: false, + }, + init: None, + }, + 35..38, + ), + ], }, - }, - 1..34, - ), - declarator: ( - "uwu", - 35..38, - ), - declaration_list: List( - [], - ), - body: [], - }, + ), + body: [], + }, + ), 1..43, ), ) 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 476dfa4..0037b8c 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 @@ -4,27 +4,41 @@ expression: parsed --- Ok( ( - FunctionDefinition { - decl_spec: ( - DeclSpec { - ty: Void, - attrs: DeclAttr { - is_extern: false, - is_static: false, - is_thread_local: false, + FunctionDef( + FunctionDef { + declaration: Normal( + NormalDecl { + decl_spec: DeclSpec { + ty: Void, + attrs: DeclAttr { + is_extern: false, + is_static: false, + is_thread_local: false, + }, + }, + init_declarators: [ + ( + InitDecl { + declarator: Declarator { + decl: WithParams { + ident: ( + "uwu", + 6..9, + ), + params: [], + }, + pointer: false, + }, + init: None, + }, + 6..9, + ), + ], }, - }, - 1..5, - ), - declarator: ( - "uwu", - 6..9, - ), - declaration_list: List( - [], - ), - body: [], - }, + ), + body: [], + }, + ), 1..14, ), )