Add autocomplete for associated functions and struct fields
This commit is contained in:
		
							parent
							
								
									bb9f69ee53
								
							
						
					
					
						commit
						4ea0913842
					
				| @ -21,7 +21,5 @@ fn main() -> u32 { | |||||||
| 
 | 
 | ||||||
|     let mut a = &mut value; |     let mut a = &mut value; | ||||||
| 
 | 
 | ||||||
|     *a.second[2] = 5; |     return *a.second[0]; | ||||||
| 
 |  | ||||||
|     return *a.second[2]; |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -36,6 +36,7 @@ export function activate(context: ExtensionContext) { | |||||||
| 			env: { | 			env: { | ||||||
| 				...process.env, | 				...process.env, | ||||||
| 				RUST_LOG: "debug", | 				RUST_LOG: "debug", | ||||||
|  | 				RUST_BACKTRACE: 1, | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	}; | 	}; | ||||||
|  | |||||||
| @ -1,11 +1,12 @@ | |||||||
| use std::{collections::HashMap, fmt::format, path::PathBuf}; | use std::{collections::HashMap, fmt::format, path::PathBuf}; | ||||||
| 
 | 
 | ||||||
| use reid::{ | use reid::{ | ||||||
|     ast::{self, FunctionDefinition, lexer::FullToken}, |     ast::{self, FunctionDefinition, lexer::FullToken, token_stream::TokenRange}, | ||||||
|     compile_module, |     compile_module, | ||||||
|     error_raporting::{ErrorModules, ReidError}, |     error_raporting::{ErrorModules, ReidError}, | ||||||
|     mir::{ |     mir::{ | ||||||
|         self, Context, FunctionCall, FunctionParam, IfExpression, SourceModuleId, StructType, TypeKind, WhileStatement, |         self, Context, FunctionCall, FunctionParam, IfExpression, SourceModuleId, StructType, TypeKind, WhileStatement, | ||||||
|  |         typecheck::typerefs::TypeRefs, | ||||||
|     }, |     }, | ||||||
|     perform_all_passes, |     perform_all_passes, | ||||||
| }; | }; | ||||||
| @ -34,6 +35,7 @@ pub struct Autocomplete { | |||||||
| #[derive(Debug, Clone)] | #[derive(Debug, Clone)] | ||||||
| pub enum AutocompleteKind { | pub enum AutocompleteKind { | ||||||
|     Type, |     Type, | ||||||
|  |     Field(TypeKind), | ||||||
|     Function(Vec<FunctionParam>, TypeKind), |     Function(Vec<FunctionParam>, TypeKind), | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -48,6 +50,7 @@ impl ToString for AutocompleteKind { | |||||||
|                     .collect::<Vec<_>>(); |                     .collect::<Vec<_>>(); | ||||||
|                 format!("({}) -> {}", params.join(", "), ret_ty) |                 format!("({}) -> {}", params.join(", "), ret_ty) | ||||||
|             } |             } | ||||||
|  |             AutocompleteKind::Field(type_kind) => format!("{}", type_kind), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -97,19 +100,17 @@ pub fn init_types(map: &mut TokenAnalysisMap, meta: &mir::Metadata, ty: Option<T | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn set_autocomplete(map: &mut TokenAnalysisMap, meta: &mir::Metadata, autocomplete: Vec<Autocomplete>) { | pub fn set_autocomplete(map: &mut TokenAnalysisMap, token_idx: usize, autocomplete: Vec<Autocomplete>) { | ||||||
|     for token in meta.range.start..=meta.range.end { |     if let Some(token) = map.get_mut(&token_idx) { | ||||||
|         if let Some(token) = map.get_mut(&token) { |         token.autocomplete = autocomplete.clone(); | ||||||
|             token.autocomplete = autocomplete.clone(); |     } else { | ||||||
|         } else { |         map.insert( | ||||||
|             map.insert( |             token_idx, | ||||||
|                 token, |             SemanticAnalysis { | ||||||
|                 SemanticAnalysis { |                 ty: None, | ||||||
|                     ty: None, |                 autocomplete: autocomplete.clone(), | ||||||
|                     autocomplete: autocomplete.clone(), |             }, | ||||||
|                 }, |         ); | ||||||
|             ); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -152,8 +153,7 @@ pub fn analyze_context(context: &mir::Context, module: &mir::Module, error: Opti | |||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             dbg!(import_meta, &autocompletes); |             set_autocomplete(&mut map, import_meta.range.end, autocompletes); | ||||||
|             set_autocomplete(&mut map, &import_meta, autocompletes); |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -219,7 +219,7 @@ pub fn analyze_block( | |||||||
|                     map, |                     map, | ||||||
|                     &named_variable_ref.2, |                     &named_variable_ref.2, | ||||||
|                     expression |                     expression | ||||||
|                         .return_type(&Default::default(), source_module.module_id) |                         .return_type(&TypeRefs::unknown(), source_module.module_id) | ||||||
|                         .ok() |                         .ok() | ||||||
|                         .map(|(_, ty)| ty), |                         .map(|(_, ty)| ty), | ||||||
|                 ); |                 ); | ||||||
| @ -254,7 +254,7 @@ pub fn analyze_expr( | |||||||
|     init_types( |     init_types( | ||||||
|         map, |         map, | ||||||
|         &expr.1, |         &expr.1, | ||||||
|         expr.return_type(&Default::default(), source_module.module_id) |         expr.return_type(&TypeRefs::unknown(), source_module.module_id) | ||||||
|             .ok() |             .ok() | ||||||
|             .map(|(_, t)| t), |             .map(|(_, t)| t), | ||||||
|     ); |     ); | ||||||
| @ -265,8 +265,48 @@ pub fn analyze_expr( | |||||||
|             analyze_expr(context, source_module, &value, map); |             analyze_expr(context, source_module, &value, map); | ||||||
|             analyze_expr(context, source_module, &index_expr, map); |             analyze_expr(context, source_module, &index_expr, map); | ||||||
|         } |         } | ||||||
|         mir::ExprKind::Accessed(expression, ..) => { |         mir::ExprKind::Accessed(expression, _, name, meta) => { | ||||||
|             analyze_expr(context, source_module, &expression, map); |             analyze_expr(context, source_module, &expression, map); | ||||||
|  | 
 | ||||||
|  |             let accessed_type = expression.return_type(&TypeRefs::unknown(), source_module.module_id); | ||||||
|  | 
 | ||||||
|  |             let mut autocompletes = Vec::new(); | ||||||
|  |             match accessed_type { | ||||||
|  |                 Ok((_, accessed_type)) => { | ||||||
|  |                     autocompletes.extend( | ||||||
|  |                         source_module | ||||||
|  |                             .associated_functions | ||||||
|  |                             .iter() | ||||||
|  |                             .filter(|(t, fun)| *t == accessed_type && fun.name.starts_with(name)) | ||||||
|  |                             .map(|(_, fun)| Autocomplete { | ||||||
|  |                                 text: fun.name.clone(), | ||||||
|  |                                 kind: AutocompleteKind::Function(fun.parameters.clone(), fun.return_type.clone()), | ||||||
|  |                             }), | ||||||
|  |                     ); | ||||||
|  |                     match accessed_type { | ||||||
|  |                         TypeKind::CustomType(ty_key) => { | ||||||
|  |                             let typedef = source_module | ||||||
|  |                                 .typedefs | ||||||
|  |                                 .iter() | ||||||
|  |                                 .find(|t| t.name == ty_key.0 && t.source_module == ty_key.1); | ||||||
|  |                             if let Some(typedef) = typedef { | ||||||
|  |                                 autocompletes.extend(match &typedef.kind { | ||||||
|  |                                     mir::TypeDefinitionKind::Struct(StructType(fields)) => { | ||||||
|  |                                         fields.iter().filter(|f| f.0.starts_with(name)).map(|f| Autocomplete { | ||||||
|  |                                             text: f.0.clone(), | ||||||
|  |                                             kind: AutocompleteKind::Field(f.1.clone()), | ||||||
|  |                                         }) | ||||||
|  |                                     } | ||||||
|  |                                 }); | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  |                         _ => {} | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 _ => {} | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             set_autocomplete(map, meta.range.end - 1, autocompletes); | ||||||
|         } |         } | ||||||
|         mir::ExprKind::Array(expressions) => { |         mir::ExprKind::Array(expressions) => { | ||||||
|             for expr in expressions { |             for expr in expressions { | ||||||
| @ -288,10 +328,25 @@ pub fn analyze_expr( | |||||||
|                 analyze_expr(context, source_module, expr, map); |                 analyze_expr(context, source_module, expr, map); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         mir::ExprKind::AssociatedFunctionCall(_, FunctionCall { parameters, .. }) => { |         mir::ExprKind::AssociatedFunctionCall( | ||||||
|  |             ty, | ||||||
|  |             FunctionCall { | ||||||
|  |                 parameters, name, meta, .. | ||||||
|  |             }, | ||||||
|  |         ) => { | ||||||
|             for expr in parameters { |             for expr in parameters { | ||||||
|                 analyze_expr(context, source_module, expr, map); |                 analyze_expr(context, source_module, expr, map); | ||||||
|             } |             } | ||||||
|  |             let function_autocomplete = source_module | ||||||
|  |                 .associated_functions | ||||||
|  |                 .iter() | ||||||
|  |                 .filter(|(t, fun)| t == ty && fun.name.starts_with(name)) | ||||||
|  |                 .map(|(_, fun)| Autocomplete { | ||||||
|  |                     text: fun.name.clone(), | ||||||
|  |                     kind: AutocompleteKind::Function(fun.parameters.clone(), fun.return_type.clone()), | ||||||
|  |                 }) | ||||||
|  |                 .collect::<Vec<_>>(); | ||||||
|  |             set_autocomplete(map, meta.range.end, function_autocomplete); | ||||||
|         } |         } | ||||||
|         mir::ExprKind::If(IfExpression(cond, then_e, else_e)) => { |         mir::ExprKind::If(IfExpression(cond, then_e, else_e)) => { | ||||||
|             analyze_expr(context, source_module, &cond, map); |             analyze_expr(context, source_module, &cond, map); | ||||||
|  | |||||||
| @ -175,7 +175,36 @@ impl Parse for AssociatedFunctionCall { | |||||||
|         let ty = stream.parse()?; |         let ty = stream.parse()?; | ||||||
|         stream.expect(Token::Colon)?; |         stream.expect(Token::Colon)?; | ||||||
|         stream.expect(Token::Colon)?; |         stream.expect(Token::Colon)?; | ||||||
|         Ok(AssociatedFunctionCall(ty, stream.parse()?)) |         match stream.parse() { | ||||||
|  |             Ok(fn_call) => Ok(AssociatedFunctionCall(ty, fn_call)), | ||||||
|  |             _ => { | ||||||
|  |                 if let Some(Token::Identifier(fn_name)) = stream.peek() { | ||||||
|  |                     stream.next(); | ||||||
|  |                     stream.expected_err_nonfatal("associated function call"); | ||||||
|  | 
 | ||||||
|  |                     Ok(AssociatedFunctionCall( | ||||||
|  |                         ty, | ||||||
|  |                         FunctionCallExpression { | ||||||
|  |                             name: fn_name, | ||||||
|  |                             params: Vec::new(), | ||||||
|  |                             range: stream.get_range_prev_single().unwrap(), | ||||||
|  |                             is_macro: false, | ||||||
|  |                         }, | ||||||
|  |                     )) | ||||||
|  |                 } else { | ||||||
|  |                     stream.expected_err_nonfatal("associated function name"); | ||||||
|  |                     Ok(AssociatedFunctionCall( | ||||||
|  |                         ty, | ||||||
|  |                         FunctionCallExpression { | ||||||
|  |                             name: String::new(), | ||||||
|  |                             params: Vec::new(), | ||||||
|  |                             range: stream.get_range_prev_single().unwrap(), | ||||||
|  |                             is_macro: false, | ||||||
|  |                         }, | ||||||
|  |                     )) | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -610,7 +639,7 @@ impl Parse for LetStatement { | |||||||
|             stream.expect(Token::Equals)?; |             stream.expect(Token::Equals)?; | ||||||
| 
 | 
 | ||||||
|             let expression = stream.parse()?; |             let expression = stream.parse()?; | ||||||
|             stream.expect_nonfatal(Token::Semi); |             stream.expect_nonfatal(Token::Semi).ok(); | ||||||
|             Ok(LetStatement { |             Ok(LetStatement { | ||||||
|                 name: variable, |                 name: variable, | ||||||
|                 ty, |                 ty, | ||||||
| @ -645,7 +674,7 @@ impl Parse for ImportStatement { | |||||||
|             Err(stream.expected_err("identifier")?)? |             Err(stream.expected_err("identifier")?)? | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         stream.expect_nonfatal(Token::Semi); |         stream.expect_nonfatal(Token::Semi).ok(); | ||||||
| 
 | 
 | ||||||
|         Ok(ImportStatement(import_list, stream.get_range().unwrap())) |         Ok(ImportStatement(import_list, stream.get_range().unwrap())) | ||||||
|     } |     } | ||||||
| @ -934,7 +963,7 @@ impl Parse for BlockLevelStatement { | |||||||
|             Some(Token::ReturnKeyword) => { |             Some(Token::ReturnKeyword) => { | ||||||
|                 stream.next(); |                 stream.next(); | ||||||
|                 let exp = stream.parse().ok(); |                 let exp = stream.parse().ok(); | ||||||
|                 stream.expect(Token::Semi)?; |                 stream.expect_nonfatal(Token::Semi).ok(); | ||||||
|                 Stmt::Return(ReturnType::Hard, exp) |                 Stmt::Return(ReturnType::Hard, exp) | ||||||
|             } |             } | ||||||
|             Some(Token::For) => { |             Some(Token::For) => { | ||||||
| @ -999,7 +1028,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_nonfatal(Token::Semi); |         stream.expect_nonfatal(Token::Semi).ok(); | ||||||
|         Ok(SetStatement(var_ref, expr, stream.get_range().unwrap())) |         Ok(SetStatement(var_ref, expr, stream.get_range().unwrap())) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -1040,7 +1069,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_nonfatal(Token::Semi); |                 stream.expect_nonfatal(Token::Semi).ok(); | ||||||
|                 extern_fn |                 extern_fn | ||||||
|             } |             } | ||||||
|             Some(Token::FnKeyword) | Some(Token::PubKeyword) => Stmt::FunctionDefinition(stream.parse()?), |             Some(Token::FnKeyword) | Some(Token::PubKeyword) => Stmt::FunctionDefinition(stream.parse()?), | ||||||
|  | |||||||
| @ -87,15 +87,18 @@ impl<'a, 'b> TokenStream<'a, 'b> { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn expect_nonfatal(&mut self, token: Token) { |     pub fn expect_nonfatal(&mut self, token: Token) -> Result<(), ()> { | ||||||
|         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 { | ||||||
|                 self.position = pos + 1; |                 self.position = pos + 1; | ||||||
|  |                 Ok(()) | ||||||
|             } else { |             } else { | ||||||
|                 self.expecting_err_nonfatal(token); |                 self.expecting_err_nonfatal(token); | ||||||
|  |                 Err(()) | ||||||
|             } |             } | ||||||
|         } else { |         } else { | ||||||
|             self.expecting_err_nonfatal(token); |             self.expecting_err_nonfatal(token); | ||||||
|  |             Err(()) | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -130,7 +130,7 @@ pub fn compile_module<'map>( | |||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     if errors.len() > 0 { |     if errors.len() > 0 { | ||||||
|         dbg!(&ast_module); |         // dbg!(&ast_module);
 | ||||||
|         return Ok(Err(( |         return Ok(Err(( | ||||||
|             ast_module, |             ast_module, | ||||||
|             ReidError::from_kind( |             ReidError::from_kind( | ||||||
|  | |||||||
| @ -621,7 +621,7 @@ impl Expression { | |||||||
|                         // Update possibly resolved type
 |                         // Update possibly resolved type
 | ||||||
|                         Ok(true_ty) |                         Ok(true_ty) | ||||||
|                     } else { |                     } else { | ||||||
|                         Err(ErrorKind::NoSuchField(field_name.clone())) |                         Err(ErrorKind::NoSuchField(key.0.clone())) | ||||||
|                     } |                     } | ||||||
|                 } else { |                 } else { | ||||||
|                     Err(ErrorKind::TriedAccessingNonStruct(expr_ty)) |                     Err(ErrorKind::TriedAccessingNonStruct(expr_ty)) | ||||||
|  | |||||||
| @ -14,7 +14,7 @@ use crate::{ | |||||||
|     mir::{ |     mir::{ | ||||||
|         pass::{AssociatedFunctionKey, ScopeVariable}, |         pass::{AssociatedFunctionKey, ScopeVariable}, | ||||||
|         BinopDefinition, Block, CustomTypeKey, ExprKind, Expression, FunctionDefinition, FunctionDefinitionKind, |         BinopDefinition, Block, CustomTypeKey, ExprKind, Expression, FunctionDefinition, FunctionDefinitionKind, | ||||||
|         IfExpression, Module, ReturnKind, StmtKind, TypeKind, WhileStatement, |         IfExpression, Module, ReturnKind, StmtKind, TypeKind, VagueType, WhileStatement, | ||||||
|     }, |     }, | ||||||
|     util::try_all, |     util::try_all, | ||||||
| }; | }; | ||||||
| @ -546,10 +546,10 @@ impl Expression { | |||||||
|                                 *type_kind = elem_ty.as_type().clone(); |                                 *type_kind = elem_ty.as_type().clone(); | ||||||
|                                 Ok(elem_ty) |                                 Ok(elem_ty) | ||||||
|                             } |                             } | ||||||
|                             None => Err(ErrorKind::NoSuchField(field_name.clone())), |                             None => Ok(type_refs.from_type(&TypeKind::Vague(VagueType::Unknown)).unwrap()), | ||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
|                     _ => Err(ErrorKind::TriedAccessingNonStruct(kind)), |                     _ => Ok(type_refs.from_type(&TypeKind::Vague(VagueType::Unknown)).unwrap()), | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             ExprKind::Struct(struct_name, fields) => { |             ExprKind::Struct(struct_name, fields) => { | ||||||
|  | |||||||
| @ -97,6 +97,9 @@ pub struct TypeRefs { | |||||||
|     /// Indirect ID-references, referring to hints-vec
 |     /// Indirect ID-references, referring to hints-vec
 | ||||||
|     pub(super) type_refs: RefCell<Vec<TypeIdRef>>, |     pub(super) type_refs: RefCell<Vec<TypeIdRef>>, | ||||||
|     pub(super) binop_types: BinopMap, |     pub(super) binop_types: BinopMap, | ||||||
|  |     /// Used when the real typerefs are not available, and any TypeRefs need to
 | ||||||
|  |     /// be resolved as Unknown.
 | ||||||
|  |     pub unknown_typerefs: bool, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl std::fmt::Display for TypeRefs { | impl std::fmt::Display for TypeRefs { | ||||||
| @ -122,6 +125,14 @@ impl TypeRefs { | |||||||
|             hints: Default::default(), |             hints: Default::default(), | ||||||
|             type_refs: Default::default(), |             type_refs: Default::default(), | ||||||
|             binop_types: binops, |             binop_types: binops, | ||||||
|  |             unknown_typerefs: false, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn unknown() -> TypeRefs { | ||||||
|  |         TypeRefs { | ||||||
|  |             unknown_typerefs: true, | ||||||
|  |             ..Default::default() | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -177,8 +188,12 @@ impl TypeRefs { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn retrieve_typeref(&self, idx: usize) -> Option<TypeRefKind> { |     pub fn retrieve_typeref(&self, idx: usize) -> Option<TypeRefKind> { | ||||||
|         let inner_idx = unsafe { *self.recurse_type_ref(idx).borrow() }; |         if !self.unknown_typerefs { | ||||||
|         self.hints.borrow().get(inner_idx).cloned() |             let inner_idx = unsafe { *self.recurse_type_ref(idx).borrow() }; | ||||||
|  |             self.hints.borrow().get(inner_idx).cloned() | ||||||
|  |         } else { | ||||||
|  |             Some(TypeRefKind::Direct(TypeKind::Vague(VagueType::Unknown))) | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn retrieve_wide_type(&self, idx: usize, seen: &mut HashSet<usize>) -> Option<TypeKind> { |     pub fn retrieve_wide_type(&self, idx: usize, seen: &mut HashSet<usize>) -> Option<TypeKind> { | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user