mirror of
https://github.com/Noratrieb/uwucc.git
synced 2026-01-14 16:45:07 +01:00
some things! progress! and suffering!
This commit is contained in:
parent
2ce2edfc64
commit
2fa0615ee5
11 changed files with 630 additions and 36 deletions
|
|
@ -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<()>,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
),
|
||||
)
|
||||
|
|
@ -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,
|
||||
),
|
||||
)
|
||||
55
parser/src/parser/tests.rs
Normal file
55
parser/src/parser/tests.rs
Normal 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);
|
||||
}
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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>"),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue