Make LSP use a more general analysis structure
This commit is contained in:
		
							parent
							
								
									dae39bc9d2
								
							
						
					
					
						commit
						8595da0c30
					
				
							
								
								
									
										294
									
								
								reid-lsp/src/analysis.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										294
									
								
								reid-lsp/src/analysis.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,294 @@ | |||||||
|  | use std::{collections::HashMap, path::PathBuf}; | ||||||
|  | 
 | ||||||
|  | use dashmap::DashMap; | ||||||
|  | use reid::{ | ||||||
|  |     ast::lexer::FullToken, | ||||||
|  |     compile_module, | ||||||
|  |     error_raporting::{ErrorModules, ReidError}, | ||||||
|  |     mir::{self, Context, FunctionCall, IfExpression, SourceModuleId, StructType, TypeKind, WhileStatement}, | ||||||
|  |     perform_all_passes, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | use crate::CompileResult; | ||||||
|  | 
 | ||||||
|  | #[derive(Debug, Clone)] | ||||||
|  | pub struct StaticAnalysis { | ||||||
|  |     pub tokens: Vec<FullToken>, | ||||||
|  |     pub token_analysis: HashMap<usize, SemanticAnalysis>, | ||||||
|  |     pub error: Option<ReidError>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Debug, Clone)] | ||||||
|  | pub struct SemanticAnalysis { | ||||||
|  |     pub ty: Option<TypeKind>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub fn analyze( | ||||||
|  |     module_id: SourceModuleId, | ||||||
|  |     tokens: Vec<FullToken>, | ||||||
|  |     path: PathBuf, | ||||||
|  |     map: &mut ErrorModules, | ||||||
|  | ) -> Result<Option<StaticAnalysis>, ReidError> { | ||||||
|  |     let mut token_analysis = HashMap::new(); | ||||||
|  | 
 | ||||||
|  |     let (module, error) = match compile_module(module_id, tokens, map, Some(path.clone()), true)? { | ||||||
|  |         Ok(module) => (module, None), | ||||||
|  |         Err((m, err)) => (m.process(module_id), Some(err)), | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     let module_id = module.module_id; | ||||||
|  |     let mut context = Context::from(vec![module], path.parent().unwrap().to_owned()); | ||||||
|  |     perform_all_passes(&mut context, map)?; | ||||||
|  | 
 | ||||||
|  |     for module in context.modules.into_values() { | ||||||
|  |         if module.module_id != module_id { | ||||||
|  |             continue; | ||||||
|  |         } | ||||||
|  |         for idx in 0..module.tokens.len() { | ||||||
|  |             token_analysis.insert( | ||||||
|  |                 idx, | ||||||
|  |                 SemanticAnalysis { | ||||||
|  |                     ty: find_type_in_context(&module, idx), | ||||||
|  |                 }, | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return Ok(Some(StaticAnalysis { | ||||||
|  |             tokens: module.tokens, | ||||||
|  |             token_analysis: token_analysis, | ||||||
|  |             error, | ||||||
|  |         })); | ||||||
|  |     } | ||||||
|  |     return Ok(None); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub fn find_type_in_context(module: &mir::Module, token_idx: usize) -> Option<TypeKind> { | ||||||
|  |     for import in &module.imports { | ||||||
|  |         if import.1.contains(token_idx) { | ||||||
|  |             return Some(TypeKind::CustomType(mir::CustomTypeKey( | ||||||
|  |                 "d".to_owned(), | ||||||
|  |                 SourceModuleId(1), | ||||||
|  |             ))); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     for typedef in &module.typedefs { | ||||||
|  |         if !typedef.meta.contains(token_idx) { | ||||||
|  |             continue; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         match &typedef.kind { | ||||||
|  |             mir::TypeDefinitionKind::Struct(StructType(fields)) => { | ||||||
|  |                 for field in fields { | ||||||
|  |                     if field.2.contains(token_idx) { | ||||||
|  |                         return Some(field.1.clone()); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     for binop in &module.binop_defs { | ||||||
|  |         if let Some(meta) = binop.block_meta() { | ||||||
|  |             if !meta.contains(token_idx) { | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             continue; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return match &binop.fn_kind { | ||||||
|  |             mir::FunctionDefinitionKind::Local(block, _) => find_type_in_block(&block, module.module_id, token_idx), | ||||||
|  |             mir::FunctionDefinitionKind::Extern(_) => None, | ||||||
|  |             mir::FunctionDefinitionKind::Intrinsic(_) => None, | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     for (_, function) in &module.associated_functions { | ||||||
|  |         if !(function.signature() + function.block_meta()).contains(token_idx) { | ||||||
|  |             continue; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         for param in &function.parameters { | ||||||
|  |             if param.meta.contains(token_idx) { | ||||||
|  |                 return Some(param.ty.clone()); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return match &function.kind { | ||||||
|  |             mir::FunctionDefinitionKind::Local(block, _) => find_type_in_block(&block, module.module_id, token_idx), | ||||||
|  |             mir::FunctionDefinitionKind::Extern(_) => None, | ||||||
|  |             mir::FunctionDefinitionKind::Intrinsic(_) => None, | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     for function in &module.functions { | ||||||
|  |         if !(function.signature() + function.block_meta()).contains(token_idx) { | ||||||
|  |             continue; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         for param in &function.parameters { | ||||||
|  |             if param.meta.contains(token_idx) { | ||||||
|  |                 return Some(param.ty.clone()); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return match &function.kind { | ||||||
|  |             mir::FunctionDefinitionKind::Local(block, _) => find_type_in_block(&block, module.module_id, token_idx), | ||||||
|  |             mir::FunctionDefinitionKind::Extern(_) => None, | ||||||
|  |             mir::FunctionDefinitionKind::Intrinsic(_) => None, | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  |     None | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub fn find_type_in_block(block: &mir::Block, module_id: SourceModuleId, token_idx: usize) -> Option<TypeKind> { | ||||||
|  |     if !block.meta.contains(token_idx) { | ||||||
|  |         return Some(TypeKind::Bool); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     for statement in &block.statements { | ||||||
|  |         if !statement.1.contains(token_idx) { | ||||||
|  |             continue; | ||||||
|  |         } | ||||||
|  |         match &statement.0 { | ||||||
|  |             mir::StmtKind::Let(named_variable_ref, _, expression) => { | ||||||
|  |                 if named_variable_ref.2.contains(token_idx) { | ||||||
|  |                     return expression | ||||||
|  |                         .return_type(&Default::default(), module_id) | ||||||
|  |                         .ok() | ||||||
|  |                         .map(|(_, ty)| ty); | ||||||
|  |                 } else { | ||||||
|  |                     return find_type_in_expr(&expression, module_id, token_idx); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             mir::StmtKind::Set(lhs, rhs) => { | ||||||
|  |                 return find_type_in_expr(lhs, module_id, token_idx).or(find_type_in_expr(rhs, module_id, token_idx)); | ||||||
|  |             } | ||||||
|  |             mir::StmtKind::Import(_) => {} | ||||||
|  |             mir::StmtKind::Expression(expression) => return find_type_in_expr(expression, module_id, token_idx), | ||||||
|  |             mir::StmtKind::While(WhileStatement { condition, block, .. }) => { | ||||||
|  |                 return find_type_in_expr(condition, module_id, token_idx) | ||||||
|  |                     .or(find_type_in_block(block, module_id, token_idx)); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if let Some((_, Some(return_exp))) = &block.return_expression { | ||||||
|  |         if let Some(ty) = find_type_in_expr(return_exp, module_id, token_idx) { | ||||||
|  |             return Some(ty); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     None | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub fn find_type_in_expr(expr: &mir::Expression, module_id: SourceModuleId, token_idx: usize) -> Option<TypeKind> { | ||||||
|  |     if !expr.1.contains(token_idx) { | ||||||
|  |         return None; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     match &expr.0 { | ||||||
|  |         mir::ExprKind::Variable(named_variable_ref) => Some(named_variable_ref.0.clone()), | ||||||
|  |         mir::ExprKind::Indexed(value, type_kind, index_expr) => Some( | ||||||
|  |             find_type_in_expr(&value, module_id, token_idx) | ||||||
|  |                 .or(find_type_in_expr(&index_expr, module_id, token_idx)) | ||||||
|  |                 .unwrap_or(type_kind.clone()), | ||||||
|  |         ), | ||||||
|  |         mir::ExprKind::Accessed(expression, type_kind, _, meta) => { | ||||||
|  |             if meta.contains(token_idx) { | ||||||
|  |                 Some(type_kind.clone()) | ||||||
|  |             } else { | ||||||
|  |                 find_type_in_expr(&expression, module_id, token_idx) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         mir::ExprKind::Array(expressions) => { | ||||||
|  |             for expr in expressions { | ||||||
|  |                 if let Some(ty) = find_type_in_expr(expr, module_id, token_idx) { | ||||||
|  |                     return Some(ty); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             None | ||||||
|  |         } | ||||||
|  |         mir::ExprKind::Struct(name, items) => { | ||||||
|  |             for (_, expr, meta) in items { | ||||||
|  |                 if meta.contains(token_idx) { | ||||||
|  |                     return expr.return_type(&Default::default(), module_id).map(|(_, t)| t).ok(); | ||||||
|  |                 } | ||||||
|  |                 if let Some(ty) = find_type_in_expr(expr, module_id, token_idx) { | ||||||
|  |                     return Some(ty); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             Some(TypeKind::CustomType(mir::CustomTypeKey(name.clone(), module_id))) | ||||||
|  |         } | ||||||
|  |         mir::ExprKind::Literal(literal) => Some(literal.as_type()), | ||||||
|  |         mir::ExprKind::BinOp(_, lhs, rhs, type_kind) => { | ||||||
|  |             if let Some(ty) = find_type_in_expr(lhs, module_id, token_idx) { | ||||||
|  |                 return Some(ty); | ||||||
|  |             } | ||||||
|  |             if let Some(ty) = find_type_in_expr(rhs, module_id, token_idx) { | ||||||
|  |                 return Some(ty); | ||||||
|  |             } | ||||||
|  |             Some(type_kind.clone()) | ||||||
|  |         } | ||||||
|  |         mir::ExprKind::FunctionCall(FunctionCall { | ||||||
|  |             return_type, | ||||||
|  |             parameters, | ||||||
|  |             .. | ||||||
|  |         }) => { | ||||||
|  |             for expr in parameters { | ||||||
|  |                 if let Some(ty) = find_type_in_expr(expr, module_id, token_idx) { | ||||||
|  |                     return Some(ty); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             Some(return_type.clone()) | ||||||
|  |         } | ||||||
|  |         mir::ExprKind::AssociatedFunctionCall( | ||||||
|  |             _, | ||||||
|  |             FunctionCall { | ||||||
|  |                 return_type, | ||||||
|  |                 parameters, | ||||||
|  |                 .. | ||||||
|  |             }, | ||||||
|  |         ) => { | ||||||
|  |             for expr in parameters { | ||||||
|  |                 if let Some(ty) = find_type_in_expr(expr, module_id, token_idx) { | ||||||
|  |                     return Some(ty); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             Some(return_type.clone()) | ||||||
|  |         } | ||||||
|  |         mir::ExprKind::If(IfExpression(cond, then_e, else_e)) => find_type_in_expr(&cond, module_id, token_idx) | ||||||
|  |             .or(find_type_in_expr(&then_e, module_id, token_idx)) | ||||||
|  |             .or(else_e.clone().and_then(|e| find_type_in_expr(&e, module_id, token_idx))), | ||||||
|  |         mir::ExprKind::Block(block) => find_type_in_block(block, module_id, token_idx), | ||||||
|  |         mir::ExprKind::Borrow(expression, mutable) => { | ||||||
|  |             if let Some(ty) = find_type_in_expr(&expression, module_id, token_idx) { | ||||||
|  |                 return Some(ty); | ||||||
|  |             } | ||||||
|  |             if let Ok(inner) = expression.return_type(&Default::default(), module_id).map(|(_, ty)| ty) { | ||||||
|  |                 Some(TypeKind::Borrow(Box::new(inner.clone()), *mutable)) | ||||||
|  |             } else { | ||||||
|  |                 None | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         mir::ExprKind::Deref(expression) => { | ||||||
|  |             if let Some(ty) = find_type_in_expr(&expression, module_id, token_idx) { | ||||||
|  |                 return Some(ty); | ||||||
|  |             } | ||||||
|  |             if let Ok(TypeKind::Borrow(inner, _)) = | ||||||
|  |                 expression.return_type(&Default::default(), module_id).map(|(_, ty)| ty) | ||||||
|  |             { | ||||||
|  |                 Some(*inner.clone()) | ||||||
|  |             } else { | ||||||
|  |                 Some(TypeKind::CustomType(mir::CustomTypeKey( | ||||||
|  |                     "ä".to_owned(), | ||||||
|  |                     SourceModuleId(1), | ||||||
|  |                 ))) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         mir::ExprKind::CastTo(expression, type_kind) => { | ||||||
|  |             Some(find_type_in_expr(&expression, module_id, token_idx).unwrap_or(type_kind.clone())) | ||||||
|  |         } | ||||||
|  |         mir::ExprKind::GlobalRef(_, type_kind) => Some(type_kind.clone()), | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -1,29 +1,28 @@ | |||||||
| use std::collections::HashMap; |  | ||||||
| use std::path::PathBuf; | use std::path::PathBuf; | ||||||
| 
 | 
 | ||||||
| use dashmap::DashMap; | use dashmap::DashMap; | ||||||
| use reid::ast::lexer::{FullToken, Position}; | use reid::ast::lexer::{FullToken, Position}; | ||||||
| use reid::error_raporting::{ErrorModules, ReidError}; | use reid::error_raporting::{self, ErrorModules, ReidError}; | ||||||
| use reid::mir::{ | use reid::mir::{SourceModuleId, TypeKind}; | ||||||
|     self, Context, FunctionCall, FunctionDefinition, FunctionParam, IfExpression, SourceModuleId, StructType, TypeKind, | use reid::parse_module; | ||||||
|     WhileStatement, |  | ||||||
| }; |  | ||||||
| use reid::{compile_module, parse_module, perform_all_passes}; |  | ||||||
| use tower_lsp::lsp_types::{ | use tower_lsp::lsp_types::{ | ||||||
|     self, CompletionItem, CompletionOptions, CompletionParams, CompletionResponse, Diagnostic, DiagnosticSeverity, |     self, CompletionItem, CompletionOptions, CompletionParams, CompletionResponse, Diagnostic, DiagnosticSeverity, | ||||||
|     DidChangeTextDocumentParams, DidOpenTextDocumentParams, Hover, HoverContents, HoverParams, HoverProviderCapability, |     DidChangeTextDocumentParams, DidOpenTextDocumentParams, Hover, HoverContents, HoverParams, HoverProviderCapability, | ||||||
|     InitializeParams, InitializeResult, InitializedParams, MarkedString, MarkupContent, MarkupKind, MessageType, OneOf, |     InitializeParams, InitializeResult, InitializedParams, MarkupContent, MarkupKind, MessageType, OneOf, Range, | ||||||
|     Range, ServerCapabilities, TextDocumentItem, TextDocumentSyncCapability, TextDocumentSyncKind, |     ServerCapabilities, TextDocumentItem, TextDocumentSyncCapability, TextDocumentSyncKind, TextDocumentSyncOptions, | ||||||
|     TextDocumentSyncOptions, WorkspaceFoldersServerCapabilities, WorkspaceServerCapabilities, |     WorkspaceFoldersServerCapabilities, WorkspaceServerCapabilities, | ||||||
| }; | }; | ||||||
| use tower_lsp::{Client, LanguageServer, LspService, Server, jsonrpc}; | use tower_lsp::{Client, LanguageServer, LspService, Server, jsonrpc}; | ||||||
| 
 | 
 | ||||||
|  | use crate::analysis::{StaticAnalysis, analyze}; | ||||||
|  | 
 | ||||||
|  | mod analysis; | ||||||
|  | 
 | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| struct Backend { | struct Backend { | ||||||
|     client: Client, |     client: Client, | ||||||
|     tokens: DashMap<String, Vec<FullToken>>, |     analysis: DashMap<String, StaticAnalysis>, | ||||||
|     ast: DashMap<String, reid::ast::Module>, |     ast: DashMap<String, reid::ast::Module>, | ||||||
|     types: DashMap<String, DashMap<FullToken, Option<TypeKind>>>, |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[tower_lsp::async_trait] | #[tower_lsp::async_trait] | ||||||
| @ -78,11 +77,11 @@ impl LanguageServer for Backend { | |||||||
|     async fn hover(&self, params: HoverParams) -> jsonrpc::Result<Option<Hover>> { |     async fn hover(&self, params: HoverParams) -> jsonrpc::Result<Option<Hover>> { | ||||||
|         let path = PathBuf::from(params.text_document_position_params.text_document.uri.path()); |         let path = PathBuf::from(params.text_document_position_params.text_document.uri.path()); | ||||||
|         let file_name = path.file_name().unwrap().to_str().unwrap().to_owned(); |         let file_name = path.file_name().unwrap().to_str().unwrap().to_owned(); | ||||||
|         let tokens = self.tokens.get(&file_name); |         let analysis = self.analysis.get(&file_name); | ||||||
|         let position = params.text_document_position_params.position; |         let position = params.text_document_position_params.position; | ||||||
| 
 | 
 | ||||||
|         let token = if let Some(tokens) = &tokens { |         let token = if let Some(analysis) = &analysis { | ||||||
|             tokens.iter().find(|tok| { |             analysis.tokens.iter().enumerate().find(|(_, tok)| { | ||||||
|                 tok.position.1 == position.line + 1 |                 tok.position.1 == position.line + 1 | ||||||
|                     && (tok.position.0 <= position.character + 1 |                     && (tok.position.0 <= position.character + 1 | ||||||
|                         && (tok.position.0 + tok.token.len() as u32) > position.character + 1) |                         && (tok.position.0 + tok.token.len() as u32) > position.character + 1) | ||||||
| @ -91,8 +90,8 @@ impl LanguageServer for Backend { | |||||||
|             None |             None | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         let (range, ty) = if let Some(token) = token { |         let (range, ty) = if let Some((idx, token)) = token { | ||||||
|             if let Some(possible_ty) = self.types.get(&file_name).unwrap().get(token) { |             if let Some(possible_ty) = self.analysis.get(&file_name).unwrap().token_analysis.get(&idx) { | ||||||
|                 let start = token.position; |                 let start = token.position; | ||||||
|                 let end = token.position.add(token.token.len() as u32); |                 let end = token.position.add(token.token.len() as u32); | ||||||
|                 let range = Range { |                 let range = Range { | ||||||
| @ -105,7 +104,7 @@ impl LanguageServer for Backend { | |||||||
|                         character: (end.0 as i32 - 1).max(0) as u32, |                         character: (end.0 as i32 - 1).max(0) as u32, | ||||||
|                     }, |                     }, | ||||||
|                 }; |                 }; | ||||||
|                 if let Some(ty) = possible_ty.clone() { |                 if let Some(ty) = possible_ty.ty.clone() { | ||||||
|                     (Some(range), format!("{}", ty)) |                     (Some(range), format!("{}", ty)) | ||||||
|                 } else { |                 } else { | ||||||
|                     (Some(range), String::from("None type")) |                     (Some(range), String::from("None type")) | ||||||
| @ -154,50 +153,33 @@ impl Backend { | |||||||
|         let mut map = Default::default(); |         let mut map = Default::default(); | ||||||
|         let parse_res = parse(¶ms.text, path.clone(), &mut map); |         let parse_res = parse(¶ms.text, path.clone(), &mut map); | ||||||
|         let (tokens, result) = match parse_res { |         let (tokens, result) = match parse_res { | ||||||
|             Ok((module_id, tokens)) => (tokens.clone(), compile(module_id, tokens, path, &mut map)), |             Ok((module_id, tokens)) => (tokens.clone(), analyze(module_id, tokens, path, &mut map)), | ||||||
|             Err(e) => (Vec::new(), Err(e)), |             Err(e) => (Vec::new(), Err(e)), | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         let mut diagnostics = Vec::new(); |         let mut diagnostics = Vec::new(); | ||||||
|         match result { |         match result { | ||||||
|             Ok(Some(result)) => { |             Ok(Some(mut analysis)) => { | ||||||
|                 self.tokens.insert(file_name.clone(), result.tokens); |                 if let Some(reid_error) = &mut analysis.error { | ||||||
|                 self.types.insert(file_name.clone(), result.types); |                     self.client | ||||||
|  |                         .log_message( | ||||||
|  |                             MessageType::INFO, | ||||||
|  |                             format!("Successfully compiled despite parsing errors!"), | ||||||
|  |                         ) | ||||||
|  |                         .await; | ||||||
|  |                     reid_error.errors.dedup(); | ||||||
|  |                     for error in &reid_error.errors { | ||||||
|  |                         diagnostics.push(reid_error_into_diagnostic(error, &tokens)); | ||||||
|  |                         self.client.log_message(MessageType::INFO, format!("{}", error)).await; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 self.analysis.insert(file_name.clone(), analysis); | ||||||
|             } |             } | ||||||
|             Ok(_) => {} |             Ok(_) => {} | ||||||
|             Err(mut reid_error) => { |             Err(mut reid_error) => { | ||||||
|                 reid_error.errors.dedup(); |                 reid_error.errors.dedup(); | ||||||
|                 for error in reid_error.errors { |                 for error in &reid_error.errors { | ||||||
|                     let meta = error.get_meta(); |                     diagnostics.push(reid_error_into_diagnostic(error, &tokens)); | ||||||
|                     let positions = meta |  | ||||||
|                         .range |  | ||||||
|                         .into_position(&tokens) |  | ||||||
|                         .unwrap_or((Position(0, 0), Position(0, 0))); |  | ||||||
|                     self.client.log_message(MessageType::INFO, format!("{:?}", &meta)).await; |  | ||||||
|                     self.client |  | ||||||
|                         .log_message(MessageType::INFO, format!("{:?}", &positions)) |  | ||||||
|                         .await; |  | ||||||
| 
 |  | ||||||
|                     diagnostics.push(Diagnostic { |  | ||||||
|                         range: Range { |  | ||||||
|                             start: lsp_types::Position { |  | ||||||
|                                 line: ((positions.0.1 as i32) - 1).max(0) as u32, |  | ||||||
|                                 character: ((positions.0.0 as i32) - 1).max(0) as u32, |  | ||||||
|                             }, |  | ||||||
|                             end: lsp_types::Position { |  | ||||||
|                                 line: ((positions.1.1 as i32) - 1).max(0) as u32, |  | ||||||
|                                 character: ((positions.1.0 as i32) - 1).max(0) as u32, |  | ||||||
|                             }, |  | ||||||
|                         }, |  | ||||||
|                         severity: Some(DiagnosticSeverity::ERROR), |  | ||||||
|                         code: None, |  | ||||||
|                         code_description: None, |  | ||||||
|                         source: Some(error.get_type_str().to_owned()), |  | ||||||
|                         message: format!("{}", error), |  | ||||||
|                         related_information: None, |  | ||||||
|                         tags: None, |  | ||||||
|                         data: None, |  | ||||||
|                     }); |  | ||||||
|                     self.client.log_message(MessageType::INFO, format!("{}", error)).await; |                     self.client.log_message(MessageType::INFO, format!("{}", error)).await; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| @ -209,6 +191,35 @@ impl Backend { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | fn reid_error_into_diagnostic(error: &error_raporting::ErrorKind, tokens: &Vec<FullToken>) -> Diagnostic { | ||||||
|  |     let meta = error.get_meta(); | ||||||
|  |     let positions = meta | ||||||
|  |         .range | ||||||
|  |         .into_position(&tokens) | ||||||
|  |         .unwrap_or((Position(0, 0), Position(0, 0))); | ||||||
|  | 
 | ||||||
|  |     Diagnostic { | ||||||
|  |         range: Range { | ||||||
|  |             start: lsp_types::Position { | ||||||
|  |                 line: ((positions.0.1 as i32) - 1).max(0) as u32, | ||||||
|  |                 character: ((positions.0.0 as i32) - 1).max(0) as u32, | ||||||
|  |             }, | ||||||
|  |             end: lsp_types::Position { | ||||||
|  |                 line: ((positions.1.1 as i32) - 1).max(0) as u32, | ||||||
|  |                 character: ((positions.1.0 as i32) - 1).max(0) as u32, | ||||||
|  |             }, | ||||||
|  |         }, | ||||||
|  |         severity: Some(DiagnosticSeverity::ERROR), | ||||||
|  |         code: None, | ||||||
|  |         code_description: None, | ||||||
|  |         source: Some(error.get_type_str().to_owned()), | ||||||
|  |         message: format!("{}", error), | ||||||
|  |         related_information: None, | ||||||
|  |         tags: None, | ||||||
|  |         data: None, | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| struct CompileResult { | struct CompileResult { | ||||||
|     tokens: Vec<FullToken>, |     tokens: Vec<FullToken>, | ||||||
|     types: DashMap<FullToken, Option<TypeKind>>, |     types: DashMap<FullToken, Option<TypeKind>>, | ||||||
| @ -220,36 +231,6 @@ fn parse(source: &str, path: PathBuf, map: &mut ErrorModules) -> Result<(SourceM | |||||||
|     Ok(parse_module(source, file_name.clone(), map)?) |     Ok(parse_module(source, file_name.clone(), map)?) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn compile( |  | ||||||
|     module_id: SourceModuleId, |  | ||||||
|     tokens: Vec<FullToken>, |  | ||||||
|     path: PathBuf, |  | ||||||
|     map: &mut ErrorModules, |  | ||||||
| ) -> Result<Option<CompileResult>, ReidError> { |  | ||||||
|     let token_types = DashMap::new(); |  | ||||||
| 
 |  | ||||||
|     let module = compile_module(module_id, tokens, map, Some(path.clone()), true)?; |  | ||||||
| 
 |  | ||||||
|     let module_id = module.module_id; |  | ||||||
|     let mut context = Context::from(vec![module], path.parent().unwrap().to_owned()); |  | ||||||
|     perform_all_passes(&mut context, map)?; |  | ||||||
| 
 |  | ||||||
|     for module in context.modules.into_values() { |  | ||||||
|         if module.module_id != module_id { |  | ||||||
|             continue; |  | ||||||
|         } |  | ||||||
|         for (idx, token) in module.tokens.iter().enumerate() { |  | ||||||
|             token_types.insert(token.clone(), find_type_in_context(&module, idx)); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         return Ok(Some(CompileResult { |  | ||||||
|             tokens: module.tokens, |  | ||||||
|             types: token_types, |  | ||||||
|         })); |  | ||||||
|     } |  | ||||||
|     return Ok(None); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[tokio::main] | #[tokio::main] | ||||||
| async fn main() { | async fn main() { | ||||||
|     let stdin = tokio::io::stdin(); |     let stdin = tokio::io::stdin(); | ||||||
| @ -258,239 +239,7 @@ async fn main() { | |||||||
|     let (service, socket) = LspService::new(|client| Backend { |     let (service, socket) = LspService::new(|client| Backend { | ||||||
|         client, |         client, | ||||||
|         ast: DashMap::new(), |         ast: DashMap::new(), | ||||||
|         tokens: DashMap::new(), |         analysis: DashMap::new(), | ||||||
|         types: DashMap::new(), |  | ||||||
|     }); |     }); | ||||||
|     Server::new(stdin, stdout, socket).serve(service).await; |     Server::new(stdin, stdout, socket).serve(service).await; | ||||||
| } | } | ||||||
| 
 |  | ||||||
| pub fn find_type_in_context(module: &mir::Module, token_idx: usize) -> Option<TypeKind> { |  | ||||||
|     for import in &module.imports { |  | ||||||
|         if import.1.contains(token_idx) { |  | ||||||
|             return Some(TypeKind::CustomType(mir::CustomTypeKey( |  | ||||||
|                 "d".to_owned(), |  | ||||||
|                 SourceModuleId(1), |  | ||||||
|             ))); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     for typedef in &module.typedefs { |  | ||||||
|         if !typedef.meta.contains(token_idx) { |  | ||||||
|             continue; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         match &typedef.kind { |  | ||||||
|             mir::TypeDefinitionKind::Struct(StructType(fields)) => { |  | ||||||
|                 for field in fields { |  | ||||||
|                     if field.2.contains(token_idx) { |  | ||||||
|                         return Some(field.1.clone()); |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     for binop in &module.binop_defs { |  | ||||||
|         if let Some(meta) = binop.block_meta() { |  | ||||||
|             if !meta.contains(token_idx) { |  | ||||||
|                 continue; |  | ||||||
|             } |  | ||||||
|         } else { |  | ||||||
|             continue; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         return match &binop.fn_kind { |  | ||||||
|             mir::FunctionDefinitionKind::Local(block, _) => find_type_in_block(&block, module.module_id, token_idx), |  | ||||||
|             mir::FunctionDefinitionKind::Extern(_) => None, |  | ||||||
|             mir::FunctionDefinitionKind::Intrinsic(_) => None, |  | ||||||
|         }; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     for (_, function) in &module.associated_functions { |  | ||||||
|         if !(function.signature() + function.block_meta()).contains(token_idx) { |  | ||||||
|             continue; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         for param in &function.parameters { |  | ||||||
|             if param.meta.contains(token_idx) { |  | ||||||
|                 return Some(param.ty.clone()); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         return match &function.kind { |  | ||||||
|             mir::FunctionDefinitionKind::Local(block, _) => find_type_in_block(&block, module.module_id, token_idx), |  | ||||||
|             mir::FunctionDefinitionKind::Extern(_) => None, |  | ||||||
|             mir::FunctionDefinitionKind::Intrinsic(_) => None, |  | ||||||
|         }; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     for function in &module.functions { |  | ||||||
|         if !(function.signature() + function.block_meta()).contains(token_idx) { |  | ||||||
|             continue; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         for param in &function.parameters { |  | ||||||
|             if param.meta.contains(token_idx) { |  | ||||||
|                 return Some(param.ty.clone()); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         return match &function.kind { |  | ||||||
|             mir::FunctionDefinitionKind::Local(block, _) => find_type_in_block(&block, module.module_id, token_idx), |  | ||||||
|             mir::FunctionDefinitionKind::Extern(_) => None, |  | ||||||
|             mir::FunctionDefinitionKind::Intrinsic(_) => None, |  | ||||||
|         }; |  | ||||||
|     } |  | ||||||
|     None |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| pub fn find_type_in_block(block: &mir::Block, module_id: SourceModuleId, token_idx: usize) -> Option<TypeKind> { |  | ||||||
|     if !block.meta.contains(token_idx) { |  | ||||||
|         return Some(TypeKind::Bool); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     for statement in &block.statements { |  | ||||||
|         if !statement.1.contains(token_idx) { |  | ||||||
|             continue; |  | ||||||
|         } |  | ||||||
|         match &statement.0 { |  | ||||||
|             mir::StmtKind::Let(named_variable_ref, _, expression) => { |  | ||||||
|                 if named_variable_ref.2.contains(token_idx) { |  | ||||||
|                     return expression |  | ||||||
|                         .return_type(&Default::default(), module_id) |  | ||||||
|                         .ok() |  | ||||||
|                         .map(|(_, ty)| ty); |  | ||||||
|                 } else { |  | ||||||
|                     return find_type_in_expr(&expression, module_id, token_idx); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             mir::StmtKind::Set(lhs, rhs) => { |  | ||||||
|                 return find_type_in_expr(lhs, module_id, token_idx).or(find_type_in_expr(rhs, module_id, token_idx)); |  | ||||||
|             } |  | ||||||
|             mir::StmtKind::Import(_) => {} |  | ||||||
|             mir::StmtKind::Expression(expression) => return find_type_in_expr(expression, module_id, token_idx), |  | ||||||
|             mir::StmtKind::While(WhileStatement { condition, block, .. }) => { |  | ||||||
|                 return find_type_in_expr(condition, module_id, token_idx) |  | ||||||
|                     .or(find_type_in_block(block, module_id, token_idx)); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if let Some((_, Some(return_exp))) = &block.return_expression { |  | ||||||
|         if let Some(ty) = find_type_in_expr(return_exp, module_id, token_idx) { |  | ||||||
|             return Some(ty); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     None |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| pub fn find_type_in_expr(expr: &mir::Expression, module_id: SourceModuleId, token_idx: usize) -> Option<TypeKind> { |  | ||||||
|     if !expr.1.contains(token_idx) { |  | ||||||
|         return None; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     match &expr.0 { |  | ||||||
|         mir::ExprKind::Variable(named_variable_ref) => Some(named_variable_ref.0.clone()), |  | ||||||
|         mir::ExprKind::Indexed(value, type_kind, index_expr) => Some( |  | ||||||
|             find_type_in_expr(&value, module_id, token_idx) |  | ||||||
|                 .or(find_type_in_expr(&index_expr, module_id, token_idx)) |  | ||||||
|                 .unwrap_or(type_kind.clone()), |  | ||||||
|         ), |  | ||||||
|         mir::ExprKind::Accessed(expression, type_kind, _, meta) => { |  | ||||||
|             if meta.contains(token_idx) { |  | ||||||
|                 Some(type_kind.clone()) |  | ||||||
|             } else { |  | ||||||
|                 find_type_in_expr(&expression, module_id, token_idx) |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         mir::ExprKind::Array(expressions) => { |  | ||||||
|             for expr in expressions { |  | ||||||
|                 if let Some(ty) = find_type_in_expr(expr, module_id, token_idx) { |  | ||||||
|                     return Some(ty); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             None |  | ||||||
|         } |  | ||||||
|         mir::ExprKind::Struct(name, items) => { |  | ||||||
|             for (_, expr, meta) in items { |  | ||||||
|                 if meta.contains(token_idx) { |  | ||||||
|                     return expr.return_type(&Default::default(), module_id).map(|(_, t)| t).ok(); |  | ||||||
|                 } |  | ||||||
|                 if let Some(ty) = find_type_in_expr(expr, module_id, token_idx) { |  | ||||||
|                     return Some(ty); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             Some(TypeKind::CustomType(mir::CustomTypeKey(name.clone(), module_id))) |  | ||||||
|         } |  | ||||||
|         mir::ExprKind::Literal(literal) => Some(literal.as_type()), |  | ||||||
|         mir::ExprKind::BinOp(_, lhs, rhs, type_kind) => { |  | ||||||
|             if let Some(ty) = find_type_in_expr(lhs, module_id, token_idx) { |  | ||||||
|                 return Some(ty); |  | ||||||
|             } |  | ||||||
|             if let Some(ty) = find_type_in_expr(rhs, module_id, token_idx) { |  | ||||||
|                 return Some(ty); |  | ||||||
|             } |  | ||||||
|             Some(type_kind.clone()) |  | ||||||
|         } |  | ||||||
|         mir::ExprKind::FunctionCall(FunctionCall { |  | ||||||
|             return_type, |  | ||||||
|             parameters, |  | ||||||
|             .. |  | ||||||
|         }) => { |  | ||||||
|             for expr in parameters { |  | ||||||
|                 if let Some(ty) = find_type_in_expr(expr, module_id, token_idx) { |  | ||||||
|                     return Some(ty); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             Some(return_type.clone()) |  | ||||||
|         } |  | ||||||
|         mir::ExprKind::AssociatedFunctionCall( |  | ||||||
|             _, |  | ||||||
|             FunctionCall { |  | ||||||
|                 return_type, |  | ||||||
|                 parameters, |  | ||||||
|                 .. |  | ||||||
|             }, |  | ||||||
|         ) => { |  | ||||||
|             for expr in parameters { |  | ||||||
|                 if let Some(ty) = find_type_in_expr(expr, module_id, token_idx) { |  | ||||||
|                     return Some(ty); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             Some(return_type.clone()) |  | ||||||
|         } |  | ||||||
|         mir::ExprKind::If(IfExpression(cond, then_e, else_e)) => find_type_in_expr(&cond, module_id, token_idx) |  | ||||||
|             .or(find_type_in_expr(&then_e, module_id, token_idx)) |  | ||||||
|             .or(else_e.clone().and_then(|e| find_type_in_expr(&e, module_id, token_idx))), |  | ||||||
|         mir::ExprKind::Block(block) => find_type_in_block(block, module_id, token_idx), |  | ||||||
|         mir::ExprKind::Borrow(expression, mutable) => { |  | ||||||
|             if let Some(ty) = find_type_in_expr(&expression, module_id, token_idx) { |  | ||||||
|                 return Some(ty); |  | ||||||
|             } |  | ||||||
|             if let Ok(inner) = expression.return_type(&Default::default(), module_id).map(|(_, ty)| ty) { |  | ||||||
|                 Some(TypeKind::Borrow(Box::new(inner.clone()), *mutable)) |  | ||||||
|             } else { |  | ||||||
|                 None |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         mir::ExprKind::Deref(expression) => { |  | ||||||
|             if let Some(ty) = find_type_in_expr(&expression, module_id, token_idx) { |  | ||||||
|                 return Some(ty); |  | ||||||
|             } |  | ||||||
|             if let Ok(TypeKind::Borrow(inner, _)) = |  | ||||||
|                 expression.return_type(&Default::default(), module_id).map(|(_, ty)| ty) |  | ||||||
|             { |  | ||||||
|                 Some(*inner.clone()) |  | ||||||
|             } else { |  | ||||||
|                 Some(TypeKind::CustomType(mir::CustomTypeKey( |  | ||||||
|                     "ä".to_owned(), |  | ||||||
|                     SourceModuleId(1), |  | ||||||
|                 ))) |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         mir::ExprKind::CastTo(expression, type_kind) => { |  | ||||||
|             Some(find_type_in_expr(&expression, module_id, token_idx).unwrap_or(type_kind.clone())) |  | ||||||
|         } |  | ||||||
|         mir::ExprKind::GlobalRef(_, type_kind) => Some(type_kind.clone()), |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | |||||||
| @ -610,7 +610,7 @@ impl Parse for LetStatement { | |||||||
|             stream.expect(Token::Equals)?; |             stream.expect(Token::Equals)?; | ||||||
| 
 | 
 | ||||||
|             let expression = stream.parse()?; |             let expression = stream.parse()?; | ||||||
|             stream.expect(Token::Semi)?; |             stream.expect_nonfatal(Token::Semi); | ||||||
|             Ok(LetStatement { |             Ok(LetStatement { | ||||||
|                 name: variable, |                 name: variable, | ||||||
|                 ty, |                 ty, | ||||||
| @ -643,7 +643,7 @@ impl Parse for ImportStatement { | |||||||
|             Err(stream.expected_err("identifier")?)? |             Err(stream.expected_err("identifier")?)? | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         stream.expect(Token::Semi)?; |         stream.expect_nonfatal(Token::Semi); | ||||||
| 
 | 
 | ||||||
|         Ok(ImportStatement(import_list, stream.get_range().unwrap())) |         Ok(ImportStatement(import_list, stream.get_range().unwrap())) | ||||||
|     } |     } | ||||||
| @ -788,7 +788,7 @@ impl Parse for Block { | |||||||
|                 // if semicolon is missing.
 |                 // if semicolon is missing.
 | ||||||
|                 if !matches!(e, Expression(ExpressionKind::IfExpr(_), _)) { |                 if !matches!(e, Expression(ExpressionKind::IfExpr(_), _)) { | ||||||
|                     // In theory could ignore the missing semicolon..
 |                     // In theory could ignore the missing semicolon..
 | ||||||
|                     return Err(stream.expected_err("semicolon to complete statement")?); |                     stream.expected_err_nonfatal("semicolon to complete statement"); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 statements.push(BlockLevelStatement::Expression(e)); |                 statements.push(BlockLevelStatement::Expression(e)); | ||||||
| @ -997,7 +997,7 @@ impl Parse for SetStatement { | |||||||
|         let var_ref = stream.parse()?; |         let var_ref = stream.parse()?; | ||||||
|         stream.expect(Token::Equals)?; |         stream.expect(Token::Equals)?; | ||||||
|         let expr = stream.parse()?; |         let expr = stream.parse()?; | ||||||
|         stream.expect(Token::Semi)?; |         stream.expect_nonfatal(Token::Semi); | ||||||
|         Ok(SetStatement(var_ref, expr, stream.get_range().unwrap())) |         Ok(SetStatement(var_ref, expr, stream.get_range().unwrap())) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -1038,7 +1038,7 @@ impl Parse for TopLevelStatement { | |||||||
|                 stream.next(); // Consume Extern
 |                 stream.next(); // Consume Extern
 | ||||||
|                 stream.expect(Token::FnKeyword)?; |                 stream.expect(Token::FnKeyword)?; | ||||||
|                 let extern_fn = Stmt::ExternFunction(stream.parse()?); |                 let extern_fn = Stmt::ExternFunction(stream.parse()?); | ||||||
|                 stream.expect(Token::Semi)?; |                 stream.expect_nonfatal(Token::Semi); | ||||||
|                 extern_fn |                 extern_fn | ||||||
|             } |             } | ||||||
|             Some(Token::FnKeyword) | Some(Token::PubKeyword) => Stmt::FunctionDefinition(stream.parse()?), |             Some(Token::FnKeyword) | Some(Token::PubKeyword) => Stmt::FunctionDefinition(stream.parse()?), | ||||||
|  | |||||||
| @ -1,6 +1,8 @@ | |||||||
| //! Contains relevant code for parsing tokens received from
 | //! Contains relevant code for parsing tokens received from
 | ||||||
| //! Lexing/Tokenizing-stage.
 | //! Lexing/Tokenizing-stage.
 | ||||||
| 
 | 
 | ||||||
|  | use std::{cell::RefCell, rc::Rc}; | ||||||
|  | 
 | ||||||
| use crate::{ | use crate::{ | ||||||
|     ast::parse::Parse, |     ast::parse::Parse, | ||||||
|     lexer::{FullToken, Token}, |     lexer::{FullToken, Token}, | ||||||
| @ -12,6 +14,7 @@ use crate::{ | |||||||
| pub struct TokenStream<'a, 'b> { | pub struct TokenStream<'a, 'b> { | ||||||
|     ref_position: Option<&'b mut usize>, |     ref_position: Option<&'b mut usize>, | ||||||
|     tokens: &'a [FullToken], |     tokens: &'a [FullToken], | ||||||
|  |     errors: Rc<RefCell<Vec<Error>>>, | ||||||
|     pub position: usize, |     pub position: usize, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -20,6 +23,7 @@ impl<'a, 'b> TokenStream<'a, 'b> { | |||||||
|         TokenStream { |         TokenStream { | ||||||
|             ref_position: None, |             ref_position: None, | ||||||
|             tokens, |             tokens, | ||||||
|  |             errors: Rc::new(RefCell::new(Vec::new())), | ||||||
|             position: 0, |             position: 0, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @ -38,6 +42,16 @@ impl<'a, 'b> TokenStream<'a, 'b> { | |||||||
|         )) |         )) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /// Returns expected-error for the next token in-line. Useful in conjunction
 | ||||||
|  |     /// with [`TokenStream::peek`]
 | ||||||
|  |     pub fn expected_err_nonfatal<T: Into<String>>(&mut self, expected: T) { | ||||||
|  |         let err = match self.expected_err(expected) { | ||||||
|  |             Ok(e) => e, | ||||||
|  |             Err(e) => e, | ||||||
|  |         }; | ||||||
|  |         self.errors.borrow_mut().push(err); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     /// Returns expected-error for the previous token that was already consumed.
 |     /// Returns expected-error for the previous token that was already consumed.
 | ||||||
|     /// Useful in conjunction with [`TokenStream::next`]
 |     /// Useful in conjunction with [`TokenStream::next`]
 | ||||||
|     pub fn expecting_err<T: Into<String>>(&mut self, expected: T) -> Result<Error, Error> { |     pub fn expecting_err<T: Into<String>>(&mut self, expected: T) -> Result<Error, Error> { | ||||||
| @ -50,6 +64,16 @@ impl<'a, 'b> TokenStream<'a, 'b> { | |||||||
|         )) |         )) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /// Returns expected-error for the previous token that was already consumed.
 | ||||||
|  |     /// Useful in conjunction with [`TokenStream::next`]
 | ||||||
|  |     pub fn expecting_err_nonfatal<T: Into<String>>(&mut self, expected: T) { | ||||||
|  |         let err = match self.expecting_err(expected) { | ||||||
|  |             Ok(e) => e, | ||||||
|  |             Err(e) => e, | ||||||
|  |         }; | ||||||
|  |         self.errors.borrow_mut().push(err); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     pub fn expect(&mut self, token: Token) -> Result<(), Error> { |     pub fn expect(&mut self, token: Token) -> Result<(), Error> { | ||||||
|         if let (pos, Some(peeked)) = self.next_token(self.position) { |         if let (pos, Some(peeked)) = self.next_token(self.position) { | ||||||
|             if token == peeked.token { |             if token == peeked.token { | ||||||
| @ -63,6 +87,18 @@ impl<'a, 'b> TokenStream<'a, 'b> { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     pub fn expect_nonfatal(&mut self, token: Token) { | ||||||
|  |         if let (pos, Some(peeked)) = self.next_token(self.position) { | ||||||
|  |             if token == peeked.token { | ||||||
|  |                 self.position = pos + 1; | ||||||
|  |             } else { | ||||||
|  |                 self.expecting_err_nonfatal(token); | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             self.expecting_err_nonfatal(token); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     pub fn next(&mut self) -> Option<Token> { |     pub fn next(&mut self) -> Option<Token> { | ||||||
|         let (position, token) = self.next_token(self.position); |         let (position, token) = self.next_token(self.position); | ||||||
|         self.position = position + 1; |         self.position = position + 1; | ||||||
| @ -147,6 +183,7 @@ impl<'a, 'b> TokenStream<'a, 'b> { | |||||||
|         let clone = TokenStream { |         let clone = TokenStream { | ||||||
|             ref_position: Some(&mut ref_pos), |             ref_position: Some(&mut ref_pos), | ||||||
|             tokens: self.tokens, |             tokens: self.tokens, | ||||||
|  |             errors: self.errors.clone(), | ||||||
|             position, |             position, | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
| @ -197,6 +234,10 @@ impl<'a, 'b> TokenStream<'a, 'b> { | |||||||
|         } |         } | ||||||
|         (from, self.tokens.get(from)) |         (from, self.tokens.get(from)) | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     pub fn errors(&self) -> Vec<Error> { | ||||||
|  |         self.errors.borrow().clone().clone() | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl Drop for TokenStream<'_, '_> { | impl Drop for TokenStream<'_, '_> { | ||||||
|  | |||||||
| @ -1326,8 +1326,6 @@ impl mir::Expression { | |||||||
|                         (val.1.clone(), type_kind.clone()) |                         (val.1.clone(), type_kind.clone()) | ||||||
|                     }; |                     }; | ||||||
| 
 | 
 | ||||||
|                     dbg!(&ty, type_kind); |  | ||||||
| 
 |  | ||||||
|                     match (&ty, type_kind) { |                     match (&ty, type_kind) { | ||||||
|                         (TypeKind::UserPtr(_), TypeKind::UserPtr(_)) => Some(StackValue( |                         (TypeKind::UserPtr(_), TypeKind::UserPtr(_)) => Some(StackValue( | ||||||
|                             val.0.derive( |                             val.0.derive( | ||||||
|  | |||||||
| @ -105,7 +105,7 @@ pub fn compile_module<'map>( | |||||||
|     map: &'map mut ErrorModules, |     map: &'map mut ErrorModules, | ||||||
|     path: Option<PathBuf>, |     path: Option<PathBuf>, | ||||||
|     is_main: bool, |     is_main: bool, | ||||||
| ) -> Result<mir::Module, ReidError> { | ) -> Result<Result<mir::Module, (ast::Module, ReidError)>, ReidError> { | ||||||
|     let module = map.module(&module_id).cloned().unwrap(); |     let module = map.module(&module_id).cloned().unwrap(); | ||||||
| 
 | 
 | ||||||
|     let mut token_stream = TokenStream::from(&tokens); |     let mut token_stream = TokenStream::from(&tokens); | ||||||
| @ -117,6 +117,8 @@ pub fn compile_module<'map>( | |||||||
|         statements.push(statement); |         statements.push(statement); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     let errors = token_stream.errors(); | ||||||
|  | 
 | ||||||
|     drop(token_stream); |     drop(token_stream); | ||||||
| 
 | 
 | ||||||
|     let ast_module = ast::Module { |     let ast_module = ast::Module { | ||||||
| @ -127,11 +129,33 @@ pub fn compile_module<'map>( | |||||||
|         is_main, |         is_main, | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|  |     if errors.len() > 0 { | ||||||
|  |         return Ok(Err(( | ||||||
|  |             ast_module, | ||||||
|  |             ReidError::from_kind( | ||||||
|  |                 errors | ||||||
|  |                     .into_iter() | ||||||
|  |                     .map(|e| { | ||||||
|  |                         error_raporting::ErrorKind::from(mir::pass::Error { | ||||||
|  |                             metadata: mir::Metadata { | ||||||
|  |                                 source_module_id: module_id, | ||||||
|  |                                 range: *e.get_range().unwrap_or(&Default::default()), | ||||||
|  |                                 position: None, | ||||||
|  |                             }, | ||||||
|  |                             kind: e, | ||||||
|  |                         }) | ||||||
|  |                     }) | ||||||
|  |                     .collect(), | ||||||
|  |                 map.clone(), | ||||||
|  |             ), | ||||||
|  |         ))); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     #[cfg(debug_assertions)] |     #[cfg(debug_assertions)] | ||||||
|     #[cfg(feature = "log_output")] |     #[cfg(feature = "log_output")] | ||||||
|     dbg!(&ast_module); |     dbg!(&ast_module); | ||||||
| 
 | 
 | ||||||
|     Ok(ast_module.process(module_id)) |     Ok(Ok(ast_module.process(module_id))) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn perform_all_passes<'map>( | pub fn perform_all_passes<'map>( | ||||||
| @ -293,7 +317,7 @@ pub fn compile_and_pass<'map>( | |||||||
|     let name = path.file_name().unwrap().to_str().unwrap().to_owned(); |     let name = path.file_name().unwrap().to_str().unwrap().to_owned(); | ||||||
| 
 | 
 | ||||||
|     let (id, tokens) = parse_module(source, name, module_map)?; |     let (id, tokens) = parse_module(source, name, module_map)?; | ||||||
|     let module = compile_module(id, tokens, module_map, Some(path.clone()), true)?; |     let module = compile_module(id, tokens, module_map, Some(path.clone()), true)?.map_err(|(_, e)| e)?; | ||||||
| 
 | 
 | ||||||
|     let mut mir_context = mir::Context::from(vec![module], path.parent().unwrap().to_owned()); |     let mut mir_context = mir::Context::from(vec![module], path.parent().unwrap().to_owned()); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -52,7 +52,7 @@ pub enum ErrorKind { | |||||||
| 
 | 
 | ||||||
| pub fn compile_std(module_map: &mut ErrorModules) -> Result<Module, ReidError> { | pub fn compile_std(module_map: &mut ErrorModules) -> Result<Module, ReidError> { | ||||||
|     let (id, tokens) = parse_module(STD_SOURCE, STD_NAME, module_map)?; |     let (id, tokens) = parse_module(STD_SOURCE, STD_NAME, module_map)?; | ||||||
|     let module = compile_module(id, tokens, module_map, None, false)?; |     let module = compile_module(id, tokens, module_map, None, false)?.map_err(|(_, e)| e)?; | ||||||
| 
 | 
 | ||||||
|     let module_id = module.module_id; |     let module_id = module.module_id; | ||||||
|     let mut mir_context = super::Context::from(vec![module], Default::default()); |     let mut mir_context = super::Context::from(vec![module], Default::default()); | ||||||
| @ -156,21 +156,33 @@ impl<'map> Pass for LinkerPass<'map> { | |||||||
|                     }; |                     }; | ||||||
| 
 | 
 | ||||||
|                     match compile_module(id, tokens, &mut self.module_map, Some(file_path), false) { |                     match compile_module(id, tokens, &mut self.module_map, Some(file_path), false) { | ||||||
|                         Ok(imported_module) => { |                         Ok(res) => match res { | ||||||
|                             if imported_module.is_main { |                             Ok(imported_module) => { | ||||||
|  |                                 if imported_module.is_main { | ||||||
|  |                                     state.ok::<_, Infallible>( | ||||||
|  |                                         Err(ErrorKind::TriedLinkingMain(module_name.clone())), | ||||||
|  |                                         import.1, | ||||||
|  |                                     ); | ||||||
|  |                                     continue; | ||||||
|  |                                 } | ||||||
|  |                                 let module_id = imported_module.module_id; | ||||||
|  |                                 module_ids.insert(imported_module.name.clone(), imported_module.module_id); | ||||||
|  |                                 modules.insert(module_id, Rc::new(RefCell::new(imported_module))); | ||||||
|  |                                 let imported = modules.get_mut(&module_id).unwrap(); | ||||||
|  |                                 modules_to_process.push(imported.clone()); | ||||||
|  |                                 imported | ||||||
|  |                             } | ||||||
|  |                             Err((_, err)) => { | ||||||
|                                 state.ok::<_, Infallible>( |                                 state.ok::<_, Infallible>( | ||||||
|                                     Err(ErrorKind::TriedLinkingMain(module_name.clone())), |                                     Err(ErrorKind::ModuleCompilationError( | ||||||
|  |                                         module_name.clone(), | ||||||
|  |                                         format!("{}", err), | ||||||
|  |                                     )), | ||||||
|                                     import.1, |                                     import.1, | ||||||
|                                 ); |                                 ); | ||||||
|                                 continue; |                                 continue; | ||||||
|                             } |                             } | ||||||
|                             let module_id = imported_module.module_id; |                         }, | ||||||
|                             module_ids.insert(imported_module.name.clone(), imported_module.module_id); |  | ||||||
|                             modules.insert(module_id, Rc::new(RefCell::new(imported_module))); |  | ||||||
|                             let imported = modules.get_mut(&module_id).unwrap(); |  | ||||||
|                             modules_to_process.push(imported.clone()); |  | ||||||
|                             imported |  | ||||||
|                         } |  | ||||||
|                         Err(err) => { |                         Err(err) => { | ||||||
|                             state.ok::<_, Infallible>( |                             state.ok::<_, Infallible>( | ||||||
|                                 Err(ErrorKind::ModuleCompilationError( |                                 Err(ErrorKind::ModuleCompilationError( | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ fn test_compile(source: &str, name: &str) -> CompileOutput { | |||||||
|         let mut map = Default::default(); |         let mut map = Default::default(); | ||||||
|         let (id, tokens) = assert_err(parse_module(source, name, &mut map)); |         let (id, tokens) = assert_err(parse_module(source, name, &mut map)); | ||||||
| 
 | 
 | ||||||
|         let module = assert_err(compile_module(id, tokens, &mut map, None, true)); |         let module = assert_err(assert_err(compile_module(id, tokens, &mut map, None, true)).map_err(|(_, e)| e)); | ||||||
|         let mut mir_context = mir::Context::from(vec![module], Default::default()); |         let mut mir_context = mir::Context::from(vec![module], Default::default()); | ||||||
|         assert_err(perform_all_passes(&mut mir_context, &mut map)); |         assert_err(perform_all_passes(&mut mir_context, &mut map)); | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user