main.rs
1 //! A compiler for the Olea programming language. 2 3 #![warn(missing_docs)] 4 #![allow( 5 clippy::cast_possible_truncation, 6 clippy::missing_panics_doc, 7 clippy::option_if_let_else, 8 clippy::similar_names, 9 clippy::too_many_lines, 10 clippy::type_complexity, 11 clippy::wildcard_imports, 12 clippy::cognitive_complexity 13 )] 14 15 mod arborist; 16 pub mod ast; 17 mod codegen_fox32; 18 pub mod compiler_types; 19 pub mod ir; 20 mod ir_builder; 21 mod ir_desugar; 22 mod ir_display; 23 pub mod ir_liveness; 24 // TODO: rewrite to account for `used_regs` not including phi arguments. 25 // mod ir_optimizer; 26 mod ir_opt; 27 mod lexer; 28 mod parser; 29 #[allow(dead_code)] 30 mod ttree_visualize; 31 mod typechecker; 32 33 use annotate_snippets::{renderer::Style, Level, Message, Renderer, Snippet}; 34 use compiler_types::Spanned; 35 use std::process::ExitCode; 36 37 fn error(message: &str) { 38 // Don't render message in bold, as is default. 39 let error_renderer = Renderer::styled().emphasis(Style::default()); 40 let error = Level::Error.title(message); 41 anstream::eprintln!("{}", error_renderer.render(error)); 42 } 43 44 fn error_snippet(message: Message) { 45 anstream::eprintln!("{}", Renderer::styled().render(message)); 46 } 47 48 fn main() -> ExitCode { 49 let args: Vec<_> = std::env::args().collect(); 50 if args.len() != 2 { 51 error(&format!( 52 "{} <file>", 53 args.first() 54 .map_or(env!("CARGO_CRATE_NAME"), String::as_ref) 55 )); 56 return ExitCode::FAILURE; 57 }; 58 let file_path = &args[1]; 59 let src = match std::fs::read_to_string(file_path) { 60 Ok(x) => x, 61 Err(e) => { 62 // We can probably do better error reporting, especially for common errors like file not found. 63 error(&format!("could not open `{file_path}`: {e}")); 64 return ExitCode::FAILURE; 65 } 66 }; 67 eprintln!("# Source code:\n{src}"); 68 69 let tokens = lexer::tokenize(&src); 70 /* 71 dbg!(tokens.has_error); 72 for i in 0..tokens.len() { 73 let lexer::Spanned { 74 token, 75 span: lexer::Span { start, len }, 76 } = tokens.get(i).unwrap(); 77 eprintln!("{:?} {:?}", &src[start..start + len], token); 78 } 79 */ 80 81 let ttree = match arborist::arborize(&tokens) { 82 Ok(x) => x, 83 Err(Spanned { kind, span }) => { 84 use arborist::ErrorKind as E; 85 let title = match kind { 86 E::Unexpected(c) => format!("unexpected {c:?}"), 87 E::Expected(c) => format!("expected {c:?}"), 88 E::Custom(msg) => msg.to_owned(), 89 }; 90 error_snippet( 91 Level::Error.title(&title).snippet( 92 Snippet::source(&src) 93 .origin(file_path) 94 .fold(true) 95 .annotation(Level::Error.span(span)), 96 ), 97 ); 98 return ExitCode::FAILURE; 99 } 100 }; 101 // eprintln!("# Token tree:"); 102 // ttree_visualize::visualize(&ttree, &src); 103 // eprintln!(); 104 105 let ast = match parser::parse(&ttree, &src) { 106 Ok(x) => x, 107 Err(Spanned { kind, span }) => { 108 let parser::ErrorKind::Custom(title) = kind; 109 error_snippet( 110 Level::Error.title(title).snippet( 111 Snippet::source(&src) 112 .origin(file_path) 113 .fold(true) 114 .annotation(Level::Error.span(span)), 115 ), 116 ); 117 return ExitCode::FAILURE; 118 } 119 }; 120 // eprintln!("#Syntax tree:\n{ast:?}\n"); 121 122 let mut ir = match ir_builder::build(&ast) { 123 Ok(x) => x, 124 Err(Spanned { kind, span }) => { 125 use ir_builder::ErrorKind as E; 126 let (title, note) = match kind { 127 E::NotFound(kind, v) => (format!("could not find {kind} `{v}`"), None), 128 E::NameConflict(kind, span) => ( 129 format!("a {kind} with this name has already been defined"), 130 span.map(|span| ("previously defined here".to_owned(), span)), 131 ), 132 E::DoesNotYield(span) => ( 133 "this expression needs to yield a value but doesn't".to_string(), 134 Some(("required by this outer context".to_owned(), span)), 135 ), 136 E::CantAssignToConstant => ("can't assign to constant".to_owned(), None), 137 E::CantCastToTy(ty) => (format!("can't cast a value to type {ty}"), None), 138 E::UnknownIntLiteralSuffix => ("unknown int literal suffix".to_owned(), None), 139 E::Todo(msg) => (format!("not yet implemented: {msg}"), None), 140 }; 141 let mut e = Snippet::source(&src) 142 .origin(file_path) 143 .fold(true) 144 .annotation(Level::Error.span(span)); 145 if let Some((message, span)) = ¬e { 146 e = e.annotation(Level::Info.span(span.clone()).label(message)); 147 } 148 error_snippet(Level::Error.title(&title).snippet(e)); 149 return ExitCode::FAILURE; 150 } 151 }; 152 eprintln!("#IR:\n{ir}\n"); 153 154 match typechecker::typecheck(&ir) { 155 Ok(()) => {} 156 Err((fn_name, e)) => { 157 use typechecker::ErrorKind as E; 158 let fun = ir.functions.get(&fn_name).unwrap(); 159 let snippet = Snippet::source(&src).origin(file_path).fold(true); 160 let (title, snippet): (String, _) = match e { 161 E::NotInt(reg) => ( 162 format!("expected integer, got {}", fun.tys.get(®).unwrap()), 163 snippet.annotation(Level::Error.span(fun.spans.get(®).unwrap().clone())), 164 ), 165 E::NotPointer(reg) => ( 166 format!( 167 "cannot dereference a value of type {}", 168 fun.tys.get(®).unwrap() 169 ), 170 snippet.annotation(Level::Error.span(fun.spans.get(®).unwrap().clone())), 171 ), 172 E::NotFunction(reg) => ( 173 format!("expected function, got {}", fun.tys.get(®).unwrap()), 174 snippet.annotation(Level::Error.span(fun.spans.get(®).unwrap().clone())), 175 ), 176 E::NotStruct(reg) => ( 177 format!( 178 "type {} does not support field access", 179 fun.tys.get(®).unwrap() 180 ), 181 snippet.annotation(Level::Error.span(fun.spans.get(®).unwrap().clone())), 182 ), 183 E::NoFieldNamed(reg, field) => ( 184 format!("{} does not have field {field}", fun.tys.get(®).unwrap()), 185 snippet.annotation(Level::Error.span(fun.spans.get(®).unwrap().clone())), 186 ), 187 E::Expected(reg, given_ty) => ( 188 format!("expected {given_ty}, got {}", fun.tys.get(®).unwrap()), 189 snippet.annotation(Level::Error.span(fun.spans.get(®).unwrap().clone())), 190 ), 191 }; 192 error_snippet(Level::Error.title(&title).snippet(snippet)); 193 return ExitCode::FAILURE; 194 } 195 } 196 eprintln!("#Desugaring phase"); 197 ir_desugar::desugar_program(&mut ir); 198 eprintln!("{ir}\n"); 199 200 if false { 201 eprintln!("#Optimizer phase"); 202 ir_opt::STACK_TO_REGISTER.run_program(&mut ir); 203 ir_opt::CONSTANT_PROPAGATION.run_program(&mut ir); 204 ir_opt::NOP_ELIMINATION.run_program(&mut ir); 205 eprintln!("{ir}\n"); 206 } 207 208 if true { 209 for (name, f) in &ir.functions { 210 let live = ir_liveness::calculate_liveness(f); 211 eprintln!("{name}:"); 212 live.pretty_print(); 213 } 214 eprintln!(); 215 216 let asm = codegen_fox32::gen_program(&ir); 217 eprintln!("#Codegen"); 218 print!("{asm}"); 219 } 220 ExitCode::SUCCESS 221 }