Make passes actually return errors well
This commit is contained in:
		
							parent
							
								
									e4845c4084
								
							
						
					
					
						commit
						575abe8172
					
				| @ -41,6 +41,9 @@ Currently missing relevant features (TODOs) are: | ||||
| - Debug Information | ||||
| - Borrows+Pointers | ||||
| 
 | ||||
| Smaller features: | ||||
| - Easier way to initialize arrays with a single value | ||||
| 
 | ||||
| ### Why "Reid" | ||||
| 
 | ||||
| [ᚱ is an Elder Futhark rune](https://en.wikipedia.org/wiki/Raido) which means | ||||
|  | ||||
| @ -1,10 +1,21 @@ | ||||
| 
 | ||||
| extern fn puts(message: string) -> i32; | ||||
| 
 | ||||
| struct DivT { | ||||
|     quot: i32, | ||||
|     rem: i32, | ||||
| } | ||||
| 
 | ||||
| extern fn div(numerator: i32, denominator: i32) -> DivT; | ||||
| 
 | ||||
| pub fn print(message: string) { | ||||
|     puts(message); | ||||
| } | ||||
| 
 | ||||
| pub fn intdiv(numerator: i32, denominator: i32) -> DivT { | ||||
|     return div(numerator, denominator); | ||||
| } | ||||
| 
 | ||||
| fn main() -> u16 { | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| @ -121,7 +121,7 @@ pub fn perform_all_passes<'map>( | ||||
|     #[cfg(debug_assertions)] | ||||
|     println!("{}", &context); | ||||
| 
 | ||||
|     let state = context.pass(&mut LinkerPass { module_map }); | ||||
|     let state = context.pass(&mut LinkerPass { module_map })?; | ||||
| 
 | ||||
|     #[cfg(debug_assertions)] | ||||
|     println!("{}", &context); | ||||
| @ -137,7 +137,7 @@ pub fn perform_all_passes<'map>( | ||||
| 
 | ||||
|     let refs = TypeRefs::default(); | ||||
| 
 | ||||
|     let state = context.pass(&mut TypeInference { refs: &refs }); | ||||
|     let state = context.pass(&mut TypeInference { refs: &refs })?; | ||||
| 
 | ||||
|     #[cfg(debug_assertions)] | ||||
|     dbg!(&refs); | ||||
| @ -157,7 +157,7 @@ pub fn perform_all_passes<'map>( | ||||
|         )); | ||||
|     } | ||||
| 
 | ||||
|     let state = context.pass(&mut TypeCheck { refs: &refs }); | ||||
|     let state = context.pass(&mut TypeCheck { refs: &refs })?; | ||||
| 
 | ||||
|     #[cfg(debug_assertions)] | ||||
|     println!("{}", &context); | ||||
| @ -189,13 +189,19 @@ pub fn compile_and_pass<'map>( | ||||
|     let path = path.canonicalize().unwrap(); | ||||
|     let name = path.file_name().unwrap().to_str().unwrap().to_owned(); | ||||
| 
 | ||||
|     let (id, tokens) = parse_module(source, name, module_map).unwrap(); | ||||
|     let (id, tokens) = parse_module(source, name, module_map)?; | ||||
|     let module = compile_module(id, &tokens, module_map, Some(path.clone()), true)?; | ||||
| 
 | ||||
|     let mut mir_context = mir::Context::from(vec![module], path.parent().unwrap().to_owned()); | ||||
| 
 | ||||
|     dbg!(&mir_context); | ||||
|     println!("Context: {}", &mir_context); | ||||
| 
 | ||||
|     perform_all_passes(&mut mir_context, module_map)?; | ||||
| 
 | ||||
|     dbg!(&mir_context); | ||||
|     println!("Context: {}", &mir_context); | ||||
| 
 | ||||
|     let mut context = Context::new(format!("Reid ({})", env!("CARGO_PKG_VERSION"))); | ||||
|     let codegen_modules = mir_context.codegen(&mut context, &module_map); | ||||
| 
 | ||||
|  | ||||
| @ -7,10 +7,15 @@ use std::{ | ||||
|     rc::Rc, | ||||
| }; | ||||
| 
 | ||||
