1use crate::{
2 expr::{Arg, ModPath},
3 typ::{FnType, NoRefs, Type},
4 BindId, Ctx, InitFn, LambdaId, UserEvent,
5};
6use anyhow::{bail, Result};
7use arcstr::ArcStr;
8use compact_str::CompactString;
9use immutable_chunkmap::{map::MapS as Map, set::SetS as Set};
10use netidx::path::Path;
11use std::{fmt, iter, ops::Bound, sync::Weak};
12use triomphe::Arc;
13
14pub struct LambdaDef<C: Ctx, E: UserEvent> {
15 pub id: LambdaId,
16 pub env: Env<C, E>,
17 pub scope: ModPath,
18 pub argspec: Arc<[Arg<NoRefs>]>,
19 pub typ: Arc<FnType<NoRefs>>,
20 pub init: InitFn<C, E>,
21}
22
23impl<C: Ctx, E: UserEvent> fmt::Debug for LambdaDef<C, E> {
24 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25 write!(f, "LambdaDef({:?})", self.id)
26 }
27}
28
29pub struct Bind {
30 pub id: BindId,
31 pub export: bool,
32 pub typ: Type<NoRefs>,
33 pub doc: Option<ArcStr>,
34 scope: ModPath,
35 name: CompactString,
36}
37
38impl fmt::Debug for Bind {
39 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40 write!(f, "Bind {{ id: {:?}, export: {} }}", self.id, self.export,)
41 }
42}
43
44impl Clone for Bind {
45 fn clone(&self) -> Self {
46 Self {
47 id: self.id,
48 scope: self.scope.clone(),
49 name: self.name.clone(),
50 doc: self.doc.clone(),
51 export: self.export,
52 typ: self.typ.clone(),
53 }
54 }
55}
56
57pub struct Env<C: Ctx, E: UserEvent> {
58 pub by_id: Map<BindId, Bind>,
59 pub lambdas: Map<LambdaId, Weak<LambdaDef<C, E>>>,
60 pub binds: Map<ModPath, Map<CompactString, BindId>>,
61 pub used: Map<ModPath, Arc<Vec<ModPath>>>,
62 pub modules: Set<ModPath>,
63 pub typedefs: Map<ModPath, Map<CompactString, Type<NoRefs>>>,
64}
65
66impl<C: Ctx, E: UserEvent> Clone for Env<C, E> {
67 fn clone(&self) -> Self {
68 Self {
69 by_id: self.by_id.clone(),
70 binds: self.binds.clone(),
71 used: self.used.clone(),
72 modules: self.modules.clone(),
73 typedefs: self.typedefs.clone(),
74 lambdas: self.lambdas.clone(),
75 }
76 }
77}
78
79impl<C: Ctx, E: UserEvent> Env<C, E> {
80 pub(super) fn new() -> Self {
81 Self {
82 by_id: Map::new(),
83 binds: Map::new(),
84 used: Map::new(),
85 modules: Set::new(),
86 typedefs: Map::new(),
87 lambdas: Map::new(),
88 }
89 }
90
91 pub(super) fn clear(&mut self) {
92 let Self { by_id, binds, used, modules, typedefs, lambdas } = self;
93 *by_id = Map::new();
94 *binds = Map::new();
95 *used = Map::new();
96 *modules = Set::new();
97 *typedefs = Map::new();
98 *lambdas = Map::new();
99 }
100
101 pub(super) fn restore_lexical_env(&self, other: &Self) -> Self {
105 Self {
106 binds: other.binds.clone(),
107 used: other.used.clone(),
108 modules: other.modules.clone(),
109 typedefs: other.typedefs.clone(),
110 by_id: self.by_id.clone(),
111 lambdas: self.lambdas.clone(),
112 }
113 }
114
115 pub(super) fn merge_lexical(&self, orig: &Self) -> Self {
119 let Self { by_id: _, lambdas: _, binds, used, modules, typedefs } = self;
120 let binds = binds.update_many(
121 orig.binds.into_iter().map(|(s, m)| (s.clone(), m)),
122 |k, v, kv| match kv {
123 None => Some((k, v.clone())),
124 Some((_, m)) => {
125 let v = m.update_many(
126 v.into_iter().map(|(k, v)| (k.clone(), *v)),
127 |k, v, _| Some((k, v)),
128 );
129 Some((k, v))
130 }
131 },
132 );
133 let used = used.update_many(
134 orig.used.into_iter().map(|(k, v)| (k.clone(), v.clone())),
135 |k, v, _| Some((k, v)),
136 );
137 let modules = modules.union(&orig.modules);
138 let typedefs = typedefs.update_many(
139 orig.typedefs.into_iter().map(|(k, v)| (k.clone(), v)),
140 |k, v, kv| match kv {
141 None => Some((k, v.clone())),
142 Some((_, m)) => {
143 let v = m.update_many(
144 v.into_iter().map(|(k, v)| (k.clone(), v.clone())),
145 |k, v, _| Some((k, v)),
146 );
147 Some((k, v))
148 }
149 },
150 );
151 Self {
152 binds,
153 used,
154 modules,
155 typedefs,
156 by_id: self.by_id.clone(),
157 lambdas: self.lambdas.clone(),
158 }
159 }
160
161 pub fn find_visible<R, F: FnMut(&str, &str) -> Option<R>>(
162 &self,
163 scope: &ModPath,
164 name: &ModPath,
165 mut f: F,
166 ) -> Option<R> {
167 let mut buf = CompactString::from("");
168 let name_scope = Path::dirname(&**name);
169 let name = Path::basename(&**name).unwrap_or("");
170 for scope in Path::dirnames(&**scope).rev() {
171 let used = self.used.get(scope);
172 let used = iter::once(scope)
173 .chain(used.iter().flat_map(|s| s.iter().map(|p| &***p)));
174 for scope in used {
175 let scope = name_scope
176 .map(|ns| {
177 buf.clear();
178 buf.push_str(scope);
179 if let Some(Path::SEP) = buf.chars().next_back() {
180 buf.pop();
181 }
182 buf.push_str(ns);
183 buf.as_str()
184 })
185 .unwrap_or(scope);
186 if let Some(res) = f(scope, name) {
187 return Some(res);
188 }
189 }
190 }
191 None
192 }
193
194 pub fn lookup_bind(
195 &self,
196 scope: &ModPath,
197 name: &ModPath,
198 ) -> Option<(&ModPath, &Bind)> {
199 self.find_visible(scope, name, |scope, name| {
200 self.binds.get_full(scope).and_then(|(scope, vars)| {
201 vars.get(name)
202 .and_then(|bid| self.by_id.get(bid).map(|bind| (scope, bind)))
203 })
204 })
205 }
206
207 pub fn lookup_matching(
211 &self,
212 scope: &ModPath,
213 part: &ModPath,
214 ) -> Vec<(CompactString, BindId)> {
215 let mut res = vec![];
216 self.find_visible(scope, part, |scope, part| {
217 if let Some(vars) = self.binds.get(scope) {
218 let r = vars.range::<str, _>((Bound::Included(part), Bound::Unbounded));
219 for (name, bind) in r {
220 if name.starts_with(part) {
221 res.push((name.clone(), *bind));
222 }
223 }
224 }
225 None::<()>
226 });
227 res
228 }
229
230 pub fn lookup_matching_modules(
234 &self,
235 scope: &ModPath,
236 part: &ModPath,
237 ) -> Vec<ModPath> {
238 let mut res = vec![];
239 self.find_visible(scope, part, |scope, part| {
240 let p = ModPath(Path::from(ArcStr::from(scope)).append(part));
241 for m in self.modules.range((Bound::Included(p.clone()), Bound::Unbounded)) {
242 if m.0.starts_with(&*p.0) {
243 if let Some(m) = m.strip_prefix(scope) {
244 if !m.trim().is_empty() {
245 res.push(ModPath(Path::from(ArcStr::from(m))));
246 }
247 }
248 }
249 }
250 None::<()>
251 });
252 res
253 }
254
255 pub fn deftype(
256 &mut self,
257 scope: &ModPath,
258 name: &str,
259 typ: Type<NoRefs>,
260 ) -> Result<()> {
261 let defs = self.typedefs.get_or_default_cow(scope.clone());
262 if defs.get(name).is_some() {
263 bail!("{name} is already defined in scope {scope}")
264 } else {
265 defs.insert_cow(name.into(), typ);
266 Ok(())
267 }
268 }
269
270 pub fn undeftype(&mut self, scope: &ModPath, name: &str) {
271 if let Some(defs) = self.typedefs.get_mut_cow(scope) {
272 defs.remove_cow(&CompactString::from(name));
273 if defs.len() == 0 {
274 self.typedefs.remove_cow(scope);
275 }
276 }
277 }
278
279 pub fn bind_variable(
282 &mut self,
283 scope: &ModPath,
284 name: &str,
285 typ: Type<NoRefs>,
286 ) -> &mut Bind {
287 let binds = self.binds.get_or_default_cow(scope.clone());
288 let mut existing = true;
289 let id = binds.get_or_insert_cow(CompactString::from(name), || {
290 existing = false;
291 BindId::new()
292 });
293 if existing {
294 *id = BindId::new();
295 }
296 self.by_id.get_or_insert_cow(*id, || Bind {
297 export: true,
298 id: *id,
299 scope: scope.clone(),
300 doc: None,
301 name: CompactString::from(name),
302 typ,
303 })
304 }
305
306 pub fn unbind_variable(&mut self, id: BindId) {
307 if let Some(b) = self.by_id.remove_cow(&id) {
308 if let Some(binds) = self.binds.get_mut_cow(&b.scope) {
309 binds.remove_cow(&b.name);
310 if binds.len() == 0 {
311 self.binds.remove_cow(&b.scope);
312 }
313 }
314 }
315 }
316}