some things! progress! and suffering!

This commit is contained in:
nora 2022-06-22 21:33:43 +02:00
parent 2ce2edfc64
commit 2fa0615ee5
11 changed files with 630 additions and 36 deletions

View file

@ -37,10 +37,39 @@ pub struct DeclSpec {
pub attrs: DeclAttr,
}
#[derive(Debug, DebugPls)]
pub enum Declaration {
Normal {
decl_spec: DeclSpec,
name: Option<String>,
initializer: Option<()>,
pointer: bool,
},
StaticAssert,
}
#[derive(Debug, DebugPls)]
pub struct Declarator {
pub identifier: String,
pub pointer: bool,
}
#[derive(Debug, DebugPls)]
pub struct FunctionParamDecl {
pub decl_spec: DeclSpec,
pub declarator: Declarator,
}
#[derive(Debug, DebugPls)]
pub enum FunctionParameters {
Void(Span),
List(Vec<Spanned<FunctionParamDecl>>),
}
#[derive(Debug, DebugPls)]
pub struct FunctionDefinition {
pub decl_spec: Spanned<DeclSpec>,
pub declarator: Spanned<String>,
pub declaration_list: Spanned<Vec<()>>,
pub declaration_list: FunctionParameters,
pub body: Vec<()>,
}
}

View file