| use crate::{compile_module, error_raporting::ModuleMap, lexer::FullToken, parse_module}; | ||||
| use crate::{ | ||||
|     compile_module, | ||||
|     error_raporting::{ModuleMap, ReidError}, | ||||
|     lexer::FullToken, | ||||
|     parse_module, | ||||
| }; | ||||
| 
 | ||||
| use super::{ | ||||
|     pass::{Pass, PassState}, | ||||
|     pass::{Pass, PassResult, PassState}, | ||||
|     r#impl::EqualsIssue, | ||||
|     Context, FunctionDefinition, Import, Metadata, Module, | ||||
| }; | ||||
| @ -41,14 +46,16 @@ pub enum ErrorKind { | ||||
|     FunctionIsPrivate(String, String), | ||||
| } | ||||
| 
 | ||||
| pub fn compile_std(module_map: &mut ModuleMap) -> (super::Module, Vec<FullToken>) { | ||||
|     let (id, tokens) = parse_module(STD_SOURCE, "standard_library", module_map).unwrap(); | ||||
|     let module = compile_module(id, &tokens, module_map, None, false).unwrap(); | ||||
| pub fn compile_std( | ||||
|     module_map: &mut ModuleMap, | ||||
| ) -> Result<(super::Module, Vec<FullToken>), ReidError> { | ||||
|     let (id, tokens) = parse_module(STD_SOURCE, "standard_library", module_map)?; | ||||
|     let module = compile_module(id, &tokens, module_map, None, false)?; | ||||
| 
 | ||||
|     let mut mir_context = super::Context::from(vec![module], Default::default()); | ||||
| 
 | ||||
|     let std_compiled = mir_context.modules.remove(0); | ||||
|     (std_compiled, tokens) | ||||
|     Ok((std_compiled, tokens)) | ||||
| } | ||||
| 
 | ||||
| /// Struct used to implement a type-checking pass that can be performed on the
 | ||||
| @ -62,7 +69,7 @@ type LinkerPassState<'st, 'sc> = PassState<'st, 'sc, (), ErrorKind>; | ||||
| impl<'map> Pass for LinkerPass<'map> { | ||||
|     type Data = (); | ||||
|     type TError = ErrorKind; | ||||
|     fn context(&mut self, context: &mut Context, mut state: LinkerPassState) { | ||||
|     fn context(&mut self, context: &mut Context, mut state: LinkerPassState) -> PassResult { | ||||
|         let mains = context | ||||
|             .modules | ||||
|             .iter() | ||||
| @ -70,16 +77,16 @@ impl<'map> Pass for LinkerPass<'map> { | ||||
|             .collect::<Vec<_>>(); | ||||
|         if mains.len() > 1 { | ||||
|             state.note_errors(&vec![ErrorKind::MultipleMainsAtStart], Metadata::default()); | ||||
|             return; | ||||
|             return Ok(()); | ||||
|         } | ||||
|         let Some(main) = mains.first() else { | ||||
|             state.note_errors(&vec![ErrorKind::NoMainDefined], Metadata::default()); | ||||
|             return; | ||||
|             return Ok(()); | ||||
|         }; | ||||
| 
 | ||||
|         let Some(_) = main.functions.iter().find(|f| f.name == "main") else { | ||||
|             state.note_errors(&vec![ErrorKind::NoMainFunction], Metadata::default()); | ||||
|             return; | ||||
|             return Ok(()); | ||||
|         }; | ||||
| 
 | ||||
|         let mut modules = HashMap::<String, Rc<RefCell<_>>>::new(); | ||||
| @ -95,10 +102,10 @@ impl<'map> Pass for LinkerPass<'map> { | ||||
|             modules.insert(module.name.clone(), Rc::new(RefCell::new((module, tokens)))); | ||||
|         } | ||||
| 
 | ||||
|         // modules.insert(
 | ||||
|         //     "std".to_owned(),
 | ||||
|         //     Rc::new(RefCell::new(compile_std(&mut self.module_map))),
 | ||||
|         // );
 | ||||
|         modules.insert( | ||||
|             "std".to_owned(), | ||||
|             Rc::new(RefCell::new(compile_std(&mut self.module_map)?)), | ||||
|         ); | ||||
| 
 | ||||
|         let mut modules_to_process: Vec<Rc<RefCell<(Module, Vec<FullToken>)>>> = | ||||
|             modules.values().cloned().collect(); | ||||
| @ -243,5 +250,7 @@ impl<'map> Pass for LinkerPass<'map> { | ||||
|             .into_values() | ||||
|             .map(|v| Rc::into_inner(v).unwrap().into_inner().0) | ||||
|             .collect(); | ||||
| 
 | ||||
|         Ok(()) | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -5,6 +5,8 @@ use std::collections::HashMap; | ||||
| use std::convert::Infallible; | ||||
| use std::error::Error as STDError; | ||||
| 
 | ||||
| use crate::error_raporting::ReidError; | ||||
| 
 | ||||
| use super::*; | ||||
| 
 | ||||
| #[derive(thiserror::Error, Debug, Clone)] | ||||
| @ -205,33 +207,65 @@ impl<'st, 'sc, Data: Clone + Default, TError: STDError + Clone> PassState<'st, ' | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub type PassResult = Result<(), ReidError>; | ||||
| 
 | ||||
| pub trait Pass { | ||||
|     type Data: Clone + Default; | ||||
|     type TError: STDError + Clone; | ||||
| 
 | ||||
|     fn context(&mut self, _context: &mut Context, mut _state: PassState<Self::Data, Self::TError>) { | ||||
|     fn context( | ||||
|         &mut self, | ||||
|         _context: &mut Context, | ||||
|         mut _state: PassState<Self::Data, Self::TError>, | ||||
|     ) -> PassResult { | ||||
|         Ok(()) | ||||
|     } | ||||
|     fn module( | ||||
|         &mut self, | ||||
|         _module: &mut Module, | ||||
|         mut _state: PassState<Self::Data, Self::TError>, | ||||
|     ) -> PassResult { | ||||
|         Ok(()) | ||||
|     } | ||||
|     fn module(&mut self, _module: &mut Module, mut _state: PassState<Self::Data, Self::TError>) {} | ||||
|     fn function( | ||||
|         &mut self, | ||||
|         _function: &mut FunctionDefinition, | ||||
|         mut _state: PassState<Self::Data, Self::TError>, | ||||
|     ) { | ||||
|     ) -> PassResult { | ||||
|         Ok(()) | ||||
|     } | ||||
|     fn block( | ||||
|         &mut self, | ||||
|         _block: &mut Block, | ||||
|         mut _state: PassState<Self::Data, Self::TError>, | ||||
|     ) -> PassResult { | ||||
|         Ok(()) | ||||
|     } | ||||
|     fn stmt( | ||||
|         &mut self, | ||||
|         _stmt: &mut Statement, | ||||
|         mut _state: PassState<Self::Data, Self::TError>, | ||||
|     ) -> PassResult { | ||||
|         Ok(()) | ||||
|     } | ||||
|     fn expr( | ||||
|         &mut self, | ||||
|         _expr: &mut Expression, | ||||
|         mut _state: PassState<Self::Data, Self::TError>, | ||||
|     ) -> PassResult { | ||||
|         Ok(()) | ||||
|     } | ||||
|     fn block(&mut self, _block: &mut Block, mut _state: PassState<Self::Data, Self::TError>) {} | ||||
|     fn stmt(&mut self, _stmt: &mut Statement, mut _state: PassState<Self::Data, Self::TError>) {} | ||||
|     fn expr(&mut self, _expr: &mut Expression, mut _state: PassState<Self::Data, Self::TError>) {} | ||||
| } | ||||
| 
 | ||||
| impl Context { | ||||
|     pub fn pass<T: Pass>(&mut self, pass: &mut T) -> State<T::TError> { | ||||
|     pub fn pass<T: Pass>(&mut self, pass: &mut T) -> Result<State<T::TError>, ReidError> { | ||||
|         let mut state = State::new(); | ||||
|         let mut scope = Scope::default(); | ||||
|         pass.context(self, PassState::from(&mut state, &mut scope)); | ||||
|         pass.context(self, PassState::from(&mut state, &mut scope))?; | ||||
|         for module in &mut self.modules { | ||||
|             module.pass(pass, &mut state, &mut scope.inner()); | ||||
|             module.pass(pass, &mut state, &mut scope.inner())?; | ||||
|         } | ||||
|         state | ||||
|         Ok(state) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -241,7 +275,7 @@ impl Module { | ||||
|         pass: &mut T, | ||||
|         state: &mut State<T::TError>, | ||||
|         scope: &mut Scope<T::Data>, | ||||
|     ) { | ||||
|     ) -> PassResult { | ||||
|         for typedef in &self.typedefs { | ||||
|             let kind = match &typedef.kind { | ||||
|                 TypeDefinitionKind::Struct(fields) => TypeDefinitionKind::Struct(fields.clone()), | ||||
| @ -262,11 +296,12 @@ impl Module { | ||||
|                 .ok(); | ||||
|         } | ||||
| 
 | ||||
|         pass.module(self, PassState::from(state, scope)); | ||||
|         pass.module(self, PassState::from(state, scope))?; | ||||
| 
 | ||||
|         for function in &mut self.functions { | ||||
|             function.pass(pass, state, &mut scope.inner()); | ||||
|             function.pass(pass, state, &mut scope.inner())?; | ||||
|         } | ||||
|         Ok(()) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -276,7 +311,7 @@ impl FunctionDefinition { | ||||
|         pass: &mut T, | ||||
|         state: &mut State<T::TError>, | ||||
|         scope: &mut Scope<T::Data>, | ||||
|     ) { | ||||
|     ) -> PassResult { | ||||
|         for param in &self.parameters { | ||||
|             scope | ||||
|                 .variables | ||||
| @ -290,15 +325,16 @@ impl FunctionDefinition { | ||||
|                 .ok(); | ||||
|         } | ||||
| 
 | ||||
|         pass.function(self, PassState::from(state, scope)); | ||||
|         pass.function(self, PassState::from(state, scope))?; | ||||
| 
 | ||||
|         match &mut self.kind { | ||||
|             FunctionDefinitionKind::Local(block, _) => { | ||||
|                 scope.return_type_hint = Some(self.return_type.clone()); | ||||
|                 block.pass(pass, state, scope); | ||||
|                 block.pass(pass, state, scope)?; | ||||
|             } | ||||
|             FunctionDefinitionKind::Extern(_) => {} | ||||
|         }; | ||||
|         Ok(()) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -308,14 +344,14 @@ impl Block { | ||||
|         pass: &mut T, | ||||
|         state: &mut State<T::TError>, | ||||
|         scope: &mut Scope<T::Data>, | ||||
|     ) { | ||||
|     ) -> PassResult { | ||||
|         let mut scope = scope.inner(); | ||||
| 
 | ||||
|         for statement in &mut self.statements { | ||||
|             statement.pass(pass, state, &mut scope); | ||||
|             statement.pass(pass, state, &mut scope)?; | ||||
|         } | ||||
| 
 | ||||
|         pass.block(self, PassState::from(state, &mut scope)); | ||||
|         pass.block(self, PassState::from(state, &mut scope)) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -325,21 +361,21 @@ impl Statement { | ||||
|         pass: &mut T, | ||||
|         state: &mut State<T::TError>, | ||||
|         scope: &mut Scope<T::Data>, | ||||
|     ) { | ||||
|     ) -> PassResult { | ||||
|         match &mut self.0 { | ||||
|             StmtKind::Let(_, _, expression) => { | ||||
|                 expression.pass(pass, state, scope); | ||||
|                 expression.pass(pass, state, scope)?; | ||||
|             } | ||||
|             StmtKind::Set(_, expression) => { | ||||
|                 expression.pass(pass, state, scope); | ||||
|                 expression.pass(pass, state, scope)?; | ||||
|             } | ||||
|             StmtKind::Import(_) => {} // Never exists at this stage
 | ||||
|             StmtKind::Expression(expression) => { | ||||
|                 expression.pass(pass, state, scope); | ||||
|                 expression.pass(pass, state, scope)?; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         pass.stmt(self, PassState::from(state, scope)); | ||||
|         pass.stmt(self, PassState::from(state, scope))?; | ||||
| 
 | ||||
|         match &mut self.0 { | ||||
|             StmtKind::Let(variable_reference, mutable, _) => { | ||||
| @ -358,6 +394,7 @@ impl Statement { | ||||
|             StmtKind::Import(_) => {} // Never exists at this stage
 | ||||
|             StmtKind::Expression(_) => {} | ||||
|         }; | ||||
|         Ok(()) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -367,7 +404,8 @@ impl Expression { | ||||
|         pass: &mut T, | ||||
|         state: &mut State<T::TError>, | ||||
|         scope: &mut Scope<T::Data>, | ||||
|     ) { | ||||
|         pass.expr(self, PassState::from(state, scope)); | ||||
|     ) -> PassResult { | ||||
|         pass.expr(self, PassState::from(state, scope))?; | ||||
|         Ok(()) | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -6,7 +6,7 @@ use crate::{mir::*, util::try_all}; | ||||
| use VagueType as Vague; | ||||
| 
 | ||||
| use super::{ | ||||
|     pass::{Pass, PassState, ScopeFunction, ScopeVariable}, | ||||
|     pass::{Pass, PassResult, PassState, ScopeFunction, ScopeVariable}, | ||||
|     typerefs::TypeRefs, | ||||
| }; | ||||
| 
 | ||||
| @ -70,7 +70,7 @@ impl<'t> Pass for TypeCheck<'t> { | ||||
|     type Data = (); | ||||
|     type TError = ErrorKind; | ||||
| 
 | ||||
|     fn module(&mut self, module: &mut Module, mut state: TypecheckPassState) { | ||||
|     fn module(&mut self, module: &mut Module, mut state: TypecheckPassState) -> PassResult { | ||||
|         let mut defmap = HashMap::new(); | ||||
|         for typedef in &module.typedefs { | ||||
|             let TypeDefinition { name, kind, meta } = &typedef; | ||||
| @ -107,6 +107,7 @@ impl<'t> Pass for TypeCheck<'t> { | ||||
|             let res = function.typecheck(&self.refs, &mut state.inner()); | ||||
|             state.ok(res, function.block_meta()); | ||||
|         } | ||||
|         Ok(()) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -9,7 +9,7 @@ use std::{convert::Infallible, iter}; | ||||
| use crate::{mir::TypeKind, util::try_all}; | ||||
| 
 | ||||
| use super::{ | ||||
|     pass::{Pass, PassState}, | ||||
|     pass::{Pass, PassResult, PassState}, | ||||
|     r#impl::pick_return, | ||||
|     typecheck::ErrorKind, | ||||
|     typerefs::{ScopeTypeRefs, TypeRef, TypeRefs}, | ||||
| @ -32,11 +32,12 @@ impl<'t> Pass for TypeInference<'t> { | ||||
|     type Data = (); | ||||
|     type TError = ErrorKind; | ||||
| 
 | ||||
|     fn module(&mut self, module: &mut Module, mut state: TypeInferencePassState) { | ||||
|     fn module(&mut self, module: &mut Module, mut state: TypeInferencePassState) -> PassResult { | ||||
|         for function in &mut module.functions { | ||||
|             let res = function.infer_types(&self.refs, &mut state.inner()); | ||||
|             state.ok(res, function.block_meta()); | ||||
|         } | ||||
|         Ok(()) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -14,7 +14,9 @@ fn compiles() { | ||||
| #[test] | ||||
| fn passes_all_passes() { | ||||
|     let mut map = Default::default(); | ||||
|     let (mut std, _) = compile_std(&mut map); | ||||
|     let Ok((mut std, _)) = compile_std(&mut map) else { | ||||
|         panic!() | ||||
|     }; | ||||
| 
 | ||||
|     // Needed to pass linker-pass
 | ||||
|     std.is_main = true; | ||||
|  | ||||
							
								
								
									
										12
									
								
								reid_src/std_test.reid
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								reid_src/std_test.reid
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | ||||
| 
 | ||||
| import std::print; | ||||
| import std::intdiv; | ||||
| 
 | ||||
| fn main() { | ||||
|     let hello = "hello world"; | ||||
| 
 | ||||
|     print(intdiv(10, 5).quot); | ||||
| 
 | ||||
|     print(hello); | ||||
| 
 | ||||
| } | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user