1use crate::lang::error::TypeError;
2use crate::lang::{PartialExpr, TcEnv, UnionIndex, ValueOrigin};
3use prism_parser::core::cache::Allocs;
4use prism_parser::grammar::action_result::ActionResult;
5use prism_parser::parser::var_map::{VarMap, VarMapValue};
6use rpds::RedBlackTreeMap;
7use std::borrow::Cow;
8
9#[derive(Clone, Debug)]
10enum ScopeValue<'arn, 'grm> {
11 FromEnv(usize),
12 FromGrammar(&'arn ActionResult<'arn, 'grm>, Scope<'arn, 'grm>),
13}
14
15#[derive(Clone, Debug, Default)]
16struct Scope<'arn, 'grm> {
17 names: RedBlackTreeMap<&'arn str, ScopeValue<'arn, 'grm>>,
18 named_scopes: RedBlackTreeMap<Guid, RedBlackTreeMap<&'arn str, ScopeValue<'arn, 'grm>>>,
19 depth: usize,
20 hygienic_decls: RedBlackTreeMap<&'arn str, usize>,
21}
22
23impl<'arn, 'grm> Scope<'arn, 'grm> {
24 pub fn insert_name(&self, key: &'arn str, program: &'arn str) -> Self {
25 Self {
26 depth: self.depth + 1,
27 ..self.clone()
28 }
29 .insert_name_at(key, self.depth, program)
30 }
31
32 pub fn insert_name_at(&self, key: &'arn str, depth: usize, program: &'arn str) -> Self {
33 let names = self.names.insert(key, ScopeValue::FromEnv(depth));
34 let hygienic_decls = if let Some(ScopeValue::FromGrammar(ar, _)) = self.names.get(key) {
35 let new_name = TcEnv::parse_name(ar, program);
36 self.hygienic_decls.insert(new_name, depth)
37 } else {
38 self.hygienic_decls.clone()
39 };
40
41 Self {
42 names,
43 hygienic_decls,
44 ..self.clone()
45 }
46 }
47
48 pub fn get(&self, key: &str) -> Option<&ScopeValue<'arn, 'grm>> {
49 self.names.get(key)
50 }
51
52 pub fn extend_with_ars(&self, new_vars: &VarMap<'arn, 'grm>, vars: &Self) -> Self {
53 let mut names = self.names.clone();
54 for (name, value) in new_vars.iter_cloned() {
55 match value {
56 VarMapValue::Expr(_) => continue,
57 VarMapValue::Value(ar) => {
58 names.insert_mut(name, ScopeValue::FromGrammar(ar, vars.clone()));
59 }
60 }
61 }
62
63 Self {
64 names,
65 ..self.clone()
66 }
67 }
68
69 pub fn insert_jump(&self, guid: Guid) -> Self {
70 Scope {
71 names: self.names.clone(),
72 named_scopes: self.named_scopes.insert(guid, self.names.clone()),
73 depth: self.depth,
74 hygienic_decls: self.hygienic_decls.clone(),
75 }
76 }
77
78 pub fn jump(&self, guid: Guid) -> Self {
79 Scope {
80 names: self.named_scopes[&guid].clone(),
81 named_scopes: self.named_scopes.clone(),
82 depth: self.depth,
83 hygienic_decls: self.hygienic_decls.clone(),
84 }
85 }
86}
87
88#[derive(Default, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Debug)]
89pub struct Guid(pub usize);
90
91impl TcEnv {
92 pub fn insert_from_action_result<'arn>(
93 &mut self,
94 value: &ActionResult<'arn, '_>,
95 program: &'arn str,
96 _arena: Allocs,
97 ) -> UnionIndex {
98 self.insert_from_action_result_rec(value, program, &Scope::default())
99 }
100
101 fn insert_from_action_result_rec<'arn, 'grm>(
102 &mut self,
103 value: &ActionResult<'arn, 'grm>,
104 program: &'arn str,
105 vars: &Scope<'arn, 'grm>,
106 ) -> UnionIndex {
107 let (inner, inner_span) = match value {
108 ActionResult::Construct(span, constructor, args) => (
109 match *constructor {
110 "Type" => {
111 assert_eq!(args.len(), 0);
112 PartialExpr::Type
113 }
114 "Let" => {
115 assert_eq!(args.len(), 3);
116 let name = Self::parse_name(&args[0], program);
117
118 let v = self.insert_from_action_result_rec(&args[1], program, vars);
119 let b = self.insert_from_action_result_rec(
120 &args[2],
121 program,
122 &vars.insert_name(name, program),
123 );
124
125 PartialExpr::Let(v, b)
126 }
127 "FnType" => {
128 assert_eq!(args.len(), 3);
129 let name = Self::parse_name(&args[0], program);
130
131 let v = self.insert_from_action_result_rec(&args[1], program, vars);
132 let b = self.insert_from_action_result_rec(
133 &args[2],
134 program,
135 &vars.insert_name(name, program),
136 );
137
138 PartialExpr::FnType(v, b)
139 }
140 "FnConstruct" => {
141 assert_eq!(args.len(), 2);
142 let name = Self::parse_name(&args[0], program);
143
144 let b = self.insert_from_action_result_rec(
145 &args[1],
146 program,
147 &vars.insert_name(name, program),
148 );
149
150 PartialExpr::FnConstruct(b)
151 }
152 "FnDestruct" => {
153 assert_eq!(args.len(), 2);
154
155 let f = self.insert_from_action_result_rec(&args[0], program, vars);
156 let v = self.insert_from_action_result_rec(&args[1], program, vars);
157
158 PartialExpr::FnDestruct(f, v)
159 }
160 "GrammarDefine" => {
161 assert_eq!(args.len(), 4);
162 let guid = Self::parse_guid(&args[1]);
163 let _id = Self::parse_name(&args[2], program);
164 let _grammar = &args[3];
165
166 return self.insert_from_action_result_rec(
167 &args[0],
168 program,
169 &vars.insert_jump(guid),
170 );
171 }
172 "TypeAssert" => {
173 assert_eq!(args.len(), 2);
174
175 let e = self.insert_from_action_result_rec(&args[0], program, vars);
176 let typ = self.insert_from_action_result_rec(&args[1], program, vars);
177
178 PartialExpr::TypeAssert(e, typ)
179 }
180 _ => unreachable!(),
181 },
182 *span,
183 ),
184 ActionResult::Value(span) => {
185 let name = Self::parse_name(value, program);
186
187 let e = if name == "_" {
188 PartialExpr::Free
189 } else {
190 match vars.get(name) {
191 None => {
192 self.errors.push(TypeError::UnknownName(*span));
193 PartialExpr::Free
194 }
195 Some(ScopeValue::FromGrammar(ar, scope_vars)) => {
196 let mut scope_vars_with_hygienic_decls = Scope {
198 depth: vars.depth,
199 ..scope_vars.clone()
200 };
201
202 for (k, v) in &vars.hygienic_decls {
204 scope_vars_with_hygienic_decls =
205 scope_vars_with_hygienic_decls.insert_name_at(k, *v, program);
206 }
207
208 return self.insert_from_action_result_rec(
210 ar,
211 program,
212 &scope_vars_with_hygienic_decls,
213 );
214 }
215 Some(ScopeValue::FromEnv(ix)) => {
216 PartialExpr::DeBruijnIndex(vars.depth - ix - 1)
217 }
218 }
219 };
220 (e, *span)
221 }
222 ActionResult::WithEnv(new_vars, ar) => {
223 let ActionResult::Construct(_span, "ScopeEnter", args) = ar else {
224 unreachable!()
225 };
226 let guid = Self::parse_guid(&args[1]);
227 let vars = vars.jump(guid).extend_with_ars(new_vars, vars);
228
229 return self.insert_from_action_result_rec(&args[0], program, &vars);
230 }
231 _ => unreachable!(),
232 };
233 self.store(inner, ValueOrigin::SourceCode(inner_span))
234 }
235
236 fn parse_name<'arn>(ar: &ActionResult<'arn, '_>, program: &'arn str) -> &'arn str {
237 match ar {
238 ActionResult::Value(span) => &program[*span],
239 ActionResult::Literal(l) => match l.to_cow() {
240 Cow::Borrowed(s) => s,
241 Cow::Owned(_) => unreachable!(),
242 },
243 _ => unreachable!(),
244 }
245 }
246
247 fn parse_guid(ar: &ActionResult) -> Guid {
248 let ActionResult::Guid(v) = ar else {
249 unreachable!()
250 };
251 Guid(*v)
252 }
253}