@ -1,12 +1,14 @@
#![allow(dead_code)]
#![warn(rust_2018_idioms)]
use std::fmt::Debug;
mod ast;
mod parser;
mod pre;
mod token;
#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
#[derive(PartialEq, Eq, Clone, Copy, Default)]
pub struct Span {
pub start: usize,
pub end: usize,
@ -23,7 +25,15 @@ impl Span {
}
impl dbg_pls::DebugPls for Span {
fn fmt(&self, f: dbg_pls::Formatter<'_>) {}
fn fmt(&self, f: dbg_pls::Formatter<'_>) {
dbg_pls::DebugPls::fmt(&(self.start..self.end), f)
}
}
impl Debug for Span {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Debug::fmt(&(self.start..self.end), f)
}
}
pub fn parse_file(src: &str) {

View file

@ -1,12 +1,16 @@
use peekmore::PeekMoreIterator;
use crate::{
ast::{DeclAttr, DeclSpec, FunctionDefinition, Spanned, TypeSpecifier},
ast::{
DeclAttr, DeclSpec, Declaration, Declarator, FunctionDefinition, FunctionParamDecl,
FunctionParameters, Spanned, TypeSpecifier,
},
pre::Punctuator as Punct,
token::{Keyword as Kw, Token as Tok},
Span,
};
use crate::pre::Punctuator;
#[derive(Debug)]
struct ParserError {
span: Span,
message: String,
@ -42,18 +46,49 @@ macro_rules! expect {
(token, span) => {
return Err(ParserError::new(
span,
format!(concat!("expected `", stringify!($pat), "`, found {}"), token),
format!(
concat!("expected `", stringify!($pat), "`, found {}"),
token
),
))
}
}
};
}
/// Can be called for the start of a sequence of tokens that could be a type.
#[rustfmt::skip]
fn is_tok_start_of_ty(tok: &Tok<'_>) -> bool {
match tok {
Tok::Kw(
// storage specifiers
Kw::Typedef | Kw::Extern | Kw::Static | Kw::ThreadLocal | Kw::Auto | Kw::Register
// primitive types
| Kw::Void | Kw::Char | Kw::Short | Kw::Int | Kw::Long | Kw::Float | Kw::Double
| Kw::Signed | Kw::Unsigned | Kw::Bool | Kw::Complex
// struct-union-enum
| Kw::Struct | Kw::Union | Kw::Enum
// atomic
| Kw::Atomic
// type qualifiers
| Kw::Const | Kw::Restrict | Kw::Volatile /* atomic too */
// function specifiers
| Kw::Inline | Kw::Noreturn
) => true,
Tok::Identifier(_) => false, // TODO: lookup typedefs!
_ => false,
}
}
impl<'src, I> Parser<'src, I>
where
I: Iterator<Item = (Tok<'src>, Span)>,
{
fn find_typedef(&self, ident: &str) -> Option<()> {
// -----------------------
// Helpers
// -----------------------
fn find_typedef(&self, _: &str) -> Option<()> {
None // TODO: this
}
@ -65,6 +100,10 @@ where
self.lex.peek().ok_or_else(ParserError::eof)
}
fn peek_t_n(&mut self, n: usize) -> Result<&(Tok<'src>, Span)> {
self.lex.peek_nth(n).ok_or_else(ParserError::eof)
}
fn ident(&mut self) -> Result<Spanned<String>> {
match self.next_t()? {
(Tok::Identifier(ident), span) => Ok((ident.to_string(), span)),
@ -75,6 +114,13 @@ where
}
}
fn is_peek_tok_start_of_ty(&mut self) -> bool {
match self.peek_t() {
Ok((tok, _)) => is_tok_start_of_ty(tok),
Err(_) => false,
}
}
// -----------------------
// Declarations
// -----------------------
@ -82,8 +128,25 @@ where
/// (6.7) declaration:
/// declaration-specifiers init-declarator-listopt ;
/// static_assert-declaration
fn declaration(&mut self) -> Result<Spanned<()>> {
todo!()
fn declaration(&mut self) -> Result<Spanned<Declaration>> {
if let &(tok @ Tok::Kw(Kw::StaticAssert), span) = self.peek_t()? {
self.next_t()?;
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));
}
// then (optionally), an initializer
todo!("this doesn't work like this")
}
/// (6.7) declaration-specifiers:
@ -169,7 +232,7 @@ where
/// (6.7.6) declarator:
/// pointer.opt direct-declarator
fn declarator(&mut self) -> Result<Spanned<String>> {
fn declarator(&mut self) -> Result<Spanned<Declarator>> {
todo!()
}
@ -180,7 +243,7 @@ where
/// (6.9) external-declaration:
/// function-definition
/// declaration
fn external_declaration(&mut self) -> Result<()> {
fn external_declaration(&mut self) -> Result<Spanned<FunctionDefinition>> {
let (next, span) = self.peek_t()?;
if let Tok::Kw(Kw::StaticAssert) = next {
return Err(ParserError::unsupported(*span, next));
@ -190,13 +253,18 @@ where
// TODO: We just assume that it's a function, that's terrible!
self.function_definition(decl_spec)?;
todo!()
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<DeclSpec>,
@ -205,18 +273,67 @@ where
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,
declarator,
declaration_list: (Vec::new(), Span::default()),
declaration_list,
body: Vec::new(),
};
expect!(self, Tok::Punctuator(Punctuator::ParenOpen));
expect!(self, Tok::Punctuator(Punctuator::ParenClose));
expect!(self, Tok::Punctuator(Punctuator::BraceOpen));
let last = expect!(self, Tok::Punctuator(Punctuator::BraceClose));
let last = expect!(self, Tok::Punct(Punct::BraceClose));
Ok((def, decl_spec_span.extend(last)))
}
fn function_param_declaration_list(&mut self) -> Result<FunctionParameters> {
// 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()?;
return Ok(FunctionParameters::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(params))
}
}
#[cfg(test)]
mod tests;

View file

@ -0,0 +1,30 @@
---
source: parser/src/parser/tests.rs
expression: parsed
---
Ok(
(
FunctionDefinition {
decl_spec: (
DeclSpec {
ty: Int,
attrs: DeclAttr {
is_extern: true,
is_static: false,
is_thread_local: true,
},
},
1..34,
),
declarator: (
"uwu",
35..38,
),
declaration_list: List(
[],
),
body: [],
},
1..43,
),
)

View file

@ -0,0 +1,30 @@
---
source: parser/src/parser/tests.rs
expression: parsed
---
Ok(
(
FunctionDefinition {
decl_spec: (
DeclSpec {
ty: Void,
attrs: DeclAttr {
is_extern: false,
is_static: false,
is_thread_local: false,
},
},
1..5,
),
declarator: (
"uwu",
6..9,
),
declaration_list: List(
[],
),
body: [],
},
1..14,
),
)

View file

@ -0,0 +1,55 @@
use std::fmt::Debug;
use super::{Parser, Tok};
use crate::Span;
fn lex_and_pre<'src>(src: &'src str) -> impl Iterator<Item = (Tok<'src>, Span)> + 'src {
let pre_tokens = crate::pre::preprocess_tokens(src);
crate::token::pre_tokens_to_tokens(pre_tokens)
}
fn the_current_root_parse_thing<'src>(src: impl Iterator<Item = (Tok<'src>, Span)>) -> impl Debug {
use peekmore::PeekMore;
let mut parser = Parser {
lex: src.peekmore(),
};
parser.external_declaration()
}
macro_rules! parse_test {
($src:expr) => {
let lexer = lex_and_pre($src);
let parsed = the_current_root_parse_thing(lexer);
insta::assert_debug_snapshot!(parsed);
};
}
#[test]
fn empty_void_function() {
let src = r#"
void uwu() {}
"#;
parse_test!(src);
}
#[test]
fn empty_funky_attributes_no_params_function() {
let src = 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);
}

