Implement most of pass-by-reference

We need some parser changes to make it work fully: function arguments
are now identifiers rather than expressions.
This commit is contained in:
Alex Bethel 2021-06-13 12:06:38 -05:00
parent f06fba1741
commit 5ac9117651
4 changed files with 41 additions and 17 deletions

View file

@ -70,7 +70,11 @@ pub enum StmtKind {
}, },
Call { Call {
iden: Iden, iden: Iden,
args: Vec<Expr>,
// 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<Iden>,
}, },
Print(Expr), Print(Expr),
Melo(Iden), Melo(Iden),

View file

@ -6,12 +6,14 @@
//! AbleScript snippet. You can then call [ExecEnv::eval_stmts] to //! AbleScript snippet. You can then call [ExecEnv::eval_stmts] to
//! evaluate or execute any number of expressions or statements. //! evaluate or execute any number of expressions or statements.
#[deny(missing_docs)] #![deny(missing_docs)]
use std::{ use std::{
cell::RefCell,
collections::HashMap, collections::HashMap,
io::{stdout, Write}, io::{stdout, Write},
ops::Range, ops::Range,
process::exit, process::exit,
rc::Rc,
usize, usize,
}; };
@ -238,13 +240,8 @@ impl ExecEnv {
StmtKind::Call { iden, args } => { StmtKind::Call { iden, args } => {
let func = self.get_var(&iden)?; let func = self.get_var(&iden)?;
let args = args
.iter()
.map(|arg| self.eval_expr(arg))
.collect::<Result<_, _>>()?;
if let Value::Functio(func) = func { if let Value::Functio(func) = func {
self.fn_call(func, args, &stmt.span)?; self.fn_call(func, &args, &stmt.span)?;
} else { } else {
return Err(Error { return Err(Error {
kind: ErrorKind::TypeError(iden.iden.to_owned()), kind: ErrorKind::TypeError(iden.iden.to_owned()),
@ -261,7 +258,8 @@ impl ExecEnv {
} }
}, },
StmtKind::Assign { iden, value } => { 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 => { StmtKind::Break => {
return Ok(HaltStatus::Break(stmt.span.clone())); return Ok(HaltStatus::Break(stmt.span.clone()));
@ -291,9 +289,14 @@ impl ExecEnv {
fn fn_call( fn fn_call(
&mut self, &mut self,
func: Functio, func: Functio,
args: Vec<Value>, args: &[Iden],
span: &Range<usize>, span: &Range<usize>,
) -> Result<(), Error> { ) -> Result<(), Error> {
let args = args
.iter()
.map(|arg| self.get_var_rc(arg))
.collect::<Result<Vec<Rc<RefCell<Value>>>, Error>>()?;
match func { match func {
Functio::BfFunctio { Functio::BfFunctio {
instructions, instructions,
@ -301,7 +304,7 @@ impl ExecEnv {
} => { } => {
let mut input: Vec<u8> = vec![]; let mut input: Vec<u8> = vec![];
for arg in args { for arg in args {
arg.bf_write(&mut input); arg.borrow().bf_write(&mut input);
} }
println!("input = {:?}", input); println!("input = {:?}", input);
let mut output = vec![]; let mut output = vec![];
@ -332,7 +335,7 @@ impl ExecEnv {
self.stack.push(Default::default()); self.stack.push(Default::default());
for (param, arg) in params.iter().zip(args.iter()) { 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); let res = self.eval_stmts_hs(&body, false);
@ -363,7 +366,7 @@ impl ExecEnv {
{ {
Some(var) => { Some(var) => {
if !var.melo { if !var.melo {
Ok(var.value.clone()) Ok(var.value.borrow().clone())
} else { } else {
Err(Error { Err(Error {
kind: ErrorKind::MeloVariable(name.iden.to_owned()), 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<Rc<RefCell<Value>>, 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) { 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<RefCell<Value>>) {
self.stack self.stack
.iter_mut() .iter_mut()
.last() .last()

View file

@ -469,7 +469,10 @@ impl<'source> Parser<'source> {
} }
self.require(Token::Semicolon)?; 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 /// Parse variable declaration

View file

@ -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; use rand::Rng;
@ -191,5 +191,8 @@ impl Display for Value {
#[derive(Debug)] #[derive(Debug)]
pub struct Variable { pub struct Variable {
pub melo: bool, 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<RefCell<Value>>,
} }