mirror of
https://github.com/Noratrieb/ub.git
synced 2026-01-14 16:45:05 +01:00
pwetty pwinting
This commit is contained in:
parent
134d23299a
commit
2f051ed45b
3 changed files with 287 additions and 7 deletions
|
|
@ -122,7 +122,6 @@ pub enum ExprKind {
|
||||||
UnaryOp(UnaryOp),
|
UnaryOp(UnaryOp),
|
||||||
FieldAccess(FieldAccess),
|
FieldAccess(FieldAccess),
|
||||||
Call(Call),
|
Call(Call),
|
||||||
Deref(Box<Expr>),
|
|
||||||
Literal(Literal),
|
Literal(Literal),
|
||||||
Name(String),
|
Name(String),
|
||||||
Array(Vec<Expr>),
|
Array(Vec<Expr>),
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ use crate::lexer::Token;
|
||||||
mod ast;
|
mod ast;
|
||||||
mod lexer;
|
mod lexer;
|
||||||
mod parser;
|
mod parser;
|
||||||
|
mod pretty;
|
||||||
|
|
||||||
pub fn parse(_str: &str, _file_name: PathBuf) -> Result<ast::File, ()> {
|
pub fn parse(_str: &str, _file_name: PathBuf) -> Result<ast::File, ()> {
|
||||||
todo!()
|
todo!()
|
||||||
|
|
@ -18,11 +19,15 @@ pub fn parse(_str: &str, _file_name: PathBuf) -> Result<ast::File, ()> {
|
||||||
|
|
||||||
pub fn test() {
|
pub fn test() {
|
||||||
let src = "
|
let src = "
|
||||||
fn main() {
|
fn main(uwu: u64, owo: ptr WOW) -> ptr u64 {
|
||||||
//-(*5);
|
let uwu = &1;
|
||||||
//&5;
|
let owo = yeet(1+2*3, AA);
|
||||||
//2 + &8;
|
|
||||||
*6 * *8; // :)
|
if 1 {
|
||||||
|
10;
|
||||||
|
} else {}
|
||||||
|
|
||||||
|
if 1 { if 1 { if 1 {} } }
|
||||||
}
|
}
|
||||||
";
|
";
|
||||||
|
|
||||||
|
|
@ -33,7 +38,7 @@ fn main() {
|
||||||
let (file, errors) = parser::parse(lexer.spanned(), &state, len, "test_file".into());
|
let (file, errors) = parser::parse(lexer.spanned(), &state, len, "test_file".into());
|
||||||
|
|
||||||
if let Some(file) = file {
|
if let Some(file) = file {
|
||||||
println!("AST: {file:#?}");
|
println!("{}", pretty::pretty_print_ast(&file));
|
||||||
}
|
}
|
||||||
|
|
||||||
errors
|
errors
|
||||||
|
|
|
||||||
276
parser/src/pretty.rs
Normal file
276
parser/src/pretty.rs
Normal file
|
|
@ -0,0 +1,276 @@
|
||||||
|
use std::fmt::Write;
|
||||||
|
|
||||||
|
use crate::ast::{
|
||||||
|
BinOpKind, ElsePart, Expr, ExprKind, File, IfStmt, Item, Literal, NameTyPair, Stmt, Ty, TyKind,
|
||||||
|
UnaryOpKind,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn pretty_print_ast(ast: &File) -> String {
|
||||||
|
let mut printer = Printer {
|
||||||
|
out: String::new(),
|
||||||
|
indent: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
printer.print_items(&ast.items);
|
||||||
|
|
||||||
|
printer.out
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Printer {
|
||||||
|
out: String,
|
||||||
|
indent: usize,
|
||||||
|
}
|
||||||
|
impl Printer {
|
||||||
|
fn print_items(&mut self, items: &[Item]) {
|
||||||
|
for item in items {
|
||||||
|
self.print_item(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_item(&mut self, item: &Item) {
|
||||||
|
match item {
|
||||||
|
Item::FnDecl(fn_decl) => {
|
||||||
|
self.word("fn ");
|
||||||
|
self.word(&fn_decl.name);
|
||||||
|
self.word("(");
|
||||||
|
let params = &fn_decl.params;
|
||||||
|
if params.len() > 0 {
|
||||||
|
self.linebreak_indent();
|
||||||
|
for i in 0..params.len().saturating_sub(1) {
|
||||||
|
let param = &fn_decl.params[i];
|
||||||
|
self.print_name_ty(param);
|
||||||
|
self.word(",");
|
||||||
|
self.linebreak();
|
||||||
|
}
|
||||||
|
if params.len() > 0 {
|
||||||
|
self.print_name_ty(params.last().unwrap());
|
||||||
|
}
|
||||||
|
self.linebreak_unindent();
|
||||||
|
}
|
||||||
|
|
||||||
|
self.word(") ");
|
||||||
|
if let Some(ret_ty) = &fn_decl.ret_ty {
|
||||||
|
self.word("-> ");
|
||||||
|
self.print_ty(ret_ty);
|
||||||
|
self.word(" ");
|
||||||
|
}
|
||||||
|
self.print_block(&fn_decl.body);
|
||||||
|
}
|
||||||
|
Item::StructDecl(_) => {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_name_ty(&mut self, name_ty: &NameTyPair) {
|
||||||
|
self.word(&name_ty.name);
|
||||||
|
self.word(": ");
|
||||||
|
self.print_ty(&name_ty.ty);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_ty(&mut self, ty: &Ty) {
|
||||||
|
match &ty.kind {
|
||||||
|
TyKind::U64 => self.word("u64"),
|
||||||
|
TyKind::Name(name) => self.word(name),
|
||||||
|
TyKind::Ptr(ty) => {
|
||||||
|
self.word("ptr ");
|
||||||
|
self.print_ty(ty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Starts off after the `{`. Indents itself first if necessary. Stops at the place where `}` should be inserted.
|
||||||
|
fn print_block(&mut self, stmts: &[Stmt]) {
|
||||||
|
self.word("{");
|
||||||
|
if let [first, rest @ ..] = &stmts {
|
||||||
|
self.linebreak_indent();
|
||||||
|
self.print_stmt(first);
|
||||||
|
|
||||||
|
for stmt in rest {
|
||||||
|
self.linebreak();
|
||||||
|
self.print_stmt(stmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.linebreak_unindent();
|
||||||
|
}
|
||||||
|
self.word("}");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Leaves the cursor after the semicolon
|
||||||
|
fn print_stmt(&mut self, stmt: &Stmt) {
|
||||||
|
match stmt {
|
||||||
|
Stmt::VarDecl(decl) => {
|
||||||
|
self.word("let ");
|
||||||
|
self.word(&decl.name);
|
||||||
|
if let Some(ty) = &decl.ty {
|
||||||
|
self.word(": ");
|
||||||
|
self.print_ty(ty);
|
||||||
|
}
|
||||||
|
if let Some(rhs) = &decl.rhs {
|
||||||
|
self.word(" = ");
|
||||||
|
self.print_expr(rhs);
|
||||||
|
}
|
||||||
|
self.word(";");
|
||||||
|
}
|
||||||
|
Stmt::Assignment(assign) => {
|
||||||
|
self.print_expr(&assign.place);
|
||||||
|
self.word(" = ");
|
||||||
|
self.print_expr(&assign.rhs);
|
||||||
|
self.word(";");
|
||||||
|
}
|
||||||
|
Stmt::IfStmt(if_stmt) => {
|
||||||
|
self.print_if(if_stmt);
|
||||||
|
}
|
||||||
|
Stmt::WhileStmt(while_stmt) => {
|
||||||
|
self.word("while ");
|
||||||
|
self.print_expr(&while_stmt.cond);
|
||||||
|
self.print_block(&while_stmt.body);
|
||||||
|
}
|
||||||
|
Stmt::LoopStmt(loop_stmt) => {
|
||||||
|
self.word("loop ");
|
||||||
|
self.print_block(&loop_stmt.body);
|
||||||
|
}
|
||||||
|
Stmt::Item(item) => {
|
||||||
|
self.print_item(item);
|
||||||
|
}
|
||||||
|
Stmt::Expr(expr) => {
|
||||||
|
self.print_expr(expr);
|
||||||
|
self.word(";");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_if(&mut self, if_stmt: &IfStmt) {
|
||||||
|
self.word("if ");
|
||||||
|
self.print_expr(&if_stmt.cond);
|
||||||
|
self.word(" ");
|
||||||
|
self.print_block(&if_stmt.body);
|
||||||
|
if let Some(else_part) = &if_stmt.else_part {
|
||||||
|
self.word(" else ");
|
||||||
|
match else_part {
|
||||||
|
ElsePart::Else(stmts, _) => {
|
||||||
|
self.print_block(stmts);
|
||||||
|
}
|
||||||
|
ElsePart::ElseIf(if_stmt) => {
|
||||||
|
self.print_if(if_stmt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_expr(&mut self, expr: &Expr) {
|
||||||
|
match &expr.kind {
|
||||||
|
ExprKind::BinOp(bin_op) => {
|
||||||
|
self.print_expr_wrapped(&bin_op.lhs);
|
||||||
|
self.word(match bin_op.kind {
|
||||||
|
BinOpKind::Eq => " == ",
|
||||||
|
BinOpKind::Neq => " != ",
|
||||||
|
BinOpKind::Gt => " > ",
|
||||||
|
BinOpKind::Lt => " < ",
|
||||||
|
BinOpKind::GtEq => " >= ",
|
||||||
|
BinOpKind::LtEq => " <= ",
|
||||||
|
BinOpKind::Add => " + ",
|
||||||
|
BinOpKind::Sub => " - ",
|
||||||
|
BinOpKind::Mul => " * ",
|
||||||
|
BinOpKind::Div => " / ",
|
||||||
|
BinOpKind::Mod => " % ",
|
||||||
|
BinOpKind::Shr => " >> ",
|
||||||
|
BinOpKind::Shl => " << ",
|
||||||
|
BinOpKind::And => " && ",
|
||||||
|
BinOpKind::Or => " || ",
|
||||||
|
BinOpKind::BitAnd => " & ",
|
||||||
|
BinOpKind::BitOr => " | ",
|
||||||
|
BinOpKind::Xor => " ^ ",
|
||||||
|
});
|
||||||
|
self.print_expr_wrapped(&bin_op.rhs);
|
||||||
|
}
|
||||||
|
ExprKind::UnaryOp(unary_op) => {
|
||||||
|
self.word(match unary_op.kind {
|
||||||
|
UnaryOpKind::Not => "!",
|
||||||
|
UnaryOpKind::Neg => "-",
|
||||||
|
UnaryOpKind::Deref => "*",
|
||||||
|
UnaryOpKind::AddrOf => "&",
|
||||||
|
});
|
||||||
|
self.print_expr_wrapped(&unary_op.expr);
|
||||||
|
}
|
||||||
|
ExprKind::FieldAccess(field_access) => {
|
||||||
|
self.print_expr(&field_access.expr);
|
||||||
|
self.word(".");
|
||||||
|
self.word(&field_access.field_name);
|
||||||
|
}
|
||||||
|
ExprKind::Call(call) => {
|
||||||
|
self.print_expr(&call.callee);
|
||||||
|
self.word("(");
|
||||||
|
if let [first, rest @ ..] = &*call.args {
|
||||||
|
self.print_expr(first);
|
||||||
|
for expr in rest {
|
||||||
|
self.word(", ");
|
||||||
|
self.print_expr(expr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.word(")");
|
||||||
|
}
|
||||||
|
ExprKind::Literal(literal) => match literal {
|
||||||
|
Literal::Integer(int, _) => write!(self.out, "{int}").unwrap(),
|
||||||
|
Literal::String(string, _) => {
|
||||||
|
self.word("\"");
|
||||||
|
// FIXME: Handle escapes.
|
||||||
|
self.word(string);
|
||||||
|
self.word("\"");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ExprKind::Name(name) => {
|
||||||
|
self.word(name);
|
||||||
|
}
|
||||||
|
ExprKind::Array(exprs) => {
|
||||||
|
self.word("[");
|
||||||
|
if let [first, rest @ ..] = exprs.as_slice() {
|
||||||
|
self.print_expr(first);
|
||||||
|
for expr in rest {
|
||||||
|
self.word(", ");
|
||||||
|
self.print_expr(expr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.word("]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_expr_wrapped(&mut self, expr: &Expr) {
|
||||||
|
match expr.kind {
|
||||||
|
ExprKind::Literal(_)
|
||||||
|
| ExprKind::Array(_)
|
||||||
|
| ExprKind::Call(_)
|
||||||
|
| ExprKind::Name(_)
|
||||||
|
| ExprKind::FieldAccess(_) => {
|
||||||
|
self.print_expr(expr);
|
||||||
|
}
|
||||||
|
ExprKind::BinOp(_) | ExprKind::UnaryOp(_) => {
|
||||||
|
self.word("(");
|
||||||
|
self.print_expr(expr);
|
||||||
|
self.word(")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// utility functions
|
||||||
|
|
||||||
|
fn word(&mut self, word: &str) {
|
||||||
|
self.out.push_str(word);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn linebreak_indent(&mut self) {
|
||||||
|
self.indent += 1;
|
||||||
|
self.linebreak();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn linebreak_unindent(&mut self) {
|
||||||
|
self.indent -= 1;
|
||||||
|
self.linebreak();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn linebreak(&mut self) {
|
||||||
|
self.word("\n");
|
||||||
|
self.word(&" ".repeat(self.indent))
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue