cl_interpret/
lib.rs

1//! Walks a Conlang AST, interpreting it as a program.
2#![warn(clippy::all)]
3#![feature(decl_macro)]
4
5use cl_ast::Sym;
6use convalue::ConValue;
7use env::Environment;
8use error::{Error, ErrorKind, IResult};
9use interpret::Interpret;
10
11/// Callable types can be called from within a Conlang program
12pub trait Callable {
13    /// Calls this [Callable] in the provided [Environment], with [ConValue] args  \
14    /// The Callable is responsible for checking the argument count and validating types
15    fn call(&self, interpreter: &mut Environment, args: &[ConValue]) -> IResult<ConValue>;
16    /// Returns the common name of this identifier.
17    fn name(&self) -> Sym;
18}
19
20pub mod convalue;
21
22pub mod interpret;
23
24pub mod function;
25
26pub mod constructor {
27    use cl_ast::Sym;
28
29    use crate::{
30        Callable,
31        convalue::ConValue,
32        env::Environment,
33        error::{Error, IResult},
34    };
35
36    #[derive(Clone, Copy, Debug)]
37    pub struct Constructor {
38        pub name: Sym,
39        pub arity: u32,
40    }
41
42    impl Callable for Constructor {
43        fn call(&self, _env: &mut Environment, args: &[ConValue]) -> IResult<ConValue> {
44            let &Self { name, arity } = self;
45            if arity as usize == args.len() {
46                Ok(ConValue::TupleStruct(name, Box::new(args.into())))
47            } else {
48                Err(Error::ArgNumber(arity as usize, args.len()))
49            }
50        }
51
52        fn name(&self) -> cl_ast::Sym {
53            "tuple-constructor".into()
54        }
55    }
56}
57
58pub mod closure;
59
60pub mod builtin;
61
62pub mod pattern;
63
64pub mod env;
65
66pub mod modules {
67    use crate::env::StackBinds;
68    use cl_ast::{PathPart, Sym};
69    use std::collections::HashMap;
70
71    /// Immutable object-oriented interface to a [ModuleTree]
72    #[derive(Clone, Copy, Debug)]
73    pub struct ModuleNode<'tree> {
74        tree: &'tree ModuleTree,
75        index: usize,
76    }
77
78    /// Mutable object-oriented interface to a [ModuleTree]
79    #[derive(Debug)]
80    pub struct ModuleNodeMut<'tree> {
81        tree: &'tree mut ModuleTree,
82        index: usize,
83    }
84
85    macro_rules! module_node_impl {
86        () => {
87            /// Gets the index from this node
88            pub fn index(self) -> usize {
89                self.index
90            }
91            /// Gets this node's parent
92            pub fn parent(self) -> Option<Self> {
93                let parent = self.tree.parent(self.index)?;
94                Some(Self { index: parent, ..self })
95            }
96            /// Gets the node's "encompassing Type"
97            pub fn selfty(self) -> Option<Self> {
98                let selfty = self.tree.selfty(self.index)?;
99                Some(Self { index: selfty, ..self })
100            }
101            /// Gets the child of this node with the given name
102            pub fn child(self, name: &Sym) -> Option<Self> {
103                let child = self.tree.child(self.index, name)?;
104                Some(Self { index: child, ..self })
105            }
106            /// Gets a stack value in this node with the given name
107            pub fn item(self, name: &Sym) -> Option<usize> {
108                self.tree.items(self.index)?.get(name).copied()
109            }
110            /// Returns true when this node represents type information
111            pub fn is_ty(self) -> Option<bool> {
112                self.tree.is_ty.get(self.index).copied()
113            }
114            /// Returns a reference to this node's children, if present
115            pub fn children(&self) -> Option<&HashMap<Sym, usize>> {
116                self.tree.children(self.index)
117            }
118            /// Returns a reference to this node's items, if present
119            pub fn items(&self) -> Option<&StackBinds> {
120                self.tree.items(self.index)
121            }
122            /// Traverses a path starting at this node
123            ///
124            /// Returns a new node, and the unconsumed path portion.
125            pub fn find(self, path: &[PathPart]) -> (Self, &[PathPart]) {
126                let (index, path) = self.tree.find(self.index, path);
127                (Self { index, ..self }, path)
128            }
129            /// Traverses a path starting at this node
130            ///
131            /// Returns an item address if the path terminated in an item.
132            pub fn find_item(&self, path: &[PathPart]) -> Option<usize> {
133                self.tree.find_item(self.index, path)
134            }
135        };
136    }
137
138    impl ModuleNode<'_> {
139        module_node_impl! {}
140    }
141
142    impl ModuleNodeMut<'_> {
143        module_node_impl! {}
144        /// Creates a new child in this node
145        pub fn add_child(self, name: Sym, is_ty: bool) -> Self {
146            let node = self.tree.add_child(self.index, name, is_ty);
147            self.tree.get_mut(node)
148        }
149        /// Creates an arbitrary edge in the module graph
150        pub fn add_import(&mut self, name: Sym, child: usize) {
151            self.tree.add_import(self.index, name, child)
152        }
153        pub fn add_imports(&mut self, binds: HashMap<Sym, usize>) {
154            self.tree.add_imports(self.index, binds)
155        }
156        /// Binds a new item in this node
157        pub fn add_item(&mut self, name: Sym, stack_index: usize) {
158            self.tree.add_item(self.index, name, stack_index)
159        }
160        /// Binds an entire stack frame in this node
161        pub fn add_items(&mut self, binds: StackBinds) {
162            self.tree.add_items(self.index, binds)
163        }
164        /// Constructs a borrowing [ModuleNode]
165        pub fn as_ref(&self) -> ModuleNode<'_> {
166            let Self { tree, index } = self;
167            ModuleNode { tree, index: *index }
168        }
169    }
170
171    #[derive(Clone, Debug)]
172    pub struct ModuleTree {
173        parents: Vec<usize>,
174        children: Vec<HashMap<Sym, usize>>,
175        items: Vec<StackBinds>,
176        is_ty: Vec<bool>,
177    }
178
179    impl ModuleTree {
180        /// Constructs a new ModuleTree with a single root module
181        pub fn new() -> Self {
182            Self {
183                parents: vec![0],
184                children: vec![HashMap::new()],
185                items: vec![HashMap::new()],
186                is_ty: vec![false],
187            }
188        }
189
190        /// Gets a borrowed handle to the node at `index`
191        pub fn get(&self, index: usize) -> ModuleNode<'_> {
192            ModuleNode { tree: self, index }
193        }
194
195        /// Gets a mutable handle to the node at `index`
196        pub fn get_mut(&mut self, index: usize) -> ModuleNodeMut<'_> {
197            ModuleNodeMut { tree: self, index }
198        }
199
200        /// Creates a new child in this node
201        pub fn add_child(&mut self, parent: usize, name: Sym, is_ty: bool) -> usize {
202            let index = self.parents.len();
203            self.children[parent].insert(name, index);
204            self.parents.push(parent);
205            self.children.push(HashMap::new());
206            self.is_ty.push(is_ty);
207            index
208        }
209
210        /// Binds a new item in this node
211        pub fn add_item(&mut self, node: usize, name: Sym, stack_index: usize) {
212            self.items[node].insert(name, stack_index);
213        }
214
215        /// Creates an arbitrary child edge
216        pub fn add_import(&mut self, parent: usize, name: Sym, child: usize) {
217            self.children[parent].insert(name, child);
218        }
219
220        /// Binds an entire stack frame in this node
221        pub fn add_items(&mut self, node: usize, binds: StackBinds) {
222            self.items[node].extend(binds);
223        }
224
225        /// Binds an arbitrary set of child edges
226        pub fn add_imports(&mut self, node: usize, binds: HashMap<Sym, usize>) {
227            self.children[node].extend(binds);
228        }
229
230        /// Gets this node's parent
231        pub fn parent(&self, node: usize) -> Option<usize> {
232            if node == 0 {
233                return None;
234            }
235            self.parents.get(node).copied()
236        }
237
238        /// Gets the node's "encompassing Type"
239        pub fn selfty(&self, node: usize) -> Option<usize> {
240            if self.is_ty[node] {
241                return Some(node);
242            }
243            self.selfty(self.parent(node)?)
244        }
245
246        /// Gets the child of this node with the given name
247        pub fn child(&self, node: usize, id: &Sym) -> Option<usize> {
248            self.children[node].get(id).copied()
249        }
250
251        /// Gets a stack value in this node with the given name
252        pub fn item(&self, node: usize, name: &Sym) -> Option<usize> {
253            self.items.get(node).and_then(|map| map.get(name).copied())
254        }
255
256        /// Returns a reference to this node's children, if present
257        pub fn children(&self, node: usize) -> Option<&HashMap<Sym, usize>> {
258            self.children.get(node)
259        }
260
261        /// Returns a reference to this node's items, if present
262        pub fn items(&self, node: usize) -> Option<&StackBinds> {
263            self.items.get(node)
264        }
265
266        /// Traverses a path starting at this node
267        ///
268        /// Returns a new node, and the unconsumed path portion.
269        pub fn find<'p>(&self, node: usize, path: &'p [PathPart]) -> (usize, &'p [PathPart]) {
270            match path {
271                [PathPart::SuperKw, tail @ ..] => match self.parent(node) {
272                    Some(node) => self.find(node, tail),
273                    None => (node, path),
274                },
275                [PathPart::Ident(name), tail @ ..] => match self.child(node, name) {
276                    Some(node) => self.find(node, tail),
277                    None => (node, path),
278                },
279                [PathPart::SelfTy, tail @ ..] => match self.selfty(node) {
280                    Some(node) => self.find(node, tail),
281                    None => (node, path),
282                },
283                [] => (node, path),
284            }
285        }
286
287        /// Traverses a path starting at this node
288        ///
289        /// Returns an item address if the path terminated in an item.
290        pub fn find_item(&self, node: usize, path: &[PathPart]) -> Option<usize> {
291            let (node, [PathPart::Ident(name)]) = self.find(node, path) else {
292                return None;
293            };
294            self.item(node, name)
295        }
296    }
297
298    impl Default for ModuleTree {
299        fn default() -> Self {
300            Self::new()
301        }
302    }
303}
304
305pub mod collector {
306    use std::ops::{Deref, DerefMut};
307
308    use crate::{
309        convalue::ConValue,
310        env::Environment,
311        modules::{ModuleNode, ModuleNodeMut},
312    };
313    use cl_ast::{
314        ast_visitor::{Visit, Walk},
315        *,
316    };
317
318    pub struct Collector<'env> {
319        module: usize,
320        env: &'env mut Environment,
321    }
322
323    impl Collector<'_> {
324        pub fn as_node(&self) -> ModuleNode<'_> {
325            self.env.modules().get(self.module)
326        }
327
328        pub fn as_node_mut(&mut self) -> ModuleNodeMut<'_> {
329            self.env.modules_mut().get_mut(self.module)
330        }
331
332        pub fn scope(&mut self, name: Sym, is_ty: bool, f: impl Fn(&mut Collector<'_>)) {
333            let module = match self.as_node_mut().child(&name) {
334                Some(m) => m,
335                None => self.as_node_mut().add_child(name, is_ty),
336            }
337            .index();
338
339            let mut frame = self.env.frame(name.to_ref());
340            f(&mut Collector { env: &mut frame, module });
341            let binds = frame.into_binds().unwrap_or_default();
342
343            self.modules_mut().add_items(module, binds);
344        }
345
346        pub fn in_foreign_scope<F, T>(&mut self, path: &[PathPart], f: F) -> Option<T>
347        where F: Fn(&mut Collector<'_>) -> T {
348            let (module, []) = self.env.modules_mut().find(self.module, path) else {
349                return None;
350            };
351
352            let mut frame = self.env.frame("impl");
353            let out = f(&mut Collector { env: &mut frame, module });
354            let binds = frame.into_binds().unwrap_or_default();
355
356            self.env.modules_mut().add_items(module, binds);
357            Some(out)
358        }
359    }
360
361    impl<'env> Deref for Collector<'env> {
362        type Target = Environment;
363        fn deref(&self) -> &Self::Target {
364            self.env
365        }
366    }
367
368    impl DerefMut for Collector<'_> {
369        fn deref_mut(&mut self) -> &mut Self::Target {
370            self.env
371        }
372    }
373
374    impl<'a, 'env> Visit<'a> for Collector<'env> {
375        fn visit_file(&mut self, value: &'a File) {
376            let mut sorter = ItemSorter::default();
377            sorter.visit(value);
378            sorter.visit_all(self);
379        }
380        fn visit_block(&mut self, value: &'a Block) {
381            let mut sorter = ItemSorter::default();
382            sorter.visit(value);
383            sorter.visit_all(self);
384        }
385        fn visit_module(&mut self, value: &'a cl_ast::Module) {
386            self.scope(value.name, false, |scope| value.children(scope));
387        }
388        fn visit_alias(&mut self, value: &'a cl_ast::Alias) {
389            let Alias { name, from } = value;
390            match from.as_ref().map(Box::as_ref) {
391                Some(Ty { kind: TyKind::Path(path), .. }) => {
392                    let mut node = if path.absolute {
393                        self.modules_mut().get_mut(0)
394                    } else {
395                        self.as_node_mut()
396                    };
397                    if let Some(item) = node.find_item(&path.parts) {
398                        node.add_item(*name, item);
399                    }
400                }
401                Some(other) => todo!("Type expressions in the collector: {other}"),
402                None => self.scope(*name, true, |_| {}),
403            }
404        }
405        fn visit_enum(&mut self, value: &'a cl_ast::Enum) {
406            let Enum { name, gens: _, variants } = value;
407
408            self.scope(*name, true, |frame| {
409                for (idx, Variant { name, kind, body }) in variants.iter().enumerate() {
410                    frame.visit(body);
411                    frame.scope(*name, false, |frame| {
412                        frame.bind("__discriminant", idx as isize);
413                        match kind {
414                            StructKind::Empty => {
415                                frame.insert_tup_constructor("call".into(), 0);
416                                frame.bind("__nmemb", ConValue::Int(0));
417                            }
418                            StructKind::Tuple(args) => {
419                                // Constructs the AST from scratch. TODO: This, better.
420                                frame.insert_tup_constructor("call".into(), args.len());
421                                frame.bind("__nmemb", ConValue::Int(args.len() as _));
422                            }
423                            StructKind::Struct(members) => {
424                                // TODO: more precise type checking of structs
425                                for (idx, memb) in members.iter().enumerate() {
426                                    let StructMember { vis: _, name, ty: _ } = memb;
427                                    frame.bind(*name, idx as isize);
428                                }
429                                frame.bind("__nmemb", ConValue::Int(members.len() as _));
430                            }
431                        }
432                    });
433                }
434            });
435        }
436        fn visit_struct(&mut self, value: &'a cl_ast::Struct) {
437            let Struct { name, gens: _, kind } = value;
438
439            self.scope(*name, true, |frame| {
440                match kind {
441                    StructKind::Empty => {
442                        frame.insert_tup_constructor("call".into(), 0);
443                        frame.bind("__nmemb", ConValue::Int(0));
444                    }
445                    StructKind::Tuple(args) => {
446                        // Constructs the AST from scratch. TODO: This, better.
447                        frame.insert_tup_constructor("call".into(), args.len());
448                        frame.bind("__nmemb", ConValue::Int(args.len() as _));
449                    }
450                    StructKind::Struct(members) => {
451                        // TODO: more precise type checking of structs
452                        for (idx, memb) in members.iter().enumerate() {
453                            let StructMember { vis: _, name, ty: _ } = memb;
454                            frame.bind(*name, idx as isize);
455                        }
456                        frame.bind("__nmemb", ConValue::Int(members.len() as _));
457                    }
458                }
459            });
460        }
461        fn visit_const(&mut self, value: &'a cl_ast::Const) {
462            let Const { name, ty: _, init } = value;
463            self.visit(init);
464            self.bind(*name, ());
465        }
466        fn visit_static(&mut self, value: &'a cl_ast::Static) {
467            let Static { mutable: _, name, ty: _, init } = value;
468            self.visit(init);
469            self.bind(*name, ());
470        }
471        fn visit_function(&mut self, value: &'a cl_ast::Function) {
472            let Function { name, gens: _, sign: _, bind: _, body } = value;
473            self.scope(*name, false, |scope| {
474                scope.visit(body);
475                let f = crate::function::Function::new(value);
476                scope.bind("call", f);
477            });
478        }
479        fn visit_impl(&mut self, value: &'a cl_ast::Impl) {
480            let Impl { gens: _, target: ImplKind::Type(Ty { kind: TyKind::Path(name), .. }), body } =
481                value
482            else {
483                eprintln!("TODO: impl X for Ty");
484                return;
485            };
486            self.in_foreign_scope(&name.parts, |scope| {
487                body.visit_in(scope);
488            });
489        }
490        fn visit_use(&mut self, value: &'a cl_ast::Use) {
491            fn traverse(dest: &mut Collector<'_>, node: usize, tree: &UseTree) {
492                match tree {
493                    UseTree::Tree(ts) => ts.iter().for_each(|tree| traverse(dest, node, tree)),
494                    UseTree::Path(PathPart::Ident(name), tree) => {
495                        if let (node, []) = dest.modules().find(node, &[PathPart::Ident(*name)]) {
496                            traverse(dest, node, tree)
497                        }
498                    }
499                    UseTree::Path(PathPart::SuperKw, tree) => {
500                        if let Some(node) = dest.modules().parent(node) {
501                            traverse(dest, node, tree)
502                        }
503                    }
504                    UseTree::Path(PathPart::SelfTy, tree) => {
505                        if let Some(node) = dest.modules().selfty(node) {
506                            traverse(dest, node, tree)
507                        }
508                    }
509                    UseTree::Alias(name, as_name) => {
510                        if let Some(child) = dest.modules().child(node, name) {
511                            dest.as_node_mut().add_import(*as_name, child);
512                        }
513                        if let Some(item) = dest.modules().item(node, name) {
514                            dest.as_node_mut().add_item(*as_name, item);
515                        }
516                    }
517                    UseTree::Name(name) => {
518                        if let Some(child) = dest.modules().child(node, name) {
519                            dest.as_node_mut().add_import(*name, child);
520                        }
521                        if let Some(item) = dest.modules().item(node, name) {
522                            dest.as_node_mut().add_item(*name, item);
523                        }
524                    }
525                    UseTree::Glob => {
526                        let &mut Collector { module, ref mut env } = dest;
527                        if let Some(children) = env.modules().children(node) {
528                            for (name, index) in children.clone() {
529                                env.modules_mut().add_import(module, name, index);
530                            }
531                        }
532                        if let Some(items) = env.modules().items(node).cloned() {
533                            env.modules_mut().add_items(node, items);
534                        }
535                    }
536                }
537            }
538
539            let Use { absolute, tree } = value;
540            let node = if *absolute { 0 } else { self.module };
541            traverse(self, node, tree);
542        }
543    }
544
545    // fn make_tuple_constructor(name: Sym, args: &[Ty]) -> ConValue {
546    //     let span = match (
547    //         args.first().map(|a| a.span.head),
548    //         args.last().map(|a| a.span.tail),
549    //     ) {
550    //         (Some(head), Some(tail)) => Span(head, tail),
551    //         _ => Span::dummy(),
552    //     };
553
554    //     let constructor = Function {
555    //         name,
556    //         gens: Default::default(),
557    //         sign: TyFn {
558    //             args: Ty { kind: TyKind::Tuple(TyTuple { types: args.to_vec() }), span }.into(),
559    //             rety: Some(Ty { span: Span::dummy(), kind: TyKind::Path(Path::from(name))
560    // }.into()),         },
561    //         bind: Pattern::Tuple(
562    //             args.iter()
563    //                 .enumerate()
564    //                 .map(|(idx, _)| Pattern::Name(idx.to_string().into()))
565    //                 .collect(),
566    //         ),
567    //         body: None,
568    //     };
569    //     // ConValue::TupleConstructor(crate::constructor::Constructor {ind})
570    //     todo!("Tuple constructor {constructor}")
571    // }
572
573    /// Sorts items
574    #[derive(Debug, Default)]
575    struct ItemSorter<'ast> {
576        modules: Vec<&'ast Module>,
577        structs: Vec<&'ast Struct>,
578        enums: Vec<&'ast Enum>,
579        aliases: Vec<&'ast Alias>,
580        consts: Vec<&'ast Const>,
581        statics: Vec<&'ast Static>,
582        functions: Vec<&'ast Function>,
583        impls: Vec<&'ast Impl>,
584        imports: Vec<&'ast Use>,
585    }
586
587    impl<'a> ItemSorter<'a> {
588        fn visit_all<V: Visit<'a>>(&self, v: &mut V) {
589            let Self {
590                modules,
591                aliases,
592                enums,
593                structs,
594                consts,
595                statics,
596                functions,
597                impls,
598                imports,
599            } = self;
600
601            // 0
602            for item in modules {
603                item.visit_in(v);
604            }
605            // 1
606            for item in structs {
607                item.visit_in(v);
608            }
609            for item in enums {
610                item.visit_in(v);
611            }
612            for item in aliases {
613                item.visit_in(v);
614            }
615            // 2
616            // 5
617            for item in consts {
618                item.visit_in(v);
619            }
620            for item in statics {
621                item.visit_in(v);
622            }
623            for item in functions {
624                item.visit_in(v);
625            }
626            // 4
627            for item in impls {
628                item.visit_in(v);
629            }
630            // 3
631            for item in imports {
632                item.visit_in(v);
633            }
634        }
635    }
636
637    impl<'a> Visit<'a> for ItemSorter<'a> {
638        fn visit_module(&mut self, value: &'a cl_ast::Module) {
639            self.modules.push(value);
640        }
641        fn visit_alias(&mut self, value: &'a cl_ast::Alias) {
642            self.aliases.push(value);
643        }
644        fn visit_enum(&mut self, value: &'a cl_ast::Enum) {
645            self.enums.push(value);
646        }
647        fn visit_struct(&mut self, value: &'a cl_ast::Struct) {
648            self.structs.push(value);
649        }
650        fn visit_const(&mut self, value: &'a cl_ast::Const) {
651            self.consts.push(value);
652        }
653        fn visit_static(&mut self, value: &'a cl_ast::Static) {
654            self.statics.push(value);
655        }
656        fn visit_function(&mut self, value: &'a cl_ast::Function) {
657            self.functions.push(value);
658        }
659        fn visit_impl(&mut self, value: &'a cl_ast::Impl) {
660            self.impls.push(value);
661        }
662        fn visit_use(&mut self, value: &'a cl_ast::Use) {
663            self.imports.push(value);
664        }
665    }
666}
667
668pub mod error;
669
670#[cfg(test)]
671mod tests;