From 76b17b4eeb180550d8dd36177253a780d5ed8634 Mon Sep 17 00:00:00 2001 From: Cassie Jones Date: Thu, 27 Feb 2020 18:27:37 +0100 Subject: [PATCH] Add support for globals which don't get captured Lots of top-level definitions don't need to be copied into every closure, because they're constant for the whole program. Global variables are never inserted into the upvars entry, so they won't be copied into closures. This also adds "builtin" names that are inserted into the initial context for arithmetic and comparisons. Booleans have to be builtin due to being returned by the comparisons, but they're still intended to be implemented via church encoding. --- src/ast.rs | 38 ++++++++++++++++++++++++++++++++------ src/main.rs | 5 ++++- 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/src/ast.rs b/src/ast.rs index 597c6de..4a0fe8f 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -6,7 +6,19 @@ use std::{ }; #[derive(PartialEq, Eq, Clone, Copy, Debug)] -pub struct Name(u32); +pub enum Name { + Local(u32), + Global(u32), +} + +impl Name { + pub fn local(&self) -> bool { + match self { + Name::Local(_) => true, + Name::Global(_) => false, + } + } +} #[derive(PartialEq, Clone, Debug)] pub enum Ast { @@ -48,7 +60,11 @@ impl Env<'_> { } fn fresh(&mut self, text: &str) -> Name { - let name = Name(*self.fresh.get_mut()); + let name = if self.up.is_some() { + Name::Local(*self.fresh.get_mut()) + } else { + Name::Global(*self.fresh.get_mut()) + }; self.vars.insert(text.into(), name); *self.fresh.get_mut() += 1; name @@ -59,7 +75,9 @@ impl Env<'_> { return Some(resolved); } self.up.and_then(|up| up._get(name)).map(|resolved| { - self.upvars.borrow_mut().insert(name.into(), resolved); + if resolved.local() { + self.upvars.borrow_mut().insert(name.into(), resolved); + } resolved }) } @@ -70,7 +88,9 @@ impl Env<'_> { } self.up.and_then(|up| up._get(name)).map(|resolved| { self.vars.insert(name.into(), resolved); - self.upvars.get_mut().insert(name.into(), resolved); + if resolved.local() { + self.upvars.get_mut().insert(name.into(), resolved); + } resolved }) } @@ -89,8 +109,14 @@ impl Drop for Env<'_> { } impl Ast { - pub fn parse(sexp: &Sexp) -> Result { - Ast::from_sexp(&mut Env::new(), sexp) + pub fn parse(builtins: &[impl AsRef], sexp: &Sexp) -> Result<(Ast, HashMap), &'static str> { + let mut env = Env::new(); + let mut builtin_map = HashMap::new(); + for builtin in builtins { + let builtin = builtin.as_ref(); + builtin_map.insert(builtin.into(), env.fresh(builtin)); + } + Ok((Ast::from_sexp(&mut env, sexp)?, builtin_map)) } fn from_sexp<'r, 'e: 'r>(env: &'r mut Env<'e>, sexp: &Sexp) -> Result { diff --git a/src/main.rs b/src/main.rs index 3328b00..6099fb6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,6 +12,8 @@ fn parse(input: &str) -> Result { Ok(sexp) } +static BUILTINS: &[&str] = &["true", "false", "<", ">", "<=", ">=", "==", "!=", "+", "-", "*", "/", "%"]; + fn main() -> io::Result<()> { let stdin = std::io::stdin(); let mut text = String::new(); @@ -23,13 +25,14 @@ fn main() -> io::Result<()> { std::process::exit(1); } }; - let ast = match Ast::parse(&sexp) { + let (ast, builtins) = match Ast::parse(BUILTINS, &sexp) { Ok(ast) => ast, Err(err) => { println!("{}", err); std::process::exit(1); } }; + println!("builtins: {:?}", builtins); println!("{:#?}", ast); Ok(()) } -- 2.43.2