From 5ac911765196f134fcb61f4208815b754d9b499e Mon Sep 17 00:00:00 2001 From: Alex Bethel Date: Sun, 13 Jun 2021 12:06:38 -0500 Subject: [PATCH] Implement most of pass-by-reference We need some parser changes to make it work fully: function arguments are now identifiers rather than expressions. --- src/ast.rs | 6 +++++- src/interpret.rs | 40 +++++++++++++++++++++++++++------------- src/parser.rs | 5 ++++- src/variables.rs | 7 +++++-- 4 files changed, 41 insertions(+), 17 deletions(-) diff --git a/src/ast.rs b/src/ast.rs index 835e679f..dcc1d2fa 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -70,7 +70,11 @@ pub enum StmtKind { }, Call { iden: Iden, - args: Vec, + + // NOTE(Alex): Function arguments are Iden's, not Expr's, + // because they're passed by reference rather than by value + // and therefore need to be assignable. + args: Vec, }, Print(Expr), Melo(Iden), diff --git a/src/interpret.rs b/src/interpret.rs index 28f792f4..b81ac7c4 100644 --- a/src/interpret.rs +++ b/src/interpret.rs @@ -6,12 +6,14 @@ //! AbleScript snippet. You can then call [ExecEnv::eval_stmts] to //! evaluate or execute any number of expressions or statements. -#[deny(missing_docs)] +#![deny(missing_docs)] use std::{ + cell::RefCell, collections::HashMap, io::{stdout, Write}, ops::Range, process::exit, + rc::Rc, usize, }; @@ -238,13 +240,8 @@ impl ExecEnv { StmtKind::Call { iden, args } => { let func = self.get_var(&iden)?; - let args = args - .iter() - .map(|arg| self.eval_expr(arg)) - .collect::>()?; - if let Value::Functio(func) = func { - self.fn_call(func, args, &stmt.span)?; + self.fn_call(func, &args, &stmt.span)?; } else { return Err(Error { kind: ErrorKind::TypeError(iden.iden.to_owned()), @@ -261,7 +258,8 @@ impl ExecEnv { } }, StmtKind::Assign { iden, value } => { - self.get_var_mut(&iden)?.value = self.eval_expr(value)?; + let value = self.eval_expr(value)?; + self.get_var_mut(&iden)?.value.replace(value); } StmtKind::Break => { return Ok(HaltStatus::Break(stmt.span.clone())); @@ -291,9 +289,14 @@ impl ExecEnv { fn fn_call( &mut self, func: Functio, - args: Vec, + args: &[Iden], span: &Range, ) -> Result<(), Error> { + let args = args + .iter() + .map(|arg| self.get_var_rc(arg)) + .collect::>>, Error>>()?; + match func { Functio::BfFunctio { instructions, @@ -301,7 +304,7 @@ impl ExecEnv { } => { let mut input: Vec = vec![]; for arg in args { - arg.bf_write(&mut input); + arg.borrow().bf_write(&mut input); } println!("input = {:?}", input); let mut output = vec![]; @@ -332,7 +335,7 @@ impl ExecEnv { self.stack.push(Default::default()); for (param, arg) in params.iter().zip(args.iter()) { - self.decl_var(param, arg.to_owned()); + self.decl_var_shared(param, arg.to_owned()); } let res = self.eval_stmts_hs(&body, false); @@ -363,7 +366,7 @@ impl ExecEnv { { Some(var) => { if !var.melo { - Ok(var.value.clone()) + Ok(var.value.borrow().clone()) } else { Err(Error { kind: ErrorKind::MeloVariable(name.iden.to_owned()), @@ -406,8 +409,19 @@ impl ExecEnv { } } - /// Declares a new variable, with the given initial value. + /// Get an Rc'd pointer to the value of a variable. Throw an error + /// if the variable is inaccessible or banned. + fn get_var_rc(&mut self, name: &Iden) -> Result>, Error> { + Ok(self.get_var_mut(name)?.value.clone()) + } + + /// Declare a new variable, with the given initial value. fn decl_var(&mut self, name: &str, value: Value) { + self.decl_var_shared(name, Rc::new(RefCell::new(value))); + } + + /// Declare a new variable, with the given shared initial value. + fn decl_var_shared(&mut self, name: &str, value: Rc>) { self.stack .iter_mut() .last() diff --git a/src/parser.rs b/src/parser.rs index 53b4cee4..3d8797af 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -469,7 +469,10 @@ impl<'source> Parser<'source> { } self.require(Token::Semicolon)?; - Ok(StmtKind::Call { iden, args }) + // Ok(StmtKind::Call { iden, args }) + + // `args` needs to be a vector of Idens now. ~~Alex + todo!() } /// Parse variable declaration diff --git a/src/variables.rs b/src/variables.rs index 89f14c54..6492cae6 100644 --- a/src/variables.rs +++ b/src/variables.rs @@ -1,4 +1,4 @@ -use std::{fmt::Display, io::Write, ops::Range}; +use std::{cell::RefCell, fmt::Display, io::Write, ops::Range, rc::Rc}; use rand::Rng; @@ -191,5 +191,8 @@ impl Display for Value { #[derive(Debug)] pub struct Variable { pub melo: bool, - pub value: Value, + + // Multiple Variables can reference the same underlying Value when + // pass-by-reference is used, therefore we use Rc here. + pub value: Rc>, }