From edabbe165530b22a6c1df3da1367af301451a16f Mon Sep 17 00:00:00 2001 From: John Date: Tue, 18 Feb 2025 21:44:52 -0600 Subject: [PATCH] cl-interpret: process use items and imports in the interpreter --- compiler/cl-ast/src/ast.rs | 1 - compiler/cl-interpret/src/env.rs | 4 +- compiler/cl-interpret/src/function.rs | 2 +- compiler/cl-interpret/src/interpret.rs | 74 ++++++++++++++++++++++++-- compiler/cl-parser/src/parser.rs | 6 ++- sample-code/hex.cl | 1 + 6 files changed, 78 insertions(+), 10 deletions(-) diff --git a/compiler/cl-ast/src/ast.rs b/compiler/cl-ast/src/ast.rs index 1857bc0..1cf907f 100644 --- a/compiler/cl-ast/src/ast.rs +++ b/compiler/cl-ast/src/ast.rs @@ -81,7 +81,6 @@ pub struct Item { /// What kind of [Item] is this? #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub enum ItemKind { - // TODO: Import declaration ("use") item // TODO: Trait declaration ("trait") item? /// A [module](Module) Module(Module), diff --git a/compiler/cl-interpret/src/env.rs b/compiler/cl-interpret/src/env.rs index 123aba6..bda18d8 100644 --- a/compiler/cl-interpret/src/env.rs +++ b/compiler/cl-interpret/src/env.rs @@ -97,8 +97,8 @@ impl Environment { self.frames.push((frame, name)); } - pub fn pop_frame(&mut self) -> Option { - self.frames.pop().map(|f| f.0) + pub fn pop_frame(&mut self) -> Option<(StackFrame, &'static str)> { + self.frames.pop() } pub fn eval(&mut self, node: &impl Interpret) -> IResult { diff --git a/compiler/cl-interpret/src/function.rs b/compiler/cl-interpret/src/function.rs index ea771bb..bd6b37a 100644 --- a/compiler/cl-interpret/src/function.rs +++ b/compiler/cl-interpret/src/function.rs @@ -68,7 +68,7 @@ impl Callable for Function { } let res = body.interpret(&mut frame); drop(frame); - if let Some(upvars) = env.pop_frame() { + if let Some((upvars, _)) = env.pop_frame() { self.upvars.replace(upvars); } match res { diff --git a/compiler/cl-interpret/src/interpret.rs b/compiler/cl-interpret/src/interpret.rs index 3c2bcf0..1ad7256 100644 --- a/compiler/cl-interpret/src/interpret.rs +++ b/compiler/cl-interpret/src/interpret.rs @@ -37,10 +37,7 @@ impl Interpret for Item { ItemKind::Struct(item) => item.interpret(env), ItemKind::Enum(item) => item.interpret(env), ItemKind::Impl(item) => item.interpret(env), - ItemKind::Use(item) => { - eprintln!("TODO: namespaces and imports in the interpreter!\n{item}\n"); - Ok(ConValue::Empty) - } + ItemKind::Use(item) => item.interpret(env), } } } @@ -80,7 +77,7 @@ impl Interpret for Module { } }; - let frame = env + let (frame, _) = env .pop_frame() .expect("Environment frames must be balanced"); env.insert(*name, Some(ConValue::Module(frame.into()))); @@ -114,6 +111,73 @@ impl Interpret for Impl { body.interpret(env) } } + +impl Interpret for Use { + fn interpret(&self, env: &mut Environment) -> IResult { + let Self { absolute: _, tree } = self; + tree.interpret(env) + } +} + +impl Interpret for UseTree { + fn interpret(&self, env: &mut Environment) -> IResult { + type Bindings = HashMap; + use std::collections::HashMap; + + fn get_bindings( + tree: &UseTree, + env: &mut Environment, + bindings: &mut Bindings, + ) -> IResult<()> { + match tree { + UseTree::Tree(use_trees) => { + for tree in use_trees { + get_bindings(tree, env, bindings)?; + } + } + UseTree::Path(PathPart::Ident(name), tree) => { + let Ok(ConValue::Module(m)) = env.get(*name) else { + Err(Error::TypeError)? + }; + env.push_frame(Interned::to_ref(name), *m); + let out = get_bindings(tree, env, bindings); + env.pop_frame(); + return out; + } + UseTree::Alias(name, alias) => { + bindings.insert(*alias, env.get(*name)?); + } + UseTree::Name(name) => { + bindings.insert(*name, env.get(*name)?); + } + UseTree::Glob => { + if let Some((frame, name)) = env.pop_frame() { + for (k, v) in &frame { + if let Some(v) = v { + bindings.insert(*k, v.clone()); + } + } + env.push_frame(name, frame); + } + } + other => { + eprintln!("ERROR: Cannot use {other}"); + } + } + Ok(()) + } + + let mut bindings = Bindings::new(); + get_bindings(self, env, &mut bindings)?; + + for (name, value) in bindings { + env.insert(name, Some(value)); + } + + Ok(ConValue::Empty) + } +} + impl Interpret for Stmt { fn interpret(&self, env: &mut Environment) -> IResult { let Self { extents: _, kind, semi } = self; diff --git a/compiler/cl-parser/src/parser.rs b/compiler/cl-parser/src/parser.rs index f1c7785..f2d649e 100644 --- a/compiler/cl-parser/src/parser.rs +++ b/compiler/cl-parser/src/parser.rs @@ -681,7 +681,11 @@ impl Parse<'_> for UseTree { let PathPart::Ident(name) = name else { Err(p.error(ErrorKind::ExpectedParsing { want: Parsing::Identifier }, P))? }; - UseTree::Name(name) + if p.match_type(TokenKind::As, P).is_ok() { + UseTree::Alias(name, p.parse()?) + } else { + UseTree::Name(name) + } } } t => Err(p.error(Unexpected(t), Parsing::UseTree))?, diff --git a/sample-code/hex.cl b/sample-code/hex.cl index 95db8c5..4bb0913 100644 --- a/sample-code/hex.cl +++ b/sample-code/hex.cl @@ -1,5 +1,6 @@ //! Formats numbers in hexadecimal, octal, or binary mod math; +use math::{min, count_leading_zeroes}; fn as_digit(n: u32) -> char { (if n > 9 {