examples: Adapt examples/yaml to a broken C generator! woo!
This commit is contained in:
		
							
								
								
									
										932
									
								
								compiler/cl-repl/examples/to_c.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										932
									
								
								compiler/cl-repl/examples/to_c.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,932 @@ | ||||
| //! Pretty prints a conlang AST in yaml | ||||
|  | ||||
| use cl_ast::{File, Stmt}; | ||||
| use cl_lexer::Lexer; | ||||
| use cl_parser::Parser; | ||||
| use repline::{Repline, error::Error as RlError}; | ||||
| use std::error::Error; | ||||
|  | ||||
| fn main() -> Result<(), Box<dyn Error>> { | ||||
|     if let Some(path) = std::env::args().nth(1) { | ||||
|         let f = std::fs::read_to_string(&path).expect("Path must be valid."); | ||||
|         let mut parser = Parser::new(path, Lexer::new(&f)); | ||||
|         let code: File = match parser.parse() { | ||||
|             Ok(f) => f, | ||||
|             Err(e) => { | ||||
|                 eprintln!("{e}"); | ||||
|                 return Ok(()); | ||||
|             } | ||||
|         }; | ||||
|         CLangifier::new().p(&code); | ||||
|         println!(); | ||||
|         return Ok(()); | ||||
|     } | ||||
|     let mut rl = Repline::new("\x1b[33m", "cl>", "? >"); | ||||
|     loop { | ||||
|         let mut line = match rl.read() { | ||||
|             Err(RlError::CtrlC(_)) => break, | ||||
|             Err(RlError::CtrlD(line)) => { | ||||
|                 rl.deny(); | ||||
|                 line | ||||
|             } | ||||
|             Ok(line) => line, | ||||
|             Err(e) => Err(e)?, | ||||
|         }; | ||||
|         if !line.ends_with(';') { | ||||
|             line.push(';'); | ||||
|         } | ||||
|  | ||||
|         let mut parser = Parser::new("stdin", Lexer::new(&line)); | ||||
|         let code = match parser.parse::<Stmt>() { | ||||
|             Ok(code) => { | ||||
|                 rl.accept(); | ||||
|                 code | ||||
|             } | ||||
|             Err(e) => { | ||||
|                 print!("\x1b[40G\x1bJ\x1b[91m{e}\x1b[0m"); | ||||
|                 continue; | ||||
|             } | ||||
|         }; | ||||
|         print!("\x1b[G\x1b[J"); | ||||
|         CLangifier::new().p(&code); | ||||
|         println!(); | ||||
|     } | ||||
|     Ok(()) | ||||
| } | ||||
|  | ||||
| pub use yamler::CLangifier; | ||||
| pub mod yamler { | ||||
|     use crate::yamlify::CLangify; | ||||
|     use std::{ | ||||
|         fmt::Display, | ||||
|         io::Write, | ||||
|         ops::{Deref, DerefMut}, | ||||
|     }; | ||||
|     #[derive(Debug, Default)] | ||||
|     pub struct CLangifier { | ||||
|         depth: usize, | ||||
|     } | ||||
|  | ||||
|     impl CLangifier { | ||||
|         pub fn new() -> Self { | ||||
|             Self::default() | ||||
|         } | ||||
|  | ||||
|         pub fn indent(&mut self) -> Section { | ||||
|             Section::new(self) | ||||
|         } | ||||
|  | ||||
|         /// Prints a [Yamlify] value | ||||
|         #[inline] | ||||
|         pub fn p<T: CLangify + ?Sized>(&mut self, yaml: &T) -> &mut Self { | ||||
|             yaml.print(self); | ||||
|             self | ||||
|         } | ||||
|  | ||||
|         fn increase(&mut self) { | ||||
|             self.depth += 1; | ||||
|         } | ||||
|  | ||||
|         fn decrease(&mut self) { | ||||
|             self.depth -= 1; | ||||
|         } | ||||
|  | ||||
|         fn print_indentation(&self, writer: &mut impl Write) { | ||||
|             for _ in 0..self.depth { | ||||
|                 let _ = write!(writer, "    "); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         pub fn endl(&mut self) -> &mut Self { | ||||
|             self.p("\n") | ||||
|                 .print_indentation(&mut std::io::stdout().lock()); | ||||
|             self | ||||
|         } | ||||
|  | ||||
|         /// Prints a section header and increases indentation | ||||
|         pub fn key(&mut self, name: impl Display) -> Section { | ||||
|             print!("{name}"); | ||||
|             self.indent() | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Tracks the start and end of an indented block (a "section") | ||||
|     pub struct Section<'y> { | ||||
|         yamler: &'y mut CLangifier, | ||||
|     } | ||||
|  | ||||
|     impl<'y> Section<'y> { | ||||
|         pub fn new(yamler: &'y mut CLangifier) -> Self { | ||||
|             yamler.increase(); | ||||
|             Self { yamler } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     impl Deref for Section<'_> { | ||||
|         type Target = CLangifier; | ||||
|         fn deref(&self) -> &Self::Target { | ||||
|             self.yamler | ||||
|         } | ||||
|     } | ||||
|     impl DerefMut for Section<'_> { | ||||
|         fn deref_mut(&mut self) -> &mut Self::Target { | ||||
|             self.yamler | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     impl Drop for Section<'_> { | ||||
|         fn drop(&mut self) { | ||||
|             let Self { yamler } = self; | ||||
|             yamler.decrease(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub mod yamlify { | ||||
|     use std::iter; | ||||
|  | ||||
|     use super::yamler::CLangifier; | ||||
|     use cl_ast::*; | ||||
|  | ||||
|     pub trait CLangify { | ||||
|         fn print(&self, y: &mut CLangifier); | ||||
|     } | ||||
|  | ||||
|     impl CLangify for File { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             let File { name, items } = self; | ||||
|             // TODO: turn name into include guard | ||||
|             y.p("// Generated from ").p(name).endl(); | ||||
|             y.p(items); | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for Visibility { | ||||
|         fn print(&self, _y: &mut CLangifier) {} | ||||
|     } | ||||
|     impl CLangify for Mutability { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             if let Mutability::Not = self { | ||||
|                 y.p("const "); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     impl CLangify for Attrs { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             let Self { meta } = self; | ||||
|             y.key("Attrs").p(meta); | ||||
|             todo!("Attributes"); | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for Meta { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             let Self { name, kind } = self; | ||||
|             y.key("Meta").p(name).p(kind); | ||||
|             todo!("Attributes"); | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for MetaKind { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             match self { | ||||
|                 MetaKind::Plain => y, | ||||
|                 MetaKind::Equals(value) => y.p(value), | ||||
|                 MetaKind::Func(args) => y.p(args), | ||||
|             }; | ||||
|             todo!("Attributes"); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     impl CLangify for Item { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             let Self { span: _, attrs: _, vis, kind } = self; | ||||
|             y.p(vis).p(kind).endl().endl(); | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for ItemKind { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             match self { | ||||
|                 ItemKind::Alias(f) => y.p(f), | ||||
|                 ItemKind::Const(f) => y.p(f), | ||||
|                 ItemKind::Static(f) => y.p(f), | ||||
|                 ItemKind::Module(f) => y.p(f), | ||||
|                 ItemKind::Function(f) => y.p(f), | ||||
|                 ItemKind::Struct(f) => y.p(f), | ||||
|                 ItemKind::Enum(f) => y.p(f), | ||||
|                 ItemKind::Impl(f) => y.p(f), | ||||
|                 ItemKind::Use(f) => y.p(f), | ||||
|             }; | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for Alias { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             let Self { name, from } = self; | ||||
|             y.p("typedef ").p(from).p(" "); | ||||
|             y.p(name).p("; "); | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for Const { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             let Self { name, ty, init } = self; | ||||
|             y.p("const ").p(ty).p(" "); | ||||
|             y.p(name).p(" = ").p(init); | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for Static { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             let Self { mutable, name, ty, init } = self; | ||||
|             y.p(mutable).p(ty).p(" "); | ||||
|             y.p(name).p(" = ").p(init); | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for Module { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             let Self { name, file } = self; | ||||
|             y.key("// mod ").p(name).p(" {").endl(); | ||||
|             y.p(file); | ||||
|             y.endl().p("// } mod ").p(name); | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for Function { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             let Self { name, sign, bind, body } = self; | ||||
|             let TyFn { args, rety } = sign; | ||||
|             let types = match args.as_ref() { | ||||
|                 TyKind::Tuple(TyTuple { types }) => types.as_slice(), | ||||
|                 TyKind::Empty => &[], | ||||
|                 _ => panic!("Unsupported function args: {args}"), | ||||
|             }; | ||||
|             match rety { | ||||
|                 Some(ty) => y.p(ty), | ||||
|                 None => y.p("void"), | ||||
|             } | ||||
|             .p(" ") | ||||
|             .p(name) | ||||
|             .p("("); | ||||
|             for (idx, (bind, ty)) in bind.iter().zip(types).enumerate() { | ||||
|                 if idx > 0 { | ||||
|                     y.p(", "); | ||||
|                 } | ||||
|                 // y.print("/* TODO: desugar pat match args */"); | ||||
|                 y.p(ty).p(" ").p(bind); | ||||
|             } | ||||
|             y.p(")").p(body); | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for Struct { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             let Self { name, kind } = self; | ||||
|             y.p("struct ").p(name).key(" {").p(kind); | ||||
|             y.endl().p("}"); | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for StructKind { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             match self { | ||||
|                 StructKind::Empty => y.endl().p("char _zero_sized_t;"), | ||||
|                 StructKind::Tuple(k) => { | ||||
|                     for (idx, ty) in k.iter().enumerate() { | ||||
|                         y.endl().p(ty).p(" _").p(&idx).p(";"); | ||||
|                     } | ||||
|                     y | ||||
|                 } | ||||
|                 StructKind::Struct(k) => y.p(k), | ||||
|             }; | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for StructMember { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             let Self { vis, name, ty } = self; | ||||
|             y.p(vis).p(ty).p(" ").p(name).p(";"); | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for Enum { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             let Self { name, variants } = self; | ||||
|             y.key("enum ").p(name).p(" {").endl(); | ||||
|             match variants { | ||||
|                 Some(v) => { | ||||
|                     for (idx, variant) in v.iter().enumerate() { | ||||
|                         if idx > 0 { | ||||
|                             y.p(",").endl(); | ||||
|                         } | ||||
|                         y.p(variant); | ||||
|                     } | ||||
|                 } | ||||
|                 None => todo!(), | ||||
|             } | ||||
|             y.endl().p("\n}"); | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for Variant { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             let Self { name, kind } = self; | ||||
|             y.p(name).p(kind); | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for VariantKind { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             match self { | ||||
|                 VariantKind::Plain => y, | ||||
|                 VariantKind::CLike(v) => y.p(" = ").p(v), | ||||
|                 VariantKind::Tuple(v) => y.p("/* TODO: ").p(v).p(" */"), | ||||
|                 VariantKind::Struct(v) => y.p("/* TODO: ").p(v).p(" */"), | ||||
|             }; | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for Impl { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             let Self { target, body } = self; | ||||
|             y.key("/* TODO: impl ").p(target).p(" { */ "); | ||||
|             y.p(body); | ||||
|             y.p("/* } // impl ").p(target).p(" */ "); | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for ImplKind { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             match self { | ||||
|                 ImplKind::Type(t) => y.p(t), | ||||
|                 ImplKind::Trait { impl_trait, for_type } => { | ||||
|                     todo!("impl {impl_trait} for {for_type}") | ||||
|                 } | ||||
|             }; | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for Use { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             let Self { absolute: _, tree } = self; | ||||
|             y.p(tree); | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for UseTree { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             match self { | ||||
|                 UseTree::Tree(trees) => y.p(trees), | ||||
|                 UseTree::Path(path, tree) => y.p("/* ").p(path).p(" */").p(tree), | ||||
|                 UseTree::Alias(from, to) => y.p("#import <").p(from).p(">.h// ").p(to).p(" "), | ||||
|                 UseTree::Name(name) => y.p("#import <").p(name).p(".h> "), | ||||
|                 UseTree::Glob => y.p("/* TODO: use globbing */"), | ||||
|             }; | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for Block { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             let Self { stmts } = self; | ||||
|             { | ||||
|                 let mut y = y.key("{"); | ||||
|                 y.endl(); | ||||
|                 if let [ | ||||
|                     stmts @ .., | ||||
|                     Stmt { span: _, kind: StmtKind::Expr(expr), semi: Semi::Unterminated }, | ||||
|                 ] = stmts.as_slice() | ||||
|                 { | ||||
|                     y.p(stmts).p("return ").p(expr).p(";"); | ||||
|                 } else { | ||||
|                     y.p(stmts); | ||||
|                 } | ||||
|             } | ||||
|             y.endl().p("}"); | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for Stmt { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             let Self { span: _, kind, semi: _ } = self; | ||||
|             y.p(kind).p(";").endl(); | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for Semi { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             y.p(";"); | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for StmtKind { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             match self { | ||||
|                 StmtKind::Empty => y, | ||||
|                 StmtKind::Item(s) => y.p(s), | ||||
|                 StmtKind::Expr(s) => y.p(s), | ||||
|             }; | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for Expr { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             let Self { span: _, kind } = self; | ||||
|             y.p(kind); | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for ExprKind { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             match self { | ||||
|                 ExprKind::Quote(k) => k.print(y), | ||||
|                 ExprKind::Let(k) => k.print(y), | ||||
|                 ExprKind::Match(k) => k.print(y), | ||||
|                 ExprKind::Assign(k) => k.print(y), | ||||
|                 ExprKind::Modify(k) => k.print(y), | ||||
|                 ExprKind::Binary(k) => k.print(y), | ||||
|                 ExprKind::Unary(k) => k.print(y), | ||||
|                 ExprKind::Cast(k) => k.print(y), | ||||
|                 ExprKind::Member(k) => k.print(y), | ||||
|                 ExprKind::Index(k) => k.print(y), | ||||
|                 ExprKind::Structor(k) => k.print(y), | ||||
|                 ExprKind::Path(k) => k.print(y), | ||||
|                 ExprKind::Literal(k) => k.print(y), | ||||
|                 ExprKind::Array(k) => k.print(y), | ||||
|                 ExprKind::ArrayRep(k) => k.print(y), | ||||
|                 ExprKind::AddrOf(k) => k.print(y), | ||||
|                 ExprKind::Block(k) => k.print(y), | ||||
|                 ExprKind::Empty => {} | ||||
|                 ExprKind::Group(k) => k.print(y), | ||||
|                 ExprKind::Tuple(k) => k.print(y), | ||||
|                 ExprKind::While(k) => k.print(y), | ||||
|                 ExprKind::If(k) => k.print(y), | ||||
|                 ExprKind::For(k) => k.print(y), | ||||
|                 ExprKind::Break(k) => k.print(y), | ||||
|                 ExprKind::Return(k) => k.print(y), | ||||
|                 ExprKind::Continue => { | ||||
|                     y.key("continue"); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for Quote { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             y.key("\""); | ||||
|             print!("{self}"); | ||||
|             y.p("\""); | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for Let { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             let Self { mutable, name, ty, init } = self; | ||||
|             let ty = ty.as_deref().map(|ty| &ty.kind).unwrap_or(&TyKind::Infer); | ||||
|             match ty { | ||||
|                 TyKind::Array(TyArray { ty, count }) => { | ||||
|                     y.p(ty).p(" ").p(mutable).p(name).p("[").p(count).p("]"); | ||||
|                 } | ||||
|                 TyKind::Fn(TyFn { args, rety }) => { | ||||
|                     y.key("(").p(rety).p(" *").p(mutable).p(name).p(")("); | ||||
|                     match args.as_ref() { | ||||
|                         TyKind::Empty => {} | ||||
|                         TyKind::Tuple(TyTuple { types }) => { | ||||
|                             for (idx, ty) in types.iter().enumerate() { | ||||
|                                 if idx > 0 { | ||||
|                                     y.p(", "); | ||||
|                                 } | ||||
|                                 y.p(ty); | ||||
|                             } | ||||
|                         } | ||||
|                         _ => { | ||||
|                             y.p(args); | ||||
|                         } | ||||
|                     } | ||||
|                     y.p(")"); | ||||
|                 } | ||||
|                 _ => { | ||||
|                     y.indent().p(ty).p(" ").p(mutable).p(name); | ||||
|                 } | ||||
|             } | ||||
|             if let Some(init) = init { | ||||
|                 y.p(" = ").p(init); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     impl CLangify for Pattern { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             // TODO: Pattern match desugaring!!! | ||||
|             match self { | ||||
|                 Pattern::Name(name) => y.p(name), | ||||
|                 Pattern::Literal(literal) => y.p(literal), | ||||
|                 Pattern::Rest(name) => y.p("..").p(name), | ||||
|                 Pattern::Ref(mutability, pattern) => y.p("&").p(mutability).p(pattern), | ||||
|                 Pattern::Tuple(patterns) => y.key("Tuple").p(patterns), | ||||
|                 Pattern::Array(patterns) => y.key("Array").p(patterns), | ||||
|                 Pattern::Struct(path, items) => { | ||||
|                     { | ||||
|                         let mut y = y.key("Struct"); | ||||
|                         y.p(path); | ||||
|                         for (name, item) in items { | ||||
|                             y.p(name).p(item); | ||||
|                         } | ||||
|                     } | ||||
|                     y | ||||
|                 } | ||||
|                 Pattern::TupleStruct(path, items) => { | ||||
|                     { | ||||
|                         let mut y = y.key("TupleStruct"); | ||||
|                         y.p(path).p(items); | ||||
|                     } | ||||
|                     y | ||||
|                 } | ||||
|             }; | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for Match { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             let Self { scrutinee, arms } = self; | ||||
|             y.p("/* match ").p(scrutinee); | ||||
|             y.key(" { ").p(arms); | ||||
|             y.p(" } */"); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     impl CLangify for MatchArm { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             let Self(pat, expr) = self; | ||||
|             y.p(pat).p(" => ").p(expr).p(", "); | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for Assign { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             let Self { parts } = self; | ||||
|             y.p(&parts.0).p(" = ").p(&parts.1); | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for Modify { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             let Self { kind, parts } = self; | ||||
|             y.p(&parts.0).p(kind).p(&parts.1); | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for ModifyKind { | ||||
|         fn print(&self, _y: &mut CLangifier) { | ||||
|             print!(" {self} "); | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for Binary { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             let Self { kind, parts } = self; | ||||
|             match kind { | ||||
|                 BinaryKind::Call => y.p(&parts.0).p(&parts.1), | ||||
|                 _ => y.p("(").p(&parts.0).p(kind).p(&parts.1).p(")"), | ||||
|             }; | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for BinaryKind { | ||||
|         fn print(&self, _y: &mut CLangifier) { | ||||
|             print!(" {self} "); | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for Unary { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             let Self { kind, tail } = self; | ||||
|             match kind { | ||||
|                 UnaryKind::Deref => y.p("*").p(tail), | ||||
|                 UnaryKind::Neg => y.p("-").p(tail), | ||||
|                 UnaryKind::Not => y.p("!").p(tail), | ||||
|                 UnaryKind::RangeInc => todo!("Unary RangeInc in C"), | ||||
|                 UnaryKind::RangeExc => todo!("Unary RangeExc in C"), | ||||
|                 UnaryKind::Loop => y.key("while (1) { ").p(tail).p(" }"), | ||||
|                 UnaryKind::At => todo!(), | ||||
|                 UnaryKind::Tilde => todo!(), | ||||
|             }; | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for Cast { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             let Self { head, ty } = self; | ||||
|             y.key("(").p(ty).p(")"); | ||||
|             y.p(head); | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for Member { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             let Self { head, kind } = self; | ||||
|             match kind { | ||||
|                 MemberKind::Call(name, Tuple { exprs }) => { | ||||
|                     y.p(name); | ||||
|                     y.p("("); | ||||
|                     for (idx, expr) in iter::once(head.as_ref()).chain(exprs).enumerate() { | ||||
|                         if idx > 0 { | ||||
|                             y.p(", "); | ||||
|                         } | ||||
|                         y.p(expr); | ||||
|                     } | ||||
|                     y.p(")") | ||||
|                 } | ||||
|                 MemberKind::Struct(name) => y.p(head).p(".").p(name), | ||||
|                 MemberKind::Tuple(idx) => y.p(head).p("._").p(idx), | ||||
|             }; | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for Tuple { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             let Self { exprs } = self; | ||||
|             let mut y = y.key("( "); | ||||
|             for (idx, expr) in exprs.iter().enumerate() { | ||||
|                 if idx > 0 { | ||||
|                     y.p(", "); | ||||
|                 } | ||||
|                 y.p(expr); | ||||
|             } | ||||
|             y.p(" )"); | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for Index { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             let Self { head, indices } = self; | ||||
|             y.p(head); | ||||
|             for index in indices { | ||||
|                 y.p("[").p(index).p("]"); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for Structor { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             let Self { to, init } = self; | ||||
|             y.key("(").p(to).p(")"); | ||||
|             { | ||||
|                 let mut y = y.key("{ "); | ||||
|                 for (idx, field) in init.iter().enumerate() { | ||||
|                     if idx > 0 { | ||||
|                         y.p(", "); | ||||
|                     } | ||||
|                     y.p(field); | ||||
|                 } | ||||
|                 y.p(init); | ||||
|             } | ||||
|             y.p("}"); | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for Fielder { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             let Self { name, init } = self; | ||||
|             y.p(".").p(name).p(" = ").p(init); | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for Array { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             let Self { values } = self; | ||||
|             { | ||||
|                 let mut y = y.key("{"); | ||||
|                 y.endl(); | ||||
|                 for (idx, value) in values.iter().enumerate() { | ||||
|                     if idx > 0 { | ||||
|                         y.p(", "); | ||||
|                     } | ||||
|                     y.p(value); | ||||
|                 } | ||||
|             } | ||||
|             y.endl().p("}"); | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for ArrayRep { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             let Self { value, repeat } = self; | ||||
|             // TODO: compile time evaluation | ||||
|             let ExprKind::Literal(Literal::Int(count)) = &repeat.kind else { | ||||
|                 panic!("Unsupported repeat count: {repeat}"); | ||||
|             }; | ||||
|             { | ||||
|                 let mut y = y.key("{"); | ||||
|                 y.endl(); | ||||
|                 for idx in 0..*count { | ||||
|                     if idx > 0 { | ||||
|                         y.p(", "); | ||||
|                     } | ||||
|                     y.p(value); | ||||
|                 } | ||||
|             } | ||||
|             y.endl().p("}"); | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for AddrOf { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             let Self { mutable: _, expr } = self; | ||||
|             y.p("&").p(expr); | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for Group { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             let Self { expr } = self; | ||||
|             y.p("(").p(expr).p(")"); | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for While { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             // TODO: to properly propagate intermediate values, a new temp variable needs to be | ||||
|             // declared on every line lmao. This will require type info. | ||||
|             let Self { cond, pass, fail } = self; | ||||
|             let Else { body: fail } = fail; | ||||
|             y.key("while(1) { if (").p(cond).p(")").p(pass); | ||||
|             if let Some(fail) = fail { | ||||
|                 y.p("else { ").p(fail).p("; break; }"); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for Else { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             let Self { body } = self; | ||||
|             if let Some(body) = body { | ||||
|                 y.key("else ").p(body); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for If { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             let Self { cond, pass, fail } = self; | ||||
|             y.p("(").p(cond).p(")"); | ||||
|             y.p(pass).p(fail); | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for For { | ||||
|         #[rustfmt::skip] | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             let Self { bind, cond, pass, fail: _ } = self; | ||||
|             let (mode, (head, tail)) = match &cond.kind { | ||||
|                 ExprKind::Binary(Binary { kind: BinaryKind::RangeExc, parts }) => (false, &**parts), | ||||
|                 ExprKind::Binary(Binary { kind: BinaryKind::RangeInc, parts }) => (true, &**parts), | ||||
|                 _ => todo!("Clangify for loops"), | ||||
|             }; | ||||
|             // for (int bind = head; bind mode? < : <= tail; bind++); | ||||
|             y.p("for ( int ").p(bind).p(" = ").p(head).p("; "); | ||||
|             y.p(bind).p(if mode {"<="} else {"<"}).p(tail).p("; "); | ||||
|             y.p("++").p(bind).p(" ) ").p(pass); | ||||
|  | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for Break { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             let Self { body } = self; | ||||
|             y.key("break ").p(body); | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for Return { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             let Self { body } = self; | ||||
|             y.key("return ").p(body); | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for Literal { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             match self { | ||||
|                 Literal::Float(l) => y.p(l), | ||||
|                 Literal::Bool(l) => y.p(l), | ||||
|                 Literal::Int(l) => y.p(l), | ||||
|                 Literal::Char(l) => y.p("'").p(l).p("'"), | ||||
|                 Literal::String(l) => y.p(&'"').p(l).p(&'"'), | ||||
|             }; | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for Sym { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             y.p(self.to_ref()); | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for Ty { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             let Self { span: _, kind } = self; | ||||
|             y.p(kind); | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for TyKind { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             match self { | ||||
|                 TyKind::Never => y.p("Never"), | ||||
|                 TyKind::Empty => y.p("Empty"), | ||||
|                 TyKind::Infer => y.p("Any"), | ||||
|                 TyKind::Path(t) => y.p(t), | ||||
|                 TyKind::Tuple(t) => y.p(t), | ||||
|                 TyKind::Ref(t) => y.p(t), | ||||
|                 TyKind::Fn(t) => y.p(t), | ||||
|                 TyKind::Slice(t) => y.p(t), | ||||
|                 TyKind::Array(t) => y.p(t), | ||||
|             }; | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for Path { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             let Self { absolute: _, parts } = self; | ||||
|             for (idx, part) in parts.iter().enumerate() { | ||||
|                 if idx > 0 { | ||||
|                     y.p("_"); | ||||
|                 } | ||||
|                 y.p(part); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for PathPart { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             match self { | ||||
|                 PathPart::SuperKw => y.p("super"), | ||||
|                 PathPart::SelfKw => y.p("self"), | ||||
|                 PathPart::SelfTy => y.p("Self"), | ||||
|                 PathPart::Ident(i) => y.p(i), | ||||
|             }; | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for TyArray { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             let Self { ty, count } = self; | ||||
|             y.p(ty).p("[").p(count).p("]"); | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for TySlice { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             let Self { ty } = self; | ||||
|             y.p(ty).p("* "); | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for TyTuple { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             let Self { types } = self; | ||||
|             { | ||||
|                 let mut y = y.key("struct {"); | ||||
|                 y.endl(); | ||||
|                 for (idx, ty) in types.iter().enumerate() { | ||||
|                     if idx > 0 { | ||||
|                         y.p(",").endl(); | ||||
|                     } | ||||
|                     y.p(ty); | ||||
|                 } | ||||
|             } | ||||
|             y.endl().p("}"); | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for TyRef { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             let Self { count, mutable, to } = self; | ||||
|             y.p(mutable).p(to); | ||||
|             for _ in 0..*count { | ||||
|                 y.p("*"); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for TyFn { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             let Self { args, rety } = self; | ||||
|             // TODO: function pointer syntax | ||||
|             y.key("*(").p(rety).p(")("); | ||||
|             match args.as_ref() { | ||||
|                 TyKind::Empty => y, | ||||
|                 TyKind::Tuple(TyTuple { types }) => { | ||||
|                     for (idx, ty) in types.iter().enumerate() { | ||||
|                         if idx > 0 { | ||||
|                             y.p(", "); | ||||
|                         } | ||||
|                         y.p(ty); | ||||
|                     } | ||||
|                     y | ||||
|                 } | ||||
|                 _ => y.p(args), | ||||
|             } | ||||
|             .p(")"); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     impl<T: CLangify> CLangify for Option<T> { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             if let Some(v) = self { | ||||
|                 y.p(v); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     impl<T: CLangify> CLangify for Box<T> { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             y.p(&**self); | ||||
|         } | ||||
|     } | ||||
|     impl<T: CLangify> CLangify for Vec<T> { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             for thing in self { | ||||
|                 y.p(thing); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     impl<T: CLangify> CLangify for [T] { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             for thing in self { | ||||
|                 y.p(thing); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     impl CLangify for () { | ||||
|         fn print(&self, _y: &mut CLangifier) { | ||||
|             // TODO: C has no language support for zst | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     impl<T: CLangify> CLangify for &T { | ||||
|         fn print(&self, y: &mut CLangifier) { | ||||
|             (*self).print(y) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     impl CLangify for std::fmt::Arguments<'_> { | ||||
|         fn print(&self, _y: &mut CLangifier) { | ||||
|             print!("{self}") | ||||
|         } | ||||
|     } | ||||
|     macro_rules! scalar { | ||||
|         ($($t:ty),*$(,)?) => { | ||||
|             $(impl CLangify for $t { | ||||
|                 fn print(&self, _y: &mut CLangifier) { | ||||
|                     print!("{self}"); | ||||
|                 } | ||||
|             })* | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     scalar! { | ||||
|         bool, char, u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, str, &str, String | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user