prism_compiler/lang/
from_action_result.rs

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                            // Create a new scope based on the current depth and `scope_vars`
197                            let mut scope_vars_with_hygienic_decls = Scope {
198                                depth: vars.depth,
199                                ..scope_vars.clone()
200                            };
201
202                            // Insert hygienically declared variables into the scope
203                            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                            // Parse the value in the new scope
209                            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}