scoping all working and patterns too

Signed-off-by: faldor20 <eli.jambu@yahoo.com>
This commit is contained in:
Eli Dowling 2023-12-02 12:59:23 +10:00 committed by faldor20
parent 049c0e6358
commit a988ee29ff
No known key found for this signature in database
GPG key ID: F2216079B890CD57
3 changed files with 238 additions and 164 deletions

View file

@ -169,7 +169,7 @@ pub fn walk_decls<V: Visitor>(visitor: &mut V, decls: &Declarations) {
} }
} }
fn walk_decl<V: Visitor>(visitor: &mut V, decl: DeclarationInfo<'_>) { pub fn walk_decl<V: Visitor>(visitor: &mut V, decl: DeclarationInfo<'_>) {
use DeclarationInfo::*; use DeclarationInfo::*;
match decl { match decl {
@ -968,74 +968,3 @@ pub fn find_declaration(symbol: Symbol, decls: &'_ Declarations) -> Option<Found
} }
} }
} }
struct CompletionVisitor<'a, U, T> {
position: Position,
found_decls: Vec<T>,
state: &'a mut U,
processor: fn(&mut U, FoundDeclaration) -> T,
}
impl<T, U> Visitor for CompletionVisitor<'_, U, T> {
fn should_visit(&mut self, region: Region) -> bool {
region.contains_pos(self.position)
}
// fn visit_expr(&mut self, expr: &Expr, region: Region, var: Variable) {
// if region.contains_pos(self.position) {
// // self.region_typ = Some((region, var));
// walk_expr(self, expr, var);
// }
// }
// fn visit_pattern(&mut self, pat: &Pattern, region: Region, opt_var: Option<Variable>) {
// if region.contains_pos(self.position) {
// // if let Some(var) = opt_var {
// // self.region_typ = Some((region, var));
// // }
// walk_pattern(self, pat);
// }
// }
fn visit_decl(&mut self, decl: DeclarationInfo<'_>) {
match decl {
DeclarationInfo::Value { .. }
| DeclarationInfo::Function { .. }
| DeclarationInfo::Destructure { .. } => {
let res = (self.processor)(
self.state,
FoundDeclaration::Decl(unsafe { std::mem::transmute(decl.clone()) }),
);
self.found_decls.push(res);
walk_decl(self, decl);
}
_ => {
walk_decl(self, decl);
}
}
}
fn visit_def(&mut self, def: &Def) {
let res = ((self.processor)(
self.state,
FoundDeclaration::Def(unsafe { std::mem::transmute(def) }),
));
self.found_decls.push(res);
walk_def(self, def);
}
}
pub fn get_completions<'a, U, T>(
position: Position,
decls: &'a Declarations,
state: &mut U,
processor: fn(&mut U, FoundDeclaration) -> T,
) -> Vec<T> {
let mut visitor = CompletionVisitor {
position,
found_decls: Vec::new(),
state,
processor,
};
visitor.visit_decls(decls);
visitor.found_decls
}

View file

