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,13 +100,12 @@ 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(),
|
||||||
@ -111,7 +113,6 @@ pub fn set_autocomplete(map: &mut TokenAnalysisMap, meta: &mir::Metadata, autoco
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
||||||
let mut map = HashMap::new();
|
let mut map = HashMap::new();
|
||||||
@ -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> {
|
||||||
|
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> {
|
||||||
|
Loading…
Reference in New Issue
Block a user