yog_script_analyze/resolve/
scope.rs1use std::collections::HashMap;
5
6use yog_ids::script_problem;
7
8use super::Resolver;
9use crate::ast::Name;
10use crate::source::token::Span;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub enum DefKind {
15 Value,
17 Variable,
19 Param,
20 Fn,
21 Type,
23 Case,
25 Field,
27 Content,
29 Import,
31}
32
33impl DefKind {
34 pub fn assignable(self) -> bool {
36 matches!(self, DefKind::Variable | DefKind::Field)
37 }
38}
39
40#[derive(Debug, Clone, PartialEq)]
42pub struct Def {
43 pub name: String,
44 pub span: Span,
45 pub kind: DefKind,
46}
47
48#[derive(Debug, Clone, Default, PartialEq)]
50pub struct Symbols {
51 pub defs: Vec<Def>,
52 pub refs: Vec<(Span, usize)>,
53}
54
55impl Symbols {
56 pub fn def_at(&self, offset: u32) -> Option<&Def> {
59 let inside = |s: Span| s.start <= offset && offset < s.end;
60 self.refs
61 .iter()
62 .find(|(s, _)| inside(*s))
63 .and_then(|(_, d)| self.defs.get(*d))
64 .or_else(|| self.defs.iter().find(|d| inside(d.span)))
65 }
66}
67
68#[derive(Default)]
70pub(super) struct Scope {
71 names: HashMap<String, usize>,
72}
73
74impl Resolver<'_, '_> {
75 pub(super) fn scoped<R>(&mut self, f: impl FnOnce(&mut Self) -> R) -> R {
77 self.scopes.push(Scope::default());
78 let out = f(self);
79 self.scopes.pop();
80 out
81 }
82
83 pub(super) fn define(&mut self, name: &Name, kind: DefKind, again: bool) {
86 let id = self.symbols.defs.len();
87 let Some(scope) = self.scopes.last_mut() else {
88 return;
89 };
90 if let Some(&first) = scope.names.get(&name.text) {
91 if !again {
92 let at = self.symbols.defs[first].span;
93 let line = self.report.line_of(at);
94 self.report.error(
95 script_problem::DUPLICATE,
96 name.span,
97 format!("`{}` is declared already (line {line})", name.text),
98 );
99 }
100 return;
101 }
102 scope.names.insert(name.text.clone(), id);
103 self.symbols.defs.push(Def {
104 name: name.text.clone(),
105 span: name.span,
106 kind,
107 });
108 }
109
110 pub(super) fn bind(&mut self, name: &Name, kind: DefKind) {
112 let id = self.symbols.defs.len();
113 if let Some(scope) = self.scopes.last_mut() {
114 scope.names.insert(name.text.clone(), id);
115 self.symbols.defs.push(Def {
116 name: name.text.clone(),
117 span: name.span,
118 kind,
119 });
120 }
121 }
122
123 pub(super) fn lookup(&self, name: &str) -> Option<usize> {
125 self.scopes
126 .iter()
127 .rev()
128 .find_map(|s| s.names.get(name).copied())
129 }
130
131 pub(super) fn refer(&mut self, name: &str, span: Span) -> Option<DefKind> {
134 let id = self.lookup(name)?;
135 self.symbols.refs.push((span, id));
136 Some(self.symbols.defs[id].kind)
137 }
138}