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::*;
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 roc_can::{
abilities::AbilitiesStore,
expr::Declarations,
traverse::{get_completions, DeclarationInfo, FoundDeclaration},
};
use roc_can::{abilities::AbilitiesStore, expr::Declarations};
use roc_collections::MutMap;
use roc_load::{CheckedModule, LoadedModule};
use roc_module::symbol::{Interns, ModuleId, Symbol};
@ -25,7 +21,7 @@ use tower_lsp::lsp_types::{
};
use crate::{
analysis::completion::Completion,
analysis::completion::get_completions,
convert::{
diag::{IntoLspDiagnostic, ProblemFmt},
ToRange, ToRocPosition,
@ -454,19 +450,15 @@ impl AnalyzedDocument {
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
let mut completion = Completion {
subs,
interns,
module_id,
prefix: symbol_prefix,
};
let completions = get_completions(
position,
&declarations,
&mut completion,
Completion::maybe_complete,
declarations,
subs,
symbol_prefix,
interns,
module_id,
);
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::{
pattern::{Pattern, RecordDestruct},
traverse::{DeclarationInfo, FoundDeclaration},
def::Def,
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_region::all::Loc;
use roc_region::all::{Loc, Position, Region};
use roc_types::subs::{Subs, Variable};
use tower_lsp::lsp_types::{CompletionItem, CompletionItemKind};
use crate::analysis::format_var_type;
use super::AnalyzedModule;
pub(crate) struct Completion<'a> {
pub struct CompletionVisitor<'a> {
position: Position,
found_decls: Vec<CompletionItem>,
pub subs: &'a mut Subs,
pub interns: &'a Interns,
pub module_id: &'a ModuleId,
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
.iter()
.flat_map(|comp| match comp {
@ -27,31 +98,102 @@ impl Completion<'_> {
FoundDeclaration::Def(def) => def
.pattern_vars
.iter()
.map(|(symbol, var)| self.make_completion_item_var(symbol, var))
.map(|(symbol, var)| (symbol.clone(), var.clone()))
.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();
writeln!(&mut stderr, "completion begin");
match found {
FoundDeclaration::Decl(dec) => self.decl_to_completion_item(&dec),
FoundDeclaration::Def(def) => def
.pattern_vars
.iter()
.map(|(symbol, var)| self.make_completion_item_var(symbol, var))
.collect(),
}
def.pattern_vars
.iter()
.map(|(symbol, var)| (symbol.clone(), var.clone()))
.collect()
}
fn record_destructs(&mut self, destructs: &Vec<Loc<RecordDestruct>>) -> Vec<CompletionItem> {
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()
}
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
.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()
}
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 {
Pattern::AppliedTag {
whole_var,
@ -95,40 +237,50 @@ impl Completion<'_> {
// Pattern::MalformedPattern(_, _) => 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 {
// roc_can::pattern::Pattern::Identifier(symbol) => {
// todo!()
// }
roc_can::pattern::Pattern::As(pat, symbol) => {
vec![self.as_pattern(&pat.value, symbol)]
roc_can::pattern::Pattern::Identifier(symbol) => {
if self.is_match(symbol) {
vec![(symbol.clone(),var.clone())]
}
else {vec![]}
}
// roc_can::pattern::Pattern::AppliedTag {
// Pattern::AppliedTag {
// whole_var,
// ext_var,
// tag_name,
// arguments,
// } => todo!(),
// roc_can::pattern::Pattern::UnwrappedOpaque {
// } => whole_var,
// Pattern::UnwrappedOpaque {
// whole_var,
// opaque,
// argument,
// specialized_def_type,
// type_arguments,
// 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 {
whole_var,
ext_var,
destructs,
} => self.record_destructs(destructs),
// roc_can::pattern::Pattern::TupleDestructure {
// whole_var,
// ext_var,
// destructs,
// } => todo!(),
roc_can::pattern::Pattern::TupleDestructure {
whole_var,
ext_var,
destructs,
} => {
self.tuple_destructs(destructs)
},
// roc_can::pattern::Pattern::List {
// list_var,
// elem_var,
@ -161,61 +313,43 @@ impl Completion<'_> {
);
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 {
DeclarationInfo::Value {
loc_symbol,
expr_var,
pattern,
..
} => {
if self.is_match(&loc_symbol.value) {
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![]
}
self.patterns(pattern,expr_var )
}
DeclarationInfo::Function {
loc_symbol,
expr_var,
pattern,
function,
loc_body,
..
} => {
let mut args: Vec<_> = function
.value
.arguments
.iter()
.flat_map(|(var, _1, pat)| match pat.value {
Pattern::Identifier(symbol) => {
if self.is_match(&symbol) {
vec![self.make_completion_item_var(&symbol, var)]
} else {
vec![]
}
}
_ => self.patterns(&pat.value),
})
.collect();
if self.is_match(&loc_symbol.value) {
args.push(self.make_completion_item(
&loc_symbol.value,
expr_var,
CompletionItemKind::FUNCTION,
))
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
.value
.arguments
.iter()
.flat_map(|(var, _1, pat)| self.patterns(&pat.value,var),
)
//We add in the pattern for the function declaration
.collect();
out.append(&mut args);
}
args.append(&mut self.patterns(pattern));
args
out
}
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![],
}
}
@ -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
}