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;
|
||||
|
||||
*a.second[2] = 5;
|
||||
|
||||
return *a.second[2];
|
||||
return *a.second[0];
|
||||
}
|
||||
|
@ -36,6 +36,7 @@ export function activate(context: ExtensionContext) {
|
||||
env: {
|
||||
...process.env,
|
||||
RUST_LOG: "debug",
|
||||
RUST_BACKTRACE: 1,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -1,11 +1,12 @@
|
||||
use std::{collections::HashMap, fmt::format, path::PathBuf};
|
||||
|
||||
use reid::{
|
||||
ast::{self, FunctionDefinition, lexer::FullToken},
|
||||
ast::{self, FunctionDefinition, lexer::FullToken, token_stream::TokenRange},
|
||||
compile_module,
|
||||
error_raporting::{ErrorModules, ReidError},
|
||||
mir::{
|
||||
self, Context, FunctionCall, FunctionParam, IfExpression, SourceModuleId, StructType, TypeKind, WhileStatement,
|
||||
typecheck::typerefs::TypeRefs,
|
||||
},
|
||||
perform_all_passes,
|
||||
};
|
||||
@ -34,6 +35,7 @@ pub struct Autocomplete {
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum AutocompleteKind {
|
||||
Type,
|
||||
Field(TypeKind),
|
||||
Function(Vec<FunctionParam>, TypeKind),
|
||||
}
|
||||
|
||||
@ -48,6 +50,7 @@ impl ToString for AutocompleteKind {
|
||||
.collect::<Vec<_>>();
|
||||
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>) {
|
||||
for token in meta.range.start..=meta.range.end {
|
||||
if let Some(token) = map.get_mut(&token) {
|
||||
token.autocomplete = autocomplete.clone();
|
||||
} else {
|
||||
map.insert(
|
||||
token,
|
||||
SemanticAnalysis {
|
||||
ty: None,
|
||||
autocomplete: autocomplete.clone(),
|
||||
},
|
||||
);
|
||||
}
|
||||
pub fn set_autocomplete(map: &mut TokenAnalysisMap, token_idx: usize, autocomplete: Vec<Autocomplete>) {
|
||||
if let Some(token) = map.get_mut(&token_idx) {
|
||||
token.autocomplete = autocomplete.clone();
|
||||
} else {
|
||||
map.insert(
|
||||
token_idx,
|
||||
SemanticAnalysis {
|
||||
ty: None,
|
||||
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, autocompletes);
|
||||
set_autocomplete(&mut map, import_meta.range.end, autocompletes);
|
||||
}
|
||||
}
|
||||
|
||||
@ -219,7 +219,7 @@ pub fn analyze_block(
|
||||
map,
|
||||
&named_variable_ref.2,
|
||||
expression
|
||||
.return_type(&Default::default(), source_module.module_id)
|
||||
.return_type(&TypeRefs::unknown(), source_module.module_id)
|
||||
.ok()
|
||||
.map(|(_, ty)| ty),
|
||||
);
|
||||
@ -254,7 +254,7 @@ pub fn analyze_expr(
|
||||
init_types(
|
||||
map,
|
||||
&expr.1,
|
||||
expr.return_type(&Default::default(), source_module.module_id)
|
||||
expr.return_type(&TypeRefs::unknown(), source_module.module_id)
|
||||
.ok()
|
||||
.map(|(_, t)| t),
|
||||
);
|
||||
@ -265,8 +265,48 @@ pub fn analyze_expr(
|
||||
analyze_expr(context, source_module, &value, 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);
|
||||
|
||||
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) => {
|
||||
for expr in expressions {
|
||||
@ -288,10 +328,25 @@ pub fn analyze_expr(
|
||||
analyze_expr(context, source_module, expr, map);
|
||||
}
|
||||
}
|
||||
mir::ExprKind::AssociatedFunctionCall(_, FunctionCall { parameters, .. }) => {
|
||||
mir::ExprKind::AssociatedFunctionCall(
|
||||
ty,
|
||||
FunctionCall {
|
||||
parameters, name, meta, ..
|
||||
},
|
||||
) => {
|
||||
for expr in parameters {
|
||||
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)) => {
|
||||
analyze_expr(context, source_module, &cond, map);
|
||||
|
@ -175,7 +175,36 @@ impl Parse for AssociatedFunctionCall {
|
||||
let ty = stream.parse()?;
|
||||
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)?;
|
||||
|
||||
let expression = stream.parse()?;
|
||||
stream.expect_nonfatal(Token::Semi);
|
||||
stream.expect_nonfatal(Token::Semi).ok();
|
||||
Ok(LetStatement {
|
||||
name: variable,
|
||||
ty,
|
||||
@ -645,7 +674,7 @@ impl Parse for ImportStatement {
|
||||
Err(stream.expected_err("identifier")?)?
|
||||
}
|
||||
|
||||
stream.expect_nonfatal(Token::Semi);
|
||||
stream.expect_nonfatal(Token::Semi).ok();
|
||||
|
||||
Ok(ImportStatement(import_list, stream.get_range().unwrap()))
|
||||
}
|
||||
@ -934,7 +963,7 @@ impl Parse for BlockLevelStatement {
|
||||
Some(Token::ReturnKeyword) => {
|
||||
stream.next();
|
||||
let exp = stream.parse().ok();
|
||||
stream.expect(Token::Semi)?;
|
||||
stream.expect_nonfatal(Token::Semi).ok();
|
||||
Stmt::Return(ReturnType::Hard, exp)
|
||||
}
|
||||
Some(Token::For) => {
|
||||
@ -999,7 +1028,7 @@ impl Parse for SetStatement {
|
||||
let var_ref = stream.parse()?;
|
||||
stream.expect(Token::Equals)?;
|
||||
let expr = stream.parse()?;
|
||||
stream.expect_nonfatal(Token::Semi);
|
||||
stream.expect_nonfatal(Token::Semi).ok();
|
||||
Ok(SetStatement(var_ref, expr, stream.get_range().unwrap()))
|
||||
}
|
||||
}
|
||||
@ -1040,7 +1069,7 @@ impl Parse for TopLevelStatement {
|
||||
stream.next(); // Consume Extern
|
||||
stream.expect(Token::FnKeyword)?;
|
||||
let extern_fn = Stmt::ExternFunction(stream.parse()?);
|
||||
stream.expect_nonfatal(Token::Semi);
|
||||
stream.expect_nonfatal(Token::Semi).ok();
|
||||
extern_fn
|
||||
}
|
||||
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 token == peeked.token {
|
||||
self.position = pos + 1;
|
||||
Ok(())
|
||||
} else {
|
||||
self.expecting_err_nonfatal(token);
|
||||
Err(())
|
||||
}
|
||||
} else {
|
||||
self.expecting_err_nonfatal(token);
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -130,7 +130,7 @@ pub fn compile_module<'map>(
|
||||
};
|
||||
|
||||
if errors.len() > 0 {
|
||||
dbg!(&ast_module);
|
||||
// dbg!(&ast_module);
|
||||
return Ok(Err((
|
||||
ast_module,
|
||||
ReidError::from_kind(
|
||||
|
@ -621,7 +621,7 @@ impl Expression {
|
||||
// Update possibly resolved type
|
||||
Ok(true_ty)
|
||||
} else {
|
||||
Err(ErrorKind::NoSuchField(field_name.clone()))
|
||||
Err(ErrorKind::NoSuchField(key.0.clone()))
|
||||
}
|
||||
} else {
|
||||
Err(ErrorKind::TriedAccessingNonStruct(expr_ty))
|
||||
|
@ -14,7 +14,7 @@ use crate::{
|
||||
mir::{
|
||||
pass::{AssociatedFunctionKey, ScopeVariable},
|
||||
BinopDefinition, Block, CustomTypeKey, ExprKind, Expression, FunctionDefinition, FunctionDefinitionKind,
|
||||
IfExpression, Module, ReturnKind, StmtKind, TypeKind, WhileStatement,
|
||||
IfExpression, Module, ReturnKind, StmtKind, TypeKind, VagueType, WhileStatement,
|
||||
},
|
||||
util::try_all,
|
||||
};
|
||||
@ -546,10 +546,10 @@ impl Expression {
|
||||
*type_kind = elem_ty.as_type().clone();
|
||||
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) => {
|
||||
|
@ -97,6 +97,9 @@ pub struct TypeRefs {
|
||||
/// Indirect ID-references, referring to hints-vec
|
||||
pub(super) type_refs: RefCell<Vec<TypeIdRef>>,
|
||||
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 {
|
||||
@ -122,6 +125,14 @@ impl TypeRefs {
|
||||
hints: Default::default(),
|
||||
type_refs: Default::default(),
|
||||
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> {
|
||||
let inner_idx = unsafe { *self.recurse_type_ref(idx).borrow() };
|
||||
self.hints.borrow().get(inner_idx).cloned()
|
||||
if !self.unknown_typerefs {
|
||||
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> {
|
||||
|
Loading…
Reference in New Issue
Block a user