Attempt to significantly improve error-raporting
This commit is contained in:
		
							parent
							
								
									64e34ecf13
								
							
						
					
					
						commit
						f0e47a5d57
					
				| @ -1,6 +1,6 @@ | ||||
| use std::{env, error::Error, fs, path::PathBuf}; | ||||
| use std::{env, fs, path::PathBuf}; | ||||
| 
 | ||||
| use reid::compile; | ||||
| use reid::compile_simple; | ||||
| use reid_lib::compile::CompileOutput; | ||||
| 
 | ||||
| fn main() -> Result<(), std::io::Error> { | ||||
| @ -15,7 +15,7 @@ fn main() -> Result<(), std::io::Error> { | ||||
|         let before = std::time::SystemTime::now(); | ||||
| 
 | ||||
|         let text = fs::read_to_string(&path)?; | ||||
|         match compile(&text, PathBuf::from(&path)) { | ||||
|         match compile_simple(&text, PathBuf::from(&path)) { | ||||
|             Ok(CompileOutput { | ||||
|                 triple, | ||||
|                 assembly, | ||||
|  | ||||
| @ -0,0 +1,175 @@ | ||||
| use std::{collections::HashMap, fmt::Debug}; | ||||
| 
 | ||||
| use crate::{ | ||||
|     ast, lexer, | ||||
|     mir::{self, pass, Metadata, SourceModuleId}, | ||||
|     token_stream, | ||||
| }; | ||||
| 
 | ||||
| impl<T: std::error::Error + std::fmt::Display> pass::Error<T> { | ||||
|     fn fmt_simple(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||
|         std::fmt::Display::fmt(&self.kind, f) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(thiserror::Error, Debug, Clone, PartialEq, Eq)] | ||||
| pub enum ErrorKind { | ||||
|     #[error("Lexing: {0:?}")] | ||||
|     LexerError(#[from] mir::pass::Error<lexer::Error>), | ||||
|     #[error("Parsing: {0:?}")] | ||||
|     ParserError(#[from] mir::pass::Error<token_stream::Error>), | ||||
|     #[error("Typechecking: {0:?}")] | ||||
|     TypeCheckError(#[source] mir::pass::Error<mir::typecheck::ErrorKind>), | ||||
|     #[error("Type Inference: {0:?}")] | ||||
|     TypeInferenceError(#[source] mir::pass::Error<mir::typecheck::ErrorKind>), | ||||
|     #[error("Linking: {0:?}")] | ||||
|     LinkerError(#[from] mir::pass::Error<mir::linker::ErrorKind>), | ||||
| } | ||||
| 
 | ||||
| impl ErrorKind { | ||||
|     pub fn from_typecheck(err: mir::pass::Error<mir::typecheck::ErrorKind>) -> ErrorKind { | ||||
|         ErrorKind::TypeCheckError(err) | ||||
|     } | ||||
| 
 | ||||
|     pub fn from_typeinference(err: mir::pass::Error<mir::typecheck::ErrorKind>) -> ErrorKind { | ||||
|         ErrorKind::TypeInferenceError(err) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl ErrorKind { | ||||
|     fn get_meta(&self) -> Metadata { | ||||
|         match &self { | ||||
|             ErrorKind::LexerError(error) => error.metadata, | ||||
|             ErrorKind::ParserError(error) => error.metadata, | ||||
|             ErrorKind::TypeCheckError(error) => error.metadata, | ||||
|             ErrorKind::TypeInferenceError(error) => error.metadata, | ||||
|             ErrorKind::LinkerError(error) => error.metadata, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl PartialOrd for ErrorKind { | ||||
|     fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { | ||||
|         self.get_meta() | ||||
|             .source_module_id | ||||
|             .partial_cmp(&other.get_meta().source_module_id) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Ord for ErrorKind { | ||||
|     fn cmp(&self, other: &Self) -> std::cmp::Ordering { | ||||
|         self.get_meta().cmp(&other.get_meta()) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone, PartialEq, Eq, Default)] | ||||
| pub struct ModuleMap { | ||||
|     module_map: HashMap<mir::SourceModuleId, String>, | ||||
|     module_counter: mir::SourceModuleId, | ||||
| } | ||||
| 
 | ||||
| impl ModuleMap { | ||||
|     pub fn add_module<T: Into<String>>(&mut self, name: T) -> Option<mir::SourceModuleId> { | ||||
|         let id = self.module_counter.increment(); | ||||
|         self.module_map.insert(id, name.into().clone()); | ||||
|         Some(id) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl TryFrom<&mir::Context> for ModuleMap { | ||||
|     type Error = (); | ||||
| 
 | ||||
|     fn try_from(value: &mir::Context) -> Result<Self, Self::Error> { | ||||
|         let mut map = HashMap::new(); | ||||
|         for module in &value.modules { | ||||
|             if let Some(_) = map.insert(module.module_id, module.name.clone()) { | ||||
|                 return Err(()); | ||||
|             } | ||||
|         } | ||||
|         let module_counter = value.modules.iter().map(|m| m.module_id).max().ok_or(())?; | ||||
|         Ok(ModuleMap { | ||||
|             module_map: map, | ||||
|             module_counter, | ||||
|         }) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone, PartialEq, Eq)] | ||||
| pub struct ReidError { | ||||
|     map: ModuleMap, | ||||
|     errors: Vec<ErrorKind>, | ||||
| } | ||||
| 
 | ||||
| impl std::error::Error for ReidError {} | ||||
| 
 | ||||
| impl std::fmt::Display for ReidError { | ||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||
|         let mut sorted_errors = self.errors.clone(); | ||||
|         sorted_errors.sort_by(|a, b| a.cmp(&b)); | ||||
| 
 | ||||
|         let mut curr_module = None; | ||||
|         for error in sorted_errors { | ||||
|             let meta = error.get_meta(); | ||||
|             if curr_module != Some(meta.source_module_id) { | ||||
|                 curr_module = Some(meta.source_module_id); | ||||
|                 writeln!( | ||||
|                     f, | ||||
|                     "Errors in module {}:", | ||||
|                     self.map.module_map.get(&meta.source_module_id).unwrap() | ||||
|                 )?; | ||||
|             } | ||||
|             write!(f, "  Error: ")?; | ||||
|             std::fmt::Display::fmt(&error, f)?; | ||||
|             writeln!(f, "      At: {}", meta)?; | ||||
|         } | ||||
|         Ok(()) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl ReidError { | ||||
|     pub fn from_lexer<U>( | ||||
|         result: Result<U, lexer::Error>, | ||||
|         map: ModuleMap, | ||||
|         module: SourceModuleId, | ||||
|     ) -> Result<U, ReidError> { | ||||
|         result.map_err(|error| { | ||||
|             let pass_err = pass::Error { | ||||
|                 metadata: Metadata { | ||||
|                     source_module_id: module, | ||||
|                     range: Default::default(), | ||||
|                     position: Some(*error.get_position()), | ||||
|                 }, | ||||
|                 kind: error, | ||||
|             }; | ||||
|             ReidError { | ||||
|                 map, | ||||
|                 errors: vec![ErrorKind::LexerError(pass_err)], | ||||
|             } | ||||
|         }) | ||||
|     } | ||||
| 
 | ||||
|     pub fn from_parser<U>( | ||||
|         result: Result<U, token_stream::Error>, | ||||
|         map: ModuleMap, | ||||
|         module: SourceModuleId, | ||||
|     ) -> Result<U, ReidError> { | ||||
|         result.map_err(|error| { | ||||
|             let pass_err = pass::Error { | ||||
|                 metadata: Metadata { | ||||
|                     source_module_id: module, | ||||
|                     range: Default::default(), | ||||
|                     position: error.get_position().copied(), | ||||
|                 }, | ||||
|                 kind: error, | ||||
|             }; | ||||
|             ReidError { | ||||
|                 map, | ||||
|                 errors: vec![ErrorKind::ParserError(pass_err)], | ||||
|             } | ||||
|         }) | ||||
|     } | ||||
| 
 | ||||
|     pub fn from_kind<U>(errors: Vec<ErrorKind>, map: ModuleMap) -> ReidError { | ||||
|         ReidError { map, errors } | ||||
|     } | ||||
| } | ||||
| @ -2,7 +2,7 @@ use std::{fmt::Debug, str::Chars}; | ||||
| 
 | ||||
| static DECIMAL_NUMERICS: &[char] = &['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; | ||||
| 
 | ||||
| #[derive(Debug, Eq, PartialEq, Clone)] | ||||
| #[derive(Debug, Eq, PartialEq, Clone, PartialOrd, Ord)] | ||||
| pub enum Token { | ||||
|     /// Values
 | ||||
|     Identifier(String), | ||||
| @ -273,10 +273,19 @@ pub fn tokenize<T: Into<String>>(to_tokenize: T) -> Result<Vec<FullToken>, Error | ||||
|     Ok(tokens) | ||||
| } | ||||
| 
 | ||||
| #[derive(thiserror::Error, Debug, Clone)] | ||||
| #[derive(thiserror::Error, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] | ||||
| pub enum Error { | ||||
|     #[error("Invalid token '{}' at Ln {}, Col {}", .0, (.1).1, (.1).0)] | ||||
|     InvalidToken(char, Position), | ||||
|     #[error("String literal that starts at Ln {}, Col {} is never finished!", (.0).1, (.0).0)] | ||||
|     MissingQuotation(Position), | ||||
| } | ||||
| 
 | ||||
| impl Error { | ||||
|     pub fn get_position(&self) -> &Position { | ||||
|         match self { | ||||
|             Error::InvalidToken(_, pos) => pos, | ||||
|             Error::MissingQuotation(pos) => pos, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -41,8 +41,9 @@ | ||||
| //! - Debug Symbols
 | ||||
| //! ```
 | ||||
| 
 | ||||
| use std::path::PathBuf; | ||||
| use std::{convert::Infallible, path::PathBuf}; | ||||
| 
 | ||||
| use error_raporting::{ErrorKind as ErrorRapKind, ModuleMap, ReidError}; | ||||
| use mir::{ | ||||
|     linker::LinkerPass, typecheck::TypeCheck, typeinference::TypeInference, typerefs::TypeRefs, | ||||
|     SourceModuleId, | ||||
| @ -53,34 +54,22 @@ use crate::{ast::TopLevelStatement, lexer::Token, token_stream::TokenStream}; | ||||
| 
 | ||||
| mod ast; | ||||
| mod codegen; | ||||
| mod error_raporting; | ||||
| mod lexer; | ||||
| pub mod mir; | ||||
| mod pad_adapter; | ||||
| mod token_stream; | ||||
| mod util; | ||||
| 
 | ||||
| #[derive(thiserror::Error, Debug, Clone)] | ||||
| pub enum ReidError { | ||||
|     #[error(transparent)] | ||||
|     LexerError(#[from] lexer::Error), | ||||
|     #[error(transparent)] | ||||
|     ParserError(#[from] token_stream::Error), | ||||
|     #[error("Errors during typecheck: {0:?}")] | ||||
|     TypeCheckErrors(Vec<mir::pass::Error<mir::typecheck::ErrorKind>>), | ||||
|     #[error("Errors during type inference: {0:?}")] | ||||
|     TypeInferenceErrors(Vec<mir::pass::Error<mir::typecheck::ErrorKind>>), | ||||
|     #[error("Errors during linking: {0:?}")] | ||||
|     LinkerErrors(Vec<mir::pass::Error<mir::linker::ErrorKind>>), | ||||
| } | ||||
| 
 | ||||
| pub fn compile_module( | ||||
| pub fn compile_module<'map>( | ||||
|     source: &str, | ||||
|     name: String, | ||||
|     module_id: SourceModuleId, | ||||
|     map: &'map mut ModuleMap, | ||||
|     path: Option<PathBuf>, | ||||
|     is_main: bool, | ||||
| ) -> Result<mir::Module, ReidError> { | ||||
|     let tokens = lexer::tokenize(source)?; | ||||
|     let id = map.add_module(name.clone()).unwrap(); | ||||
|     let tokens = ReidError::from_lexer(lexer::tokenize(source), map.clone(), id)?; | ||||
| 
 | ||||
|     #[cfg(debug_assertions)] | ||||
|     dbg!(&tokens); | ||||
| @ -90,7 +79,8 @@ pub fn compile_module( | ||||
|     let mut statements = Vec::new(); | ||||
| 
 | ||||
|     while !matches!(token_stream.peek().unwrap_or(Token::Eof), Token::Eof) { | ||||
|         let statement = token_stream.parse::<TopLevelStatement>()?; | ||||
|         let statement = | ||||
|             ReidError::from_parser(token_stream.parse::<TopLevelStatement>(), map.clone(), id)?; | ||||
|         statements.push(statement); | ||||
|     } | ||||
| 
 | ||||
| @ -101,17 +91,24 @@ pub fn compile_module( | ||||
|         is_main, | ||||
|     }; | ||||
| 
 | ||||
|     Ok(ast_module.process(module_id)) | ||||
|     Ok(ast_module.process(id)) | ||||
| } | ||||
| 
 | ||||
| pub fn perform_all_passes(context: &mut mir::Context) -> Result<(), ReidError> { | ||||
| pub fn perform_all_passes<'map>( | ||||
|     context: &mut mir::Context, | ||||
|     map: &'map mut ModuleMap, | ||||
| ) -> Result<(), ReidError> { | ||||
|     #[cfg(debug_assertions)] | ||||
|     dbg!(&context); | ||||
| 
 | ||||
|     #[cfg(debug_assertions)] | ||||
|     println!("{}", &context); | ||||
| 
 | ||||
|     let state = context.pass(&mut LinkerPass); | ||||
|     let mut module_map = (&*context).try_into().unwrap(); | ||||
| 
 | ||||
|     let state = context.pass(&mut LinkerPass { | ||||
|         module_map: &mut module_map, | ||||
|     }); | ||||
| 
 | ||||
|     #[cfg(debug_assertions)] | ||||
|     println!("{}", &context); | ||||
| @ -119,7 +116,10 @@ pub fn perform_all_passes(context: &mut mir::Context) -> Result<(), ReidError> { | ||||
|     dbg!(&state); | ||||
| 
 | ||||
|     if !state.errors.is_empty() { | ||||
|         return Err(ReidError::LinkerErrors(state.errors)); | ||||
|         return Err(ReidError::from_kind::<()>( | ||||
|             state.errors.iter().map(|e| e.clone().into()).collect(), | ||||
|             map.clone(), | ||||
|         )); | ||||
|     } | ||||
| 
 | ||||
|     let refs = TypeRefs::default(); | ||||
| @ -134,7 +134,14 @@ pub fn perform_all_passes(context: &mut mir::Context) -> Result<(), ReidError> { | ||||
|     dbg!(&state); | ||||
| 
 | ||||
|     if !state.errors.is_empty() { | ||||
|         return Err(ReidError::TypeInferenceErrors(state.errors)); | ||||
|         return Err(ReidError::from_kind::<()>( | ||||
|             state | ||||
|                 .errors | ||||
|                 .iter() | ||||
|                 .map(|e| ErrorRapKind::TypeInferenceError(e.clone())) | ||||
|                 .collect(), | ||||
|             map.clone(), | ||||
|         )); | ||||
|     } | ||||
| 
 | ||||
|     let state = context.pass(&mut TypeCheck { refs: &refs }); | ||||
| @ -145,7 +152,14 @@ pub fn perform_all_passes(context: &mut mir::Context) -> Result<(), ReidError> { | ||||
|     dbg!(&state); | ||||
| 
 | ||||
|     if !state.errors.is_empty() { | ||||
|         return Err(ReidError::TypeCheckErrors(state.errors)); | ||||
|         return Err(ReidError::from_kind::<()>( | ||||
|             state | ||||
|                 .errors | ||||
|                 .iter() | ||||
|                 .map(|e| ErrorRapKind::TypeCheckError(e.clone())) | ||||
|                 .collect(), | ||||
|             map.clone(), | ||||
|         )); | ||||
|     } | ||||
| 
 | ||||
|     Ok(()) | ||||
| @ -154,21 +168,24 @@ pub fn perform_all_passes(context: &mut mir::Context) -> Result<(), ReidError> { | ||||
| /// Takes in a bit of source code, parses and compiles it and produces `hello.o`
 | ||||
| /// and `hello.asm` from it, which can be linked using `ld` to produce an
 | ||||
| /// executable file.
 | ||||
| pub fn compile(source: &str, path: PathBuf) -> Result<CompileOutput, ReidError> { | ||||
| pub fn compile_and_pass<'map>( | ||||
|     source: &str, | ||||
|     path: PathBuf, | ||||
|     module_map: &'map mut ModuleMap, | ||||
| ) -> Result<CompileOutput, ReidError> { | ||||
|     let path = path.canonicalize().unwrap(); | ||||
| 
 | ||||
|     let mut mir_context = mir::Context::from( | ||||
|         vec![compile_module( | ||||
|             source, | ||||
|             path.file_name().unwrap().to_str().unwrap().to_owned(), | ||||
|             SourceModuleId::default(), | ||||
|             Some(path.clone()), | ||||
|             true, | ||||
|         )?], | ||||
|         path.parent().unwrap().to_owned(), | ||||
|     ); | ||||
|     let module = compile_module( | ||||
|         source, | ||||
|         path.file_name().unwrap().to_str().unwrap().to_owned(), | ||||
|         module_map, | ||||
|         Some(path.clone()), | ||||
|         true, | ||||
|     )?; | ||||
| 
 | ||||
|     perform_all_passes(&mut mir_context)?; | ||||
|     let mut mir_context = mir::Context::from(vec![module], path.parent().unwrap().to_owned()); | ||||
| 
 | ||||
|     perform_all_passes(&mut mir_context, module_map)?; | ||||
| 
 | ||||
|     let mut context = Context::new(); | ||||
|     let codegen_modules = mir_context.codegen(&mut context); | ||||
| @ -179,3 +196,8 @@ pub fn compile(source: &str, path: PathBuf) -> Result<CompileOutput, ReidError> | ||||
|     let compiled = codegen_modules.compile(); | ||||
|     Ok(compiled.output()) | ||||
| } | ||||
| 
 | ||||
| pub fn compile_simple(source: &str, path: PathBuf) -> Result<CompileOutput, ReidError> { | ||||
|     let mut map = ModuleMap::default(); | ||||
|     compile_and_pass(source, path, &mut map) | ||||
| } | ||||
|  | ||||
| @ -279,7 +279,7 @@ impl TypeKind { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone, thiserror::Error)] | ||||
| #[derive(Debug, Clone, thiserror::Error, PartialEq, Eq, PartialOrd, Ord)] | ||||
| pub enum EqualsIssue { | ||||
|     #[error("Function is already defined locally at {:?}", (.0).range)] | ||||
|     ExistsLocally(Metadata), | ||||
|  | ||||
| @ -7,7 +7,7 @@ use std::{ | ||||
|     rc::Rc, | ||||
| }; | ||||
| 
 | ||||
| use crate::{compile_module, ReidError}; | ||||
| use crate::{compile_module, error_raporting::ModuleMap}; | ||||
| 
 | ||||
| use super::{ | ||||
|     pass::{Pass, PassState}, | ||||
| @ -17,14 +17,14 @@ use super::{ | ||||
| 
 | ||||
| pub static STD_SOURCE: &str = include_str!("../../lib/std.reid"); | ||||
| 
 | ||||
| #[derive(thiserror::Error, Debug, Clone)] | ||||
| #[derive(thiserror::Error, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] | ||||
| pub enum ErrorKind { | ||||
|     #[error("Unable to import inner modules, not yet supported: {0}")] | ||||
|     InnerModulesNotYetSupported(Import), | ||||
|     #[error("No such module: {0}")] | ||||
|     ModuleNotFound(String), | ||||
|     #[error("Error while compiling module {0}: {1}")] | ||||
|     ModuleCompilationError(String, ReidError), | ||||
|     ModuleCompilationError(String, String), | ||||
|     #[error("No such function {0} found in module {1}")] | ||||
|     NoSuchFunctionInModule(String, String), | ||||
|     #[error("Importing function {0}::{1} not possible: {2}")] | ||||
| @ -41,11 +41,11 @@ pub enum ErrorKind { | ||||
|     FunctionIsPrivate(String, String), | ||||
| } | ||||
| 
 | ||||
| pub fn compile_std(module_id: SourceModuleId) -> super::Module { | ||||
| pub fn compile_std(module_map: &mut ModuleMap) -> super::Module { | ||||
|     let module = compile_module( | ||||
|         STD_SOURCE, | ||||
|         "standard_library".to_owned(), | ||||
|         module_id, | ||||
|         module_map, | ||||
|         None, | ||||
|         false, | ||||
|     ) | ||||
| @ -59,11 +59,13 @@ pub fn compile_std(module_id: SourceModuleId) -> super::Module { | ||||
| 
 | ||||
| /// Struct used to implement a type-checking pass that can be performed on the
 | ||||
| /// MIR.
 | ||||
| pub struct LinkerPass; | ||||
| pub struct LinkerPass<'map> { | ||||
|     pub module_map: &'map mut ModuleMap, | ||||
| } | ||||
| 
 | ||||
| type LinkerPassState<'st, 'sc> = PassState<'st, 'sc, (), ErrorKind>; | ||||
| 
 | ||||
| impl Pass for LinkerPass { | ||||
| impl<'map> Pass for LinkerPass<'map> { | ||||
|     type Data = (); | ||||
|     type TError = ErrorKind; | ||||
|     fn context(&mut self, context: &mut Context, mut state: LinkerPassState) { | ||||
| @ -92,15 +94,9 @@ impl Pass for LinkerPass { | ||||
|             modules.insert(module.name.clone(), Rc::new(RefCell::new(module))); | ||||
|         } | ||||
| 
 | ||||
|         let mut module_counter = modules | ||||
|             .values() | ||||
|             .map(|m| m.borrow().module_id) | ||||
|             .max() | ||||
|             .unwrap(); | ||||
| 
 | ||||
|         modules.insert( | ||||
|             "std".to_owned(), | ||||
|             Rc::new(RefCell::new(compile_std(module_counter.increment()))), | ||||
|             Rc::new(RefCell::new(compile_std(&mut self.module_map))), | ||||
|         ); | ||||
| 
 | ||||
|         let mut modules_to_process: Vec<Rc<RefCell<Module>>> = modules.values().cloned().collect(); | ||||
| @ -136,7 +132,7 @@ impl Pass for LinkerPass { | ||||
|                     match compile_module( | ||||
|                         &source, | ||||
|                         module_name.clone(), | ||||
|                         module_counter.increment(), | ||||
|                         &mut self.module_map, | ||||
|                         Some(file_path), | ||||
|                         false, | ||||
|                     ) { | ||||
| @ -159,7 +155,10 @@ impl Pass for LinkerPass { | ||||
|                         } | ||||
|                         Err(err) => { | ||||
|                             state.ok::<_, Infallible>( | ||||
|                                 Err(ErrorKind::ModuleCompilationError(module_name.clone(), err)), | ||||
|                                 Err(ErrorKind::ModuleCompilationError( | ||||
|                                     module_name.clone(), | ||||
|                                     format!("{}", err), | ||||
|                                 )), | ||||
|                                 import.1, | ||||
|                             ); | ||||
|                             continue; | ||||
|  | ||||
| @ -4,7 +4,7 @@ | ||||
| 
 | ||||
| use std::{collections::HashMap, path::PathBuf}; | ||||
| 
 | ||||
| use crate::token_stream::TokenRange; | ||||
| use crate::{lexer::Position, token_stream::TokenRange}; | ||||
| 
 | ||||
| mod display; | ||||
| pub mod r#impl; | ||||
| @ -24,10 +24,11 @@ impl SourceModuleId { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Default, Clone, Copy)] | ||||
| #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] | ||||
| pub struct Metadata { | ||||
|     pub range: TokenRange, | ||||
|     pub source_module_id: SourceModuleId, | ||||
|     pub range: TokenRange, | ||||
|     pub position: Option<Position>, | ||||
| } | ||||
| 
 | ||||
| impl std::ops::Add for Metadata { | ||||
| @ -38,6 +39,7 @@ impl std::ops::Add for Metadata { | ||||
|         Metadata { | ||||
|             range: self.range + rhs.range, | ||||
|             source_module_id: self.source_module_id, | ||||
|             position: None, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -47,11 +49,12 @@ impl TokenRange { | ||||
|         Metadata { | ||||
|             range: self, | ||||
|             source_module_id: module, | ||||
|             position: None, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)] | ||||
| #[derive(Debug, Clone, PartialEq, Eq, thiserror::Error, PartialOrd, Ord)] | ||||
| pub enum TypeKind { | ||||
|     #[error("bool")] | ||||
|     Bool, | ||||
| @ -89,7 +92,7 @@ pub enum TypeKind { | ||||
|     Vague(#[from] VagueType), | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)] | ||||
| #[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error, PartialOrd, Ord)] | ||||
| pub enum VagueType { | ||||
|     #[error("Unknown")] | ||||
|     Unknown, | ||||
| @ -125,7 +128,7 @@ impl TypeKind { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] | ||||
| pub enum Literal { | ||||
|     I8(i8), | ||||
|     I16(i16), | ||||
| @ -142,7 +145,7 @@ pub enum Literal { | ||||
|     Vague(VagueLiteral), | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone, Copy)] | ||||
| #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] | ||||
| pub enum VagueLiteral { | ||||
|     Number(u64), | ||||
| } | ||||
| @ -204,7 +207,7 @@ pub enum ReturnKind { | ||||
| #[derive(Debug)] | ||||
| pub struct NamedVariableRef(pub TypeKind, pub String, pub Metadata); | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] | ||||
| pub struct Import(pub Vec<String>, pub Metadata); | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
|  | ||||
| @ -15,10 +15,10 @@ pub enum SimplePassError { | ||||
|     VariableAlreadyDefined(String), | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] | ||||
| pub struct Error<TErr: STDError> { | ||||
|     metadata: Metadata, | ||||
|     kind: TErr, | ||||
|     pub metadata: Metadata, | ||||
|     pub kind: TErr, | ||||
| } | ||||
| 
 | ||||
| impl<TErr: STDError> std::fmt::Display for Error<TErr> { | ||||
|  | ||||
| @ -10,7 +10,7 @@ use super::{ | ||||
|     typerefs::TypeRefs, | ||||
| }; | ||||
| 
 | ||||
| #[derive(thiserror::Error, Debug, Clone)] | ||||
| #[derive(thiserror::Error, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] | ||||
| pub enum ErrorKind { | ||||
|     #[error("NULL error, should never occur!")] | ||||
|     Null, | ||||
|  | ||||
| @ -174,7 +174,7 @@ impl Drop for TokenStream<'_, '_> { | ||||
| 
 | ||||
| /// Index-range that can be used with the original array of [`FullToken`]s to
 | ||||
| /// retrieve the precise location of a failure.
 | ||||
| #[derive(Default, Clone, Copy)] | ||||
| #[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] | ||||
| pub struct TokenRange { | ||||
|     pub start: usize, | ||||
|     pub end: usize, | ||||
| @ -207,7 +207,7 @@ impl std::iter::Sum for TokenRange { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(thiserror::Error, Debug, Clone)] | ||||
| #[derive(thiserror::Error, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] | ||||
| pub enum Error { | ||||
|     #[error("Expected {} at Ln {}, Col {}, got {:?}", .0, (.2).1, (.2).0, .1)] | ||||
|     Expected(String, Token, Position), | ||||
| @ -220,3 +220,14 @@ pub enum Error { | ||||
|     #[error("Condition failed for parse-if. Should never be returned to end-user.")] | ||||
|     IfFailed, | ||||
| } | ||||
| 
 | ||||
| impl Error { | ||||
|     pub fn get_position(&self) -> Option<&Position> { | ||||
|         match self { | ||||
|             Error::Expected(_, _, pos) => Some(pos), | ||||
|             Error::FileEmpty => None, | ||||
|             Error::Undefined => None, | ||||
|             Error::IfFailed => None, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -7,88 +7,70 @@ use util::assert_err; | ||||
| 
 | ||||
| mod util; | ||||
| 
 | ||||
| fn test(source: &str, name: &str) { | ||||
|     let mut map = Default::default(); | ||||
|     let module = assert_err(compile_module( | ||||
|         source, | ||||
|         name.to_owned(), | ||||
|         &mut map, | ||||
|         None, | ||||
|         true, | ||||
|     )); | ||||
| 
 | ||||
|     assert_err(perform_all_passes( | ||||
|         &mut mir::Context { | ||||
|             modules: vec![module], | ||||
|             base: Default::default(), | ||||
|         }, | ||||
|         &mut map, | ||||
|     )); | ||||
| } | ||||
| 
 | ||||
| pub static ARRAY: &str = include_str!("../../reid_src/array.reid"); | ||||
| pub static FIBONACCI: &str = include_str!("../../reid_src/fibonacci.reid"); | ||||
| pub static HELLO_WORLD: &str = include_str!("../../reid_src/hello_world.reid"); | ||||
| pub static MUTABLE: &str = include_str!("../../reid_src/mutable.reid"); | ||||
| pub static STRINGS: &str = include_str!("../../reid_src/strings.reid"); | ||||
| pub static ARRAYS: &str = include_str!("../../reid_src/array.reid"); | ||||
| pub static STRUCTS: &str = include_str!("../../reid_src/struct.reid"); | ||||
| pub static ARRAY_STRUCTS: &str = include_str!("../../reid_src/array_structs.reid"); | ||||
| 
 | ||||
| #[test] | ||||
| fn array_compiles_well() { | ||||
|     let module = assert_err(compile_module( | ||||
|         ARRAY, | ||||
|         "array".to_owned(), | ||||
|         Default::default(), | ||||
|         None, | ||||
|         true, | ||||
|     )); | ||||
| 
 | ||||
|     assert_err(perform_all_passes(&mut mir::Context { | ||||
|         modules: vec![module], | ||||
|         base: Default::default(), | ||||
|     })); | ||||
|     test(ARRAY, "array"); | ||||
| } | ||||
| 
 | ||||
| #[test] | ||||
| fn fibonacci_compiles_well() { | ||||
|     let module = assert_err(compile_module( | ||||
|         FIBONACCI, | ||||
|         "fibonacci".to_owned(), | ||||
|         Default::default(), | ||||
|         None, | ||||
|         true, | ||||
|     )); | ||||
| 
 | ||||
|     assert_err(perform_all_passes(&mut mir::Context { | ||||
|         modules: vec![module], | ||||
|         base: Default::default(), | ||||
|     })); | ||||
|     test(FIBONACCI, "fibonacci"); | ||||
| } | ||||
| 
 | ||||
| #[test] | ||||
| fn hello_world_compiles_well() { | ||||
|     let module = assert_err(compile_module( | ||||
|         HELLO_WORLD, | ||||
|         "hello_world".to_owned(), | ||||
|         Default::default(), | ||||
|         None, | ||||
|         true, | ||||
|     )); | ||||
| 
 | ||||
|     assert_err(perform_all_passes(&mut mir::Context { | ||||
|         modules: vec![module], | ||||
|         base: Default::default(), | ||||
|     })); | ||||
|     test(HELLO_WORLD, "hello_world"); | ||||
| } | ||||
| 
 | ||||
| #[test] | ||||
| fn mutable_compiles_well() { | ||||
|     let module = assert_err(compile_module( | ||||
|         MUTABLE, | ||||
|         "mutable".to_owned(), | ||||
|         Default::default(), | ||||
|         None, | ||||
|         true, | ||||
|     )); | ||||
| 
 | ||||
|     assert_err(perform_all_passes(&mut mir::Context { | ||||
|         modules: vec![module], | ||||
|         base: Default::default(), | ||||
|     })); | ||||
|     test(MUTABLE, "mutable"); | ||||
| } | ||||
| 
 | ||||
| #[test] | ||||
| fn strings_compiles_well() { | ||||
|     let module = assert_err(compile_module( | ||||
|         STRINGS, | ||||
|         "strings".to_owned(), | ||||
|         Default::default(), | ||||
|         None, | ||||
|         true, | ||||
|     )); | ||||
| 
 | ||||
|     assert_err(perform_all_passes(&mut mir::Context { | ||||
|         modules: vec![module], | ||||
|         base: Default::default(), | ||||
|     })); | ||||
|     test(STRINGS, "strings"); | ||||
| } | ||||
| 
 | ||||
| #[test] | ||||
| fn arrays_compiles_well() { | ||||
|     test(ARRAY, "array"); | ||||
| } | ||||
| 
 | ||||
| #[test] | ||||
| fn struct_compiles_well() { | ||||
|     test(STRUCTS, "struct"); | ||||
| } | ||||
| 
 | ||||
| #[test] | ||||
| fn array_structs_compiles_well() { | ||||
|     test(ARRAY_STRUCTS, "array_structs"); | ||||
| } | ||||
|  | ||||
| @ -8,18 +8,22 @@ mod util; | ||||
| 
 | ||||
| #[test] | ||||
| fn compiles() { | ||||
|     let _ = compile_std(Default::default()); | ||||
|     let _ = compile_std(&mut Default::default()); | ||||
| } | ||||
| 
 | ||||
| #[test] | ||||
| fn passes_all_passes() { | ||||
|     let mut std = compile_std(Default::default()); | ||||
|     let mut map = Default::default(); | ||||
|     let mut std = compile_std(&mut map); | ||||
| 
 | ||||
|     // Needed to pass linker-pass
 | ||||
|     std.is_main = true; | ||||
| 
 | ||||
|     assert_err(perform_all_passes(&mut mir::Context { | ||||
|         modules: vec![std], | ||||
|         base: Default::default(), | ||||
|     })); | ||||
|     assert_err(perform_all_passes( | ||||
|         &mut mir::Context { | ||||
|             modules: vec![std], | ||||
|             base: Default::default(), | ||||
|         }, | ||||
|         &mut map, | ||||
|     )); | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user