diff --git a/parser/src/ast.rs b/parser/src/ast.rs index 37c8c14..f4f82ad 100644 --- a/parser/src/ast.rs +++ b/parser/src/ast.rs @@ -173,8 +173,8 @@ pub struct Declarator { #[derive(Debug, DebugPls)] pub struct FunctionDef { - pub declaration: Decl, - pub body: Vec, + pub decl: Decl, + pub body: Vec<()>, } #[derive(Debug, DebugPls)] @@ -182,3 +182,5 @@ pub enum ExternalDecl { Decl(Decl), FunctionDef(FunctionDef), } + +pub type TranslationUnit = Vec; diff --git a/parser/src/lib.rs b/parser/src/lib.rs index 2b8e236..463a1fd 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -9,6 +9,7 @@ use crate::token::Token; mod ast; mod parser; mod pre; +mod pretty; mod token; pub type Spanned = (T, Span); diff --git a/parser/src/parser.rs b/parser/src/parser.rs index 0163132..74bbf24 100644 --- a/parser/src/parser.rs +++ b/parser/src/parser.rs @@ -402,7 +402,7 @@ where Ok(( ExternalDecl::FunctionDef(FunctionDef { - declaration, + decl: declaration, body: Vec::new(), }), span.extend(span2), 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 index d588a33..9519634 100644 --- 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 @@ -1,66 +1,69 @@ --- source: parser/src/parser/tests.rs -expression: parsed_pretty +expression: "(parsed_pretty, pretty_printed_source)" --- -Ok([ - ( - FunctionDef(FunctionDef { - declaration: Normal(NormalDecl { - decl_spec: DeclSpec { - ty: Int, - attrs: "(empty)", - }, - init_declarators: [ - ( - InitDecl { - declarator: Declarator { - decl: WithParams { - ident: ("uwu", 5..8), - params: [ - FunctionParamDecl { - decl_spec: ( - DeclSpec { - ty: Long, - attrs: "(empty)", - }, - 9..13, - ), - declarator: ( - Declarator { - decl: Ident(("owo", 14..17)), - pointer: false, - }, - 14..17, - ), - }, - FunctionParamDecl { - decl_spec: ( - DeclSpec { - ty: Int, - attrs: "(empty)", - }, - 19..22, - ), - declarator: ( - Declarator { - decl: Ident(("qwq", 23..26)), - pointer: false, - }, - 23..26, - ), - }, - ], +( + Ok([ + ( + FunctionDef(FunctionDef { + decl: Normal(NormalDecl { + decl_spec: DeclSpec { + ty: Int, + attrs: "(empty)", + }, + init_declarators: [ + ( + InitDecl { + declarator: Declarator { + decl: WithParams { + ident: ("uwu", 5..8), + params: [ + FunctionParamDecl { + decl_spec: ( + DeclSpec { + ty: Long, + attrs: "(empty)", + }, + 9..13, + ), + declarator: ( + Declarator { + decl: Ident(("owo", 14..17)), + pointer: false, + }, + 14..17, + ), + }, + FunctionParamDecl { + decl_spec: ( + DeclSpec { + ty: Int, + attrs: "(empty)", + }, + 19..22, + ), + declarator: ( + Declarator { + decl: Ident(("qwq", 23..26)), + pointer: false, + }, + 23..26, + ), + }, + ], + }, + pointer: false, }, - pointer: false, + init: None, }, - init: None, - }, - 5..8, - ), - ], + 5..8, + ), + ], + }), + body: [], }), - body: [], - }), - 1..30, - ), -]) + 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 5de27a9..5817c2a 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 @@ -1,33 +1,36 @@ --- source: parser/src/parser/tests.rs -expression: parsed_pretty +expression: "(parsed_pretty, pretty_printed_source)" --- -Ok([ - ( - FunctionDef(FunctionDef { - declaration: Normal(NormalDecl { - decl_spec: DeclSpec { - ty: Int, - attrs: "EXTERN | THREAD_LOCAL", - }, - init_declarators: [ - ( - InitDecl { - declarator: Declarator { - decl: WithParams { - ident: ("uwu", 35..38), - params: [], +( + Ok([ + ( + FunctionDef(FunctionDef { + decl: Normal(NormalDecl { + decl_spec: DeclSpec { + ty: Int, + attrs: "EXTERN | THREAD_LOCAL", + }, + init_declarators: [ + ( + InitDecl { + declarator: Declarator { + decl: WithParams { + ident: ("uwu", 35..38), + params: [], + }, + pointer: false, }, - pointer: false, + init: None, }, - init: None, - }, - 35..38, - ), - ], + 35..38, + ), + ], + }), + body: [], }), - body: [], - }), - 1..43, - ), -]) + 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 aafb3a2..d0b3a6a 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 @@ -1,33 +1,36 @@ --- source: parser/src/parser/tests.rs -expression: parsed_pretty +expression: "(parsed_pretty, pretty_printed_source)" --- -Ok([ - ( - FunctionDef(FunctionDef { - declaration: Normal(NormalDecl { - decl_spec: DeclSpec { - ty: Void, - attrs: "(empty)", - }, - init_declarators: [ - ( - InitDecl { - declarator: Declarator { - decl: WithParams { - ident: ("uwu", 6..9), - params: [], +( + Ok([ + ( + FunctionDef(FunctionDef { + decl: Normal(NormalDecl { + decl_spec: DeclSpec { + ty: Void, + attrs: "(empty)", + }, + init_declarators: [ + ( + InitDecl { + declarator: Declarator { + decl: WithParams { + ident: ("uwu", 6..9), + params: [], + }, + pointer: false, }, - pointer: false, + init: None, }, - init: None, - }, - 6..9, - ), - ], + 6..9, + ), + ], + }), + body: [], }), - body: [], - }), - 1..14, - ), -]) + 1..14, + ), + ]), + "", +) 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 0bddb39..b338cb1 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 @@ -1,88 +1,91 @@ --- source: parser/src/parser/tests.rs -expression: parsed_pretty +expression: "(parsed_pretty, pretty_printed_source)" --- -Ok([ - ( - Decl( - Normal(NormalDecl { - decl_spec: DeclSpec { - ty: Int, - attrs: "(empty)", - }, - init_declarators: [ - ( - InitDecl { - declarator: Declarator { - decl: Ident(("test", 5..9)), - pointer: false, - }, - init: None, - }, - 5..9, - ), - ], - }), - ), - 1..9, - ), - ( - Decl( - Normal(NormalDecl { - decl_spec: DeclSpec { - ty: Double, - attrs: "THREAD_LOCAL", - }, - init_declarators: [ - ( - InitDecl { - declarator: Declarator { - decl: Ident(("uwu", 32..35)), - pointer: false, - }, - init: None, - }, - 32..35, - ), - ( - InitDecl { - declarator: Declarator { - decl: Ident(("owo", 37..40)), - pointer: false, - }, - init: None, - }, - 37..40, - ), - ], - }), - ), - 11..40, - ), - ( - Decl( - Normal(NormalDecl { - decl_spec: DeclSpec { - ty: Int, - attrs: "(empty)", - }, - init_declarators: [ - ( - InitDecl { - declarator: Declarator { - decl: WithParams { - ident: ("function", 68..76), - params: [], +( + Ok([ + ( + Decl( + Normal(NormalDecl { + decl_spec: DeclSpec { + ty: Int, + attrs: "(empty)", + }, + init_declarators: [ + ( + InitDecl { + declarator: Declarator { + decl: Ident(("test", 5..9)), + pointer: false, }, - pointer: false, + init: None, }, - init: None, - }, - 68..76, - ), - ], - }), + 5..9, + ), + ], + }), + ), + 1..9, ), - 64..76, - ), -]) + ( + Decl( + Normal(NormalDecl { + decl_spec: DeclSpec { + ty: Double, + attrs: "THREAD_LOCAL", + }, + init_declarators: [ + ( + InitDecl { + declarator: Declarator { + decl: Ident(("uwu", 32..35)), + pointer: false, + }, + init: None, + }, + 32..35, + ), + ( + InitDecl { + declarator: Declarator { + decl: Ident(("owo", 37..40)), + pointer: false, + }, + init: None, + }, + 37..40, + ), + ], + }), + ), + 11..40, + ), + ( + Decl( + Normal(NormalDecl { + decl_spec: DeclSpec { + ty: Int, + attrs: "(empty)", + }, + 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/snapshots/parser__parser__tests__small_expressions.snap b/parser/src/parser/snapshots/parser__parser__tests__small_expressions.snap index b24bb21..bd6d2fa 100644 --- a/parser/src/parser/snapshots/parser__parser__tests__small_expressions.snap +++ b/parser/src/parser/snapshots/parser__parser__tests__small_expressions.snap @@ -1,103 +1,106 @@ --- source: parser/src/parser/tests.rs -expression: parsed_pretty +expression: "(parsed_pretty, pretty_printed_source)" --- -Ok([ - ( - Decl( - Normal(NormalDecl { - decl_spec: DeclSpec { - ty: Int, - attrs: "(empty)", - }, - init_declarators: [ - ( - InitDecl { - declarator: Declarator { - decl: Ident(("x", 5..6)), - pointer: false, +( + Ok([ + ( + Decl( + Normal(NormalDecl { + decl_spec: DeclSpec { + ty: Int, + attrs: "(empty)", + }, + init_declarators: [ + ( + InitDecl { + declarator: Declarator { + decl: Ident(("x", 5..6)), + pointer: false, + }, + init: Some(( + Binary(ExprBinary { + lhs: (Atom(Int(1)), 9..10), + rhs: (Atom(Int(1)), 13..14), + op: Arith(Add), + }), + 9..14, + )), }, - init: Some(( - Binary(ExprBinary { - lhs: (Atom(Int(1)), 9..10), - rhs: (Atom(Int(1)), 13..14), - op: Add, - }), - 9..14, - )), - }, - 5..6, - ), - ], - }), + 5..6, + ), + ], + }), + ), + 1..6, ), - 1..6, - ), - ( - Decl( - Normal(NormalDecl { - decl_spec: DeclSpec { - ty: Int, - attrs: "(empty)", - }, - init_declarators: [ - ( - InitDecl { - declarator: Declarator { - decl: Ident(("y", 21..22)), - pointer: false, + ( + Decl( + Normal(NormalDecl { + decl_spec: DeclSpec { + ty: Int, + attrs: "(empty)", + }, + init_declarators: [ + ( + InitDecl { + declarator: Declarator { + decl: Ident(("y", 21..22)), + pointer: false, + }, + init: Some(( + Binary(ExprBinary { + lhs: (Atom(Int(1)), 26..27), + rhs: ( + Binary(ExprBinary { + lhs: (Atom(Int(2)), 31..32), + rhs: (Atom(Int(3)), 35..36), + op: Arith(Sub), + }), + 31..36, + ), + op: Arith(Add), + }), + 26..36, + )), }, - init: Some(( - Binary(ExprBinary { - lhs: (Atom(Int(1)), 26..27), - rhs: ( - Binary(ExprBinary { - lhs: (Atom(Int(2)), 31..32), - rhs: (Atom(Int(3)), 35..36), - op: Sub, - }), - 31..36, - ), - op: Add, - }), - 26..36, - )), - }, - 21..22, - ), - ], - }), + 21..22, + ), + ], + }), + ), + 17..22, ), - 17..22, - ), - ( - Decl( - Normal(NormalDecl { - decl_spec: DeclSpec { - ty: Int, - attrs: "(empty)", - }, - init_declarators: [ - ( - InitDecl { - declarator: Declarator { - decl: Ident(("z", 45..46)), - pointer: false, + ( + Decl( + Normal(NormalDecl { + decl_spec: DeclSpec { + ty: Int, + attrs: "(empty)", + }, + init_declarators: [ + ( + InitDecl { + declarator: Declarator { + decl: Ident(("z", 45..46)), + pointer: false, + }, + init: Some(( + Binary(ExprBinary { + lhs: (Atom(Ident("array")), 50..55), + rhs: (Atom(Int(9)), 56..57), + op: Index, + }), + 50..58, + )), }, - init: Some(( - Binary(ExprBinary { - lhs: (Atom(Ident("array")), 50..55), - rhs: (Atom(Int(9)), 56..57), - op: Index, - }), - 50..58, - )), - }, - 45..46, - ), - ], - }), + 45..46, + ), + ], + }), + ), + 41..46, ), - 41..46, - ), -]) + ]), + "", +) diff --git a/parser/src/parser/tests.rs b/parser/src/parser/tests.rs index 17f8e27..3c7896a 100644 --- a/parser/src/parser/tests.rs +++ b/parser/src/parser/tests.rs @@ -1,15 +1,15 @@ -use std::fmt::Debug; - use super::Tok; -use crate::Span; +use crate::{ast::ExternalDecl, parser::ParserError, Span, Spanned}; 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) } -fn the_current_root_parse_thing<'src>(src: impl Iterator, Span)>) -> impl Debug { - super::parse_declarations(src) +fn pretty_print(ast: &Result>, ParserError>) -> String { + let mut vec = Vec::new(); + + String::from_utf8_lossy(&vec).into_owned() } macro_rules! parse_test { @@ -17,8 +17,9 @@ macro_rules! parse_test { let lexer = lex_and_pre($src); let parsed = super::parse_declarations(lexer); let parsed_pretty = dbg_pls::pretty(&parsed); + let pretty_printed_source = pretty_print(&parsed); - insta::assert_debug_snapshot!(parsed_pretty); + insta::assert_debug_snapshot!((parsed_pretty, pretty_printed_source)); }; } diff --git a/parser/src/pretty.rs b/parser/src/pretty.rs new file mode 100644 index 0000000..c6b7ff0 --- /dev/null +++ b/parser/src/pretty.rs @@ -0,0 +1,286 @@ +use std::io::Write; + +type Result = std::io::Result<()>; + +use crate::{ + ast::{ + ArithOpKind, Atom, BinaryOp, ComparisonKind, Decl, DeclAttr, DeclSpec, Declarator, + DirectDeclarator, Expr, ExprBinary, ExprUnary, ExternalDecl, FunctionDef, + FunctionParamDecl, InitDecl, NormalDecl, TypeSpecifier, UnaryOp, + }, + Spanned, +}; + +pub struct PrettyPrinter { + indent: usize, + output: W, + force_parens: bool, +} + +const INDENT: &str = " "; + +impl PrettyPrinter { + pub fn new(output: W, force_parens: bool) -> Self { + Self { + indent: 0, + output, + force_parens, + } + } + + fn string(&mut self, str: &str) -> Result { + write!(self.output, "{}", str) + } + + fn print_indent(&mut self) -> Result { + self.string(&INDENT.repeat(self.indent)) + } + + fn linebreak(&mut self) -> Result { + self.string("\n")?; + self.print_indent()?; + Ok(()) + } + + fn indent(&mut self) { + self.indent += 1; + } + + fn dedent(&mut self) { + self.indent -= 1; + } + + pub fn translation_unit(&mut self, unit: &[Spanned]) -> Result { + for decl in unit { + self.external_decl(&decl.0)?; + } + Ok(()) + } + + fn external_decl(&mut self, decl: &ExternalDecl) -> Result { + match decl { + ExternalDecl::FunctionDef(def) => self.function_def(def), + ExternalDecl::Decl(decl) => self.decl(decl), + } + } + + fn function_def(&mut self, def: &FunctionDef) -> Result { + self.decl(&def.decl)?; + self.string(" {")?; + self.indent(); + self.linebreak()?; + // TODO: body + self.dedent(); + self.linebreak()?; + + Ok(()) + } + + fn decl(&mut self, decl: &Decl) -> Result { + match decl { + Decl::StaticAssert => todo!(), + Decl::Normal(normal_decl) => self.normal_decl(normal_decl), + } + } + + fn normal_decl(&mut self, decl: &NormalDecl) -> Result { + self.decl_spec(&decl.decl_spec)?; + self.string(" ")?; + let mut first = true; + for declarator in &decl.init_declarators { + if !first { + self.string(", ")?; + } + first = false; + self.init_declarator(&declarator.0)?; + } + + Ok(()) + } + + fn decl_spec(&mut self, decl_spec: &DeclSpec) -> Result { + self.type_specifier(&decl_spec.ty)?; + self.string(" ")?; + self.decl_attr(&decl_spec.attrs)?; + Ok(()) + } + + fn init_declarator(&mut self, init_declarator: &InitDecl) -> Result { + self.declarator(&init_declarator.declarator)?; + if let Some(init) = &init_declarator.init { + self.string(" = ")?; + self.expr(&init.0)?; + } + Ok(()) + } + + fn type_specifier(&mut self, spec: &TypeSpecifier) -> Result { + self.string(match spec { + TypeSpecifier::Void => "void", + TypeSpecifier::Char => "char", + TypeSpecifier::Short => "short", + TypeSpecifier::Int => "int", + TypeSpecifier::Long => "long", + TypeSpecifier::Float => "float", + TypeSpecifier::Double => "double", + TypeSpecifier::Signed => "signed", + TypeSpecifier::Unsigned => "unsigned", + TypeSpecifier::Bool => "_Bool", + TypeSpecifier::Complex => "_Complex", + }) + } + + fn decl_attr(&mut self, attr: &DeclAttr) -> Result { + let mut attrs = Vec::new(); + if attr.contains(DeclAttr::EXTERN) { + attrs.push("extern"); + } + if attr.contains(DeclAttr::STATIC) { + attrs.push("static"); + } + if attr.contains(DeclAttr::THREAD_LOCAL) { + attrs.push("_Thread_local"); + } + self.string(&attrs.join(" "))?; + self.string(" ")?; + + Ok(()) + } + + fn declarator(&mut self, declarator: &Declarator) -> Result { + if declarator.pointer { + self.string("*")?; + } + self.direct_declarator(&declarator.decl)?; + Ok(()) + } + + fn direct_declarator(&mut self, declarator: &DirectDeclarator) -> Result { + match declarator { + DirectDeclarator::Ident(ident) => self.string(&ident.0), + DirectDeclarator::WithParams { ident, params } => { + self.string(&ident.0)?; + self.string("(")?; + self.function_param_decls(params)?; + self.string(")")?; + Ok(()) + } + } + } + + fn function_param_decls(&mut self, decls: &[FunctionParamDecl]) -> Result { + let mut first = true; + for decl in decls { + if !first { + self.string(", ")?; + } + first = false; + self.decl_spec(&decl.decl_spec.0)?; + self.declarator(&decl.declarator.0)?; + } + Ok(()) + } + + fn expr(&mut self, expr: &Expr) -> Result { + match expr { + Expr::Atom(atom) => match atom { + Atom::Ident(ident) => self.string(ident), + Atom::Int(int) => write!(self.output, "{}", int), + Atom::Float(float) => write!(self.output, "{}", float), + Atom::String(string) => { + self.string("\"")?; + // bare attempt at escpaing + self.string(&string.replace('\"', "\\\""))?; + self.string("\"")?; + Ok(()) + } + Atom::Char(char) => { + self.string("'")?; + let ascii = *char as char; + write!(self.output, "{}", ascii)?; + self.string("'")?; + Ok(()) + } + }, + Expr::Unary(unary) => self.unary(unary), + Expr::Binary(ExprBinary { + op: BinaryOp::Index, + lhs, + rhs, + }) => { + self.expr(&lhs.as_ref().0)?; + self.string("[")?; + self.expr(&rhs.as_ref().0)?; + self.string("]")?; + Ok(()) + } + Expr::Binary(binary) => self.binary(binary), + } + } + + fn unary(&mut self, unary: &ExprUnary) -> Result { + self.string(match unary.op { + UnaryOp::AddrOf => "&", + UnaryOp::Deref => "*", + UnaryOp::Plus => "+", + UnaryOp::Minus => "-", + UnaryOp::Tilde => "~", + UnaryOp::Bang => "!", + })?; + if self.force_parens { + self.string("(")?; + } + self.expr(&unary.rhs.as_ref().0)?; + if self.force_parens { + self.string(")")?; + } + Ok(()) + } + + fn binary(&mut self, binary: &ExprBinary) -> Result { + if self.force_parens { + self.string("(")?; + } + self.expr(&binary.lhs.as_ref().0)?; + self.string(" ")?; + self.string(match binary.op { + BinaryOp::Arith(ArithOpKind::Mul) => "*", + BinaryOp::Arith(ArithOpKind::Div) => "/", + BinaryOp::Arith(ArithOpKind::Mod) => "%", + BinaryOp::Arith(ArithOpKind::Add) => "+", + BinaryOp::Arith(ArithOpKind::Sub) => "-", + BinaryOp::Arith(ArithOpKind::Shl) => "<<", + BinaryOp::Arith(ArithOpKind::Shr) => ">>", + BinaryOp::Arith(ArithOpKind::BitAnd) => "&", + BinaryOp::Arith(ArithOpKind::BitXor) => "^", + BinaryOp::Arith(ArithOpKind::BitOr) => "|", + BinaryOp::LogicalAnd => "&&", + BinaryOp::LogicalOr => "||", + BinaryOp::Comparison(ComparisonKind::Lt) => "<", + BinaryOp::Comparison(ComparisonKind::Gt) => ">", + BinaryOp::Comparison(ComparisonKind::LtEq) => "<=", + BinaryOp::Comparison(ComparisonKind::GtEq) => ">=", + BinaryOp::Comparison(ComparisonKind::Eq) => "==", + BinaryOp::Comparison(ComparisonKind::Neq) => "!=", + BinaryOp::Comma => ",", + BinaryOp::Index => unreachable!("special case outside"), + BinaryOp::Assign(None) => "=", + BinaryOp::Assign(Some(ArithOpKind::Mul)) => "*=", + BinaryOp::Assign(Some(ArithOpKind::Div)) => "/=", + BinaryOp::Assign(Some(ArithOpKind::Mod)) => "%=", + BinaryOp::Assign(Some(ArithOpKind::Add)) => "+=", + BinaryOp::Assign(Some(ArithOpKind::Sub)) => "-=", + BinaryOp::Assign(Some(ArithOpKind::Shl)) => "<<=", + BinaryOp::Assign(Some(ArithOpKind::Shr)) => ">>=", + BinaryOp::Assign(Some(ArithOpKind::BitAnd)) => "&=", + BinaryOp::Assign(Some(ArithOpKind::BitXor)) => "^=", + BinaryOp::Assign(Some(ArithOpKind::BitOr)) => "|=", + })?; + self.string(" ")?; + self.expr(&binary.rhs.as_ref().0)?; + if self.force_parens { + self.string(")")?; + } + Ok(()) + } +}