Add autocomplete for associated functions and struct fields

This commit is contained in:
Sofia 2025-08-03 00:13:53 +03:00
parent bb9f69ee53
commit 4ea0913842
9 changed files with 138 additions and 37 deletions

View File

@ -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];
} }

View File

@ -36,6 +36,7 @@ export function activate(context: ExtensionContext) {
env: { env: {
...process.env, ...process.env,
RUST_LOG: "debug", RUST_LOG: "debug",
RUST_BACKTRACE: 1,
} }
} }
}; };

View File

@ -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,20 +100,18 @@ 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, token_idx,
SemanticAnalysis { SemanticAnalysis {
ty: None, ty: None,
autocomplete: autocomplete.clone(), autocomplete: autocomplete.clone(),
}, },
); );
} }
}
} }
pub fn analyze_context(context: &mir::Context, module: &mir::Module, error: Option<ReidError>) -> StaticAnalysis { pub fn analyze_context(context: &mir::Context, module: &mir::Module, error: Option<ReidError>) -> StaticAnalysis {
@ -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);

View File

@ -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()?),

View File

@ -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(())
} }
} }

View File

@ -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(

View File

@ -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))

View File

@ -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) => {

View File

@ -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> {
if !self.unknown_typerefs {
let inner_idx = unsafe { *self.recurse_type_ref(idx).borrow() }; let inner_idx = unsafe { *self.recurse_type_ref(idx).borrow() };
self.hints.borrow().get(inner_idx).cloned() 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> {