View file

@ -9,7 +9,7 @@ use peekmore::PeekMore;
use crate::Span;
#[derive(Debug)]
#[derive(Debug, Clone, Copy)]
pub enum PToken<'src> {
HeaderName(&'src str),
Identifier(&'src str),
@ -21,7 +21,7 @@ pub enum PToken<'src> {
Error,
}
#[derive(Debug)]
#[derive(Debug, Clone, Copy)]
pub enum Punctuator {
/// [ <:
BracketOpen,

View file

@ -4,7 +4,7 @@ expression: tokens
---
[
(
Keyword(
Kw(
Int,
),
1..4,
@ -16,19 +16,19 @@ expression: tokens
5..9,
),
(
Punctuator(
Punct(
ParenOpen,
),
9..10,
),
(
Punctuator(
Punct(
ParenClose,
),
10..11,
),
(
Punctuator(
Punct(
BraceOpen,
),
12..13,
@ -40,7 +40,7 @@ expression: tokens
18..22,
),
(
Punctuator(
Punct(
ParenOpen,
),
22..23,
@ -52,19 +52,19 @@ expression: tokens
23..37,
),
(
Punctuator(
Punct(
ParenClose,
),
38..39,
),
(
Punctuator(
Punct(
Semicolon,
),
39..40,
),
(
Punctuator(
Punct(
BraceClose,
),
41..42,

View file

@ -11,17 +11,17 @@ use crate::{
/// constant
/// string-literal
/// punctuator
#[derive(Debug)]
#[derive(Debug, Clone, Copy)]
pub enum Token<'src> {
Kw(Keyword),
Identifier(&'src str),
Constant(Constant),
StringLiteral(&'src str),
Punctuator(Punctuator),
Punct(Punctuator),
Error,
}
#[derive(Debug)]
#[derive(Debug, Clone, Copy)]
pub enum Keyword {
Auto,
Break,
@ -69,7 +69,7 @@ pub enum Keyword {
ThreadLocal,
}
#[derive(Debug)]
#[derive(Debug, Clone, Copy)]
pub enum Constant {
Int(i128),
Float(f64),
@ -147,7 +147,7 @@ pub fn pre_tokens_to_tokens<'src>(
.unwrap_or(Token::Error),
PToken::CharConstant(u8) => Token::Constant(Constant::Char(u8)),
PToken::StringLiteral(lit) => Token::StringLiteral(lit),
PToken::Punctuator(p) => Token::Punctuator(p),
PToken::Punctuator(p) => Token::Punct(p),
PToken::OtherNonWs(_) => Token::Error,
PToken::Error => Token::Error,
};
@ -162,7 +162,7 @@ impl Display for Token<'_> {
Token::Identifier(ident) => Display::fmt(ident, f),
Token::Constant(c) => Display::fmt(c, f),
Token::StringLiteral(str) => write!(f, "\"{}\"", str),
Token::Punctuator(p) => Display::fmt(p, f),
Token::Punct(p) => Display::fmt(p, f),
Token::Error => f.write_str("<invalid token>"),
}
}