@ -5,11 +5,7 @@ use std::{
}; };
use bumpalo::Bump; use bumpalo::Bump;
use roc_can::{ use roc_can::{abilities::AbilitiesStore, expr::Declarations};
abilities::AbilitiesStore,
expr::Declarations,
traverse::{get_completions, DeclarationInfo, FoundDeclaration},
};
use roc_collections::MutMap; use roc_collections::MutMap;
use roc_load::{CheckedModule, LoadedModule}; use roc_load::{CheckedModule, LoadedModule};
use roc_module::symbol::{Interns, ModuleId, Symbol}; use roc_module::symbol::{Interns, ModuleId, Symbol};
@ -25,7 +21,7 @@ use tower_lsp::lsp_types::{
}; };
use crate::{ use crate::{
analysis::completion::Completion, analysis::completion::get_completions,
convert::{ convert::{
diag::{IntoLspDiagnostic, ProblemFmt}, diag::{IntoLspDiagnostic, ProblemFmt},
ToRange, ToRocPosition, ToRange, ToRocPosition,
@ -454,19 +450,15 @@ impl AnalyzedDocument {
writeln!(&mut stderr, "prefix is: {:?}", symbol_prefix); writeln!(&mut stderr, "prefix is: {:?}", symbol_prefix);
//TODO: to impliment record destructuring and other complex patterns i should pass in the completion item maker into this call and call it directly from the visitor //TODO: to impliment record destructuring and other complex patterns i should pass in the completion item maker into this call and call it directly from the visitor
let mut completion = Completion {
subs,
interns,
module_id,
prefix: symbol_prefix,
};
let completions = get_completions( let completions = get_completions(
position, position,
&declarations, declarations,
&mut completion, subs,
Completion::maybe_complete, symbol_prefix,
interns,
module_id,
); );
writeln!(&mut stderr, "got completions: "); writeln!(&mut stderr, "got completions: ");
Some(completions.into_iter().flatten().collect()) Some(completions)
} }
} }

View file

@ -1,25 +1,96 @@
use std::io::Write; use std::{io::Write, path::Prefix};
use roc_can::{ use roc_can::{
pattern::{Pattern, RecordDestruct}, def::Def,
traverse::{DeclarationInfo, FoundDeclaration}, expr::{Declarations, Expr, WhenBranch},
pattern::{Pattern, RecordDestruct, TupleDestruct},
traverse::{walk_decl, walk_def, walk_expr, DeclarationInfo, FoundDeclaration, Visitor},
}; };
use roc_module::symbol::{self, Interns, ModuleId, Symbol}; use roc_module::symbol::{self, Interns, ModuleId, Symbol};
use roc_region::all::Loc; use roc_region::all::{Loc, Position, Region};
use roc_types::subs::{Subs, Variable}; use roc_types::subs::{Subs, Variable};
use tower_lsp::lsp_types::{CompletionItem, CompletionItemKind}; use tower_lsp::lsp_types::{CompletionItem, CompletionItemKind};
use crate::analysis::format_var_type; use crate::analysis::format_var_type;
use super::AnalyzedModule; pub struct CompletionVisitor<'a> {
pub(crate) struct Completion<'a> { position: Position,
found_decls: Vec<CompletionItem>,
pub subs: &'a mut Subs, pub subs: &'a mut Subs,
pub interns: &'a Interns, pub interns: &'a Interns,
pub module_id: &'a ModuleId, pub module_id: &'a ModuleId,
pub prefix: String, pub prefix: String,
} }
impl Completion<'_> {
pub fn make_completion_items(&mut self, found: Vec<FoundDeclaration>) -> Vec<CompletionItem> { impl Visitor for CompletionVisitor<'_> {
fn should_visit(&mut self, region: Region) -> bool {
region.contains_pos(self.position)
}
fn visit_expr(&mut self, expr: &Expr, region: Region, var: Variable) {
if region.contains_pos(self.position) {
// self.region_typ = Some((region, var));
let mut res = self
.expression_defs(expr)
.into_iter()
.map(|(symbol, var)| {
self.make_completion_item(&symbol, &var, CompletionItemKind::VARIABLE)
})
.collect();
self.found_decls.append(&mut res);
walk_expr(self, expr, var);
}
}
// fn visit_pattern(&mut self, pat: &Pattern, region: Region, opt_var: Option<Variable>) {
// if region.contains_pos(self.position) {
// // if let Some(var) = opt_var {
// // self.region_typ = Some((region, var));
// // }
// walk_pattern(self, pat);
// }
// }
fn visit_decl(&mut self, decl: DeclarationInfo<'_>) {
match decl {
DeclarationInfo::Value { loc_expr, .. }
| DeclarationInfo::Function {
loc_body: loc_expr, ..
}
| DeclarationInfo::Destructure { loc_expr, .. } => {
let mut res = self
.decl_to_completion_item(&decl)
.into_iter()
.map(|(symbol, var)| {
self.make_completion_item(&symbol, &var, CompletionItemKind::VARIABLE)
})
.collect();
self.found_decls.append(&mut res);
if loc_expr.region.contains_pos(self.position) {
walk_decl(self, decl);
};
}
_ => {
walk_decl(self, decl);
}
}
}
fn visit_def(&mut self, def: &Def) {
let mut res = self
.extract_defs(def)
.into_iter()
.map(|(symbol, var)| {
self.make_completion_item(&symbol, &var, CompletionItemKind::VARIABLE)
})
.collect();
self.found_decls.append(&mut res);
walk_def(self, def);
}
}
impl CompletionVisitor<'_> {
fn make_completion_items(&mut self, found: Vec<FoundDeclaration>) -> Vec<(Symbol, Variable)> {
found found
.iter() .iter()
.flat_map(|comp| match comp { .flat_map(|comp| match comp {
@ -27,31 +98,102 @@ impl Completion<'_> {
FoundDeclaration::Def(def) => def FoundDeclaration::Def(def) => def
.pattern_vars .pattern_vars
.iter() .iter()
.map(|(symbol, var)| self.make_completion_item_var(symbol, var)) .map(|(symbol, var)| (symbol.clone(), var.clone()))
.collect(), .collect(),
}) })
.collect() .collect()
} }
pub fn maybe_complete(&mut self, found: FoundDeclaration) -> Vec<CompletionItem> { fn extract_defs(&mut self, def: &Def) -> Vec<(Symbol, Variable)> {
let mut stderr = std::io::stderr(); let mut stderr = std::io::stderr();
writeln!(&mut stderr, "completion begin"); writeln!(&mut stderr, "completion begin");
match found { def.pattern_vars
FoundDeclaration::Decl(dec) => self.decl_to_completion_item(&dec),
FoundDeclaration::Def(def) => def
.pattern_vars
.iter() .iter()
.map(|(symbol, var)| self.make_completion_item_var(symbol, var)) .map(|(symbol, var)| (symbol.clone(), var.clone()))
.collect(), .collect()
} }
fn expression_defs(&self, expr: &Expr) -> Vec<(Symbol, Variable)> {
match expr {
// Expr::Num(_, _, _, _) => todo!(),
// Expr::Int(_, _, _, _, _) => todo!(),
// Expr::Float(_, _, _, _, _) => todo!(),
// Expr::Str(_) => todo!(),
// Expr::SingleQuote(_, _, _, _) => todo!(),
// Expr::List { elem_var, loc_elems } => todo!(),
// Expr::IngestedFile(_, _, _) => todo!(),
// Expr::Var(_, _) => todo!(),
// Expr::AbilityMember(_, _, _) => todo!(),
Expr::When { loc_cond, cond_var, expr_var, region, branches, branches_cond_var, exhaustive } => {
let out:Vec<_> =
branches.iter().flat_map(|WhenBranch{ patterns, value, guard, redundant }|{
if value.region.contains_pos(self.position) {
patterns.iter().flat_map(|pattern|{
//We use the expression var here because if the pattern is an identifier then it must have the type of the expession given to the when is block
self.patterns(&pattern.pattern.value,expr_var)
}).collect()
} }
fn record_destructs(&mut self, destructs: &Vec<Loc<RecordDestruct>>) -> Vec<CompletionItem> { else{vec![]}
}).collect();
out
},
// Expr::If { cond_var, branch_var, branches, final_else } => todo!(),
_=>vec![]
// Expr::LetRec(_, _, _) => todo!(),
// Expr::LetNonRec(_, _) => todo!(),
// Expr::Call(_, _, _) => todo!(),
// Expr::RunLowLevel { op, args, ret_var } => todo!(),
// Expr::ForeignCall { foreign_symbol, args, ret_var } => todo!(),
// Expr::Closure(_) => todo!(),
// Expr::Record { record_var, fields } => todo!(),
// Expr::EmptyRecord => todo!(),
// Expr::Tuple { tuple_var, elems } => todo!(),
// Expr::Crash { msg, ret_var } => todo!(),
// Expr::RecordAccess { record_var, ext_var, field_var, loc_expr, field } => todo!(),
// Expr::RecordAccessor(_) => todo!(),
// Expr::TupleAccess { tuple_var, ext_var, elem_var, loc_expr, index } => todo!(),
// Expr::RecordUpdate { record_var, ext_var, symbol, updates } => todo!(),
// Expr::Tag { tag_union_var, ext_var, name, arguments } => todo!(),
// Expr::ZeroArgumentTag { closure_name, variant_var, ext_var, name } => todo!(),
// Expr::OpaqueRef { opaque_var, name, argument, specialized_def_type, type_arguments, lambda_set_variables } => todo!(),
// Expr::OpaqueWrapFunction(_) => todo!(),
// Expr::Expect { loc_condition, loc_continuation, lookups_in_cond } => todo!(),
// Expr::ExpectFx { loc_condition, loc_continuation, lookups_in_cond } => todo!(),
// Expr::Dbg { loc_message, loc_continuation, variable, symbol } => todo!(),
// Expr::TypedHole(_) => todo!(),
// Expr::RuntimeError(_) => todo!(),
}
}
fn record_destructs(&self, destructs: &Vec<Loc<RecordDestruct>>) -> Vec<(Symbol, Variable)> {
destructs destructs
.iter() .iter()
.map(|a| self.make_completion_item_var(&a.value.symbol, &a.value.var)) //TODO:I need to destructure value.typ here
.flat_map(|a| {
match &a.value.typ {
roc_can::pattern::DestructType::Required |
roc_can::pattern::DestructType::Optional(_, _) => vec![(a.value.symbol,a.value.var)],
roc_can::pattern::DestructType::Guard(var, pat) =>self.patterns(&pat.value,&var ) ,
}
}
)
.collect()
}
fn tuple_destructs(&self, destructs: &Vec<Loc<TupleDestruct>>) -> Vec<(Symbol, Variable)> {
destructs
.iter()
//TODO:I need to destructure value.typ here
.flat_map(|a| {
let (var,pattern)=&a.value.typ;
self.patterns(&pattern.value,&var)
})
.collect() .collect()
} }
fn as_pattern(&mut self, as_pat: &Pattern, as_symbol: &Symbol) -> CompletionItem { fn as_pattern(&self, as_pat: &Pattern, as_symbol: Symbol) -> (Symbol, Variable) {
let var = match as_pat { let var = match as_pat {
Pattern::AppliedTag { Pattern::AppliedTag {
whole_var, whole_var,
@ -95,40 +237,50 @@ impl Completion<'_> {
// Pattern::MalformedPattern(_, _) => todo!(), // Pattern::MalformedPattern(_, _) => todo!(),
_ => todo!(), _ => todo!(),
}; };
self.make_completion_item_var(&as_symbol, &var) (as_symbol, var.clone())
} }
fn patterns(&mut self, pattern: &roc_can::pattern::Pattern) -> Vec<CompletionItem> { fn patterns(&self, pattern: &roc_can::pattern::Pattern,var: &Variable) -> Vec<(Symbol, Variable)> {
match pattern { match pattern {
// roc_can::pattern::Pattern::Identifier(symbol) => { roc_can::pattern::Pattern::Identifier(symbol) => {
// todo!() if self.is_match(symbol) {
// } vec![(symbol.clone(),var.clone())]
roc_can::pattern::Pattern::As(pat, symbol) => {
vec![self.as_pattern(&pat.value, symbol)]
} }
// roc_can::pattern::Pattern::AppliedTag { else {vec![]}
}
// Pattern::AppliedTag {
// whole_var, // whole_var,
// ext_var, // ext_var,
// tag_name, // tag_name,
// arguments, // arguments,
// } => todo!(), // } => whole_var,
// roc_can::pattern::Pattern::UnwrappedOpaque { // Pattern::UnwrappedOpaque {
// whole_var, // whole_var,
// opaque, // opaque,
// argument, // argument,
// specialized_def_type, // specialized_def_type,
// type_arguments, // type_arguments,
// lambda_set_variables, // lambda_set_variables,
// } => todo!(), // } => whole_var,
// Pattern::List {
// list_var,
// elem_var,
// patterns,
// } => list_var,
roc_can::pattern::Pattern::As(pat, symbol) => {
vec![self.as_pattern(&pat.value, symbol.clone())]
}
roc_can::pattern::Pattern::RecordDestructure { roc_can::pattern::Pattern::RecordDestructure {
whole_var, whole_var,
ext_var, ext_var,
destructs, destructs,
} => self.record_destructs(destructs), } => self.record_destructs(destructs),
// roc_can::pattern::Pattern::TupleDestructure { roc_can::pattern::Pattern::TupleDestructure {
// whole_var, whole_var,
// ext_var, ext_var,
// destructs, destructs,
// } => todo!(), } => {
self.tuple_destructs(destructs)
},
// roc_can::pattern::Pattern::List { // roc_can::pattern::Pattern::List {
// list_var, // list_var,
// elem_var, // elem_var,
@ -161,61 +313,43 @@ impl Completion<'_> {
); );
symbol.as_str(self.interns).starts_with(&self.prefix) symbol.as_str(self.interns).starts_with(&self.prefix)
} }
fn decl_to_completion_item(&mut self, decl: &DeclarationInfo) -> Vec<CompletionItem> { fn decl_to_completion_item(&self, decl: &DeclarationInfo) -> Vec<(Symbol, Variable)> {
match decl { match decl {
DeclarationInfo::Value { DeclarationInfo::Value {
loc_symbol, loc_symbol,
expr_var, expr_var,
pattern,
.. ..
} => { } => {
if self.is_match(&loc_symbol.value) { self.patterns(pattern,expr_var )
let mut stderr = std::io::stderr();
writeln!(&mut stderr, "match");
vec![self.make_completion_item(
&loc_symbol.value,
expr_var,
CompletionItemKind::VARIABLE,
)]
} else {
let mut stderr = std::io::stderr();
writeln!(&mut stderr, "non_match");
vec![]
}
} }
DeclarationInfo::Function { DeclarationInfo::Function {
loc_symbol, loc_symbol,
expr_var, expr_var,
pattern, pattern,
function, function,
loc_body,
.. ..
} => { } => {
let mut out: Vec<_> = vec![];
//append the function declaration
out.append(&mut self.patterns(pattern,expr_var));
if loc_body.region.contains_pos(self.position) {
//also add the arguments if we are inside the function
let mut args: Vec<_> = function let mut args: Vec<_> = function
.value .value
.arguments .arguments
.iter() .iter()
.flat_map(|(var, _1, pat)| match pat.value { .flat_map(|(var, _1, pat)| self.patterns(&pat.value,var),
Pattern::Identifier(symbol) => { )
if self.is_match(&symbol) { //We add in the pattern for the function declaration
vec![self.make_completion_item_var(&symbol, var)]
} else {
vec![]
}
}
_ => self.patterns(&pat.value),
})
.collect(); .collect();
if self.is_match(&loc_symbol.value) { out.append(&mut args);
args.push(self.make_completion_item(
&loc_symbol.value,
expr_var,
CompletionItemKind::FUNCTION,
))
} }
args.append(&mut self.patterns(pattern)); out
args
} }
DeclarationInfo::Destructure { loc_pattern, .. } => self.patterns(&loc_pattern.value), DeclarationInfo::Destructure { loc_pattern,expr_var, .. } => self.patterns(&loc_pattern.value,expr_var),
DeclarationInfo::Expectation { .. } => vec![], DeclarationInfo::Expectation { .. } => vec![],
} }
} }
@ -254,3 +388,22 @@ impl Completion<'_> {
} }
} }
} }
pub fn get_completions<'a>(
position: Position,
decls: &'a Declarations,
subs: &mut Subs,
prefix: String,
interns: &Interns,
module_id: &ModuleId,
) -> Vec<CompletionItem> {
let mut visitor = CompletionVisitor {
position,
found_decls: Vec::new(),
subs,
interns,
module_id,
prefix,
};
visitor.visit_decls(decls);
visitor.found_decls
}