use tree_sitter::Node;
use crate::scope_model::walk::{Backend, dispatch};
use crate::scope_model::{IntroKind, Write};
use super::scope::Collector;
impl Collector<'_> {
pub(super) fn walk_pattern_declaration(&mut self, n: Node, scope: usize) {
let mut targets = Vec::new();
for child in pre_eq_nodes(n) {
collect_identifiers(child, &mut targets);
}
for t in targets {
let w = Write::assign(t.start_byte(), t.id(), None);
self.bind_var(t, scope, w, IntroKind::Assign);
}
walk_post_eq(self, n, scope);
}
pub(super) fn walk_pattern_assignment(&mut self, n: Node, scope: usize) {
let mut targets = Vec::new();
for child in pre_eq_nodes(n) {
collect_identifiers(child, &mut targets);
}
for t in targets {
if !self.rebind_local(t, scope, true, None) {
let name = self.text_of(t).to_string();
self.model.record_read(scope, &name, t.start_byte());
}
}
walk_post_eq(self, n, scope);
}
pub(super) fn walk_assignment(&mut self, n: Node, scope: usize) {
let left = n.child_by_field_name("left");
let right = n.child_by_field_name("right");
let plain = n
.child_by_field_name("operator")
.and_then(|o| o.utf8_text(self.src).ok())
== Some("=");
if let Some(left) = left {
if let Some(target) = bare_target(left) {
if !self.rebind_local(target, scope, plain, right.map(|r| r.id())) {
self.walk_children(left, scope);
}
} else {
self.walk_children(left, scope);
}
}
if let Some(right) = right {
dispatch(self, right, scope);
}
}
}
fn pre_eq_nodes<'t>(n: Node<'t>) -> Vec<Node<'t>> {
let mut out = Vec::new();
let mut cursor = n.walk();
for child in n.children(&mut cursor) {
if child.kind() == "=" && !child.is_named() {
break;
}
out.push(child);
}
out
}
fn walk_post_eq(b: &mut Collector<'_>, n: Node, scope: usize) {
let mut past_eq = false;
let mut cursor = n.walk();
for child in n.children(&mut cursor) {
if !past_eq {
if child.kind() == "=" && !child.is_named() {
past_eq = true;
}
continue;
}
dispatch(b, child, scope);
}
}
pub(super) fn bare_target(left: Node<'_>) -> Option<Node<'_>> {
let mut cursor = left.walk();
let named: Vec<_> = left
.children(&mut cursor)
.filter(|c| c.is_named())
.collect();
match named[..] {
[only] if only.kind() == "identifier" => Some(only),
_ => None,
}
}
fn collect_identifiers<'t>(n: Node<'t>, out: &mut Vec<Node<'t>>) {
if n.kind() == "identifier" {
out.push(n);
}
let mut cursor = n.walk();
for child in n.children(&mut cursor) {
collect_identifiers(child, out);
}
}