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 4b0aa1602b
commit 66d4f4f82d
4 changed files with 41 additions and 17 deletions

View file

@ -70,7 +70,11 @@ pub enum StmtKind {
},
Call {
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),
Melo(Iden),

View file

@ -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::<Result<_, _>>()?;
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<Value>,
args: &[Iden],
span: &Range<usize>,
) -> Result<(), Error> {
let args = args
.iter()
.map(|arg| self.get_var_rc(arg))
.collect::<Result<Vec<Rc<RefCell<Value>>>, Error>>()?;
match func {
Functio::BfFunctio {
instructions,
@ -301,7 +304,7 @@ impl ExecEnv {
} => {
let mut input: Vec<u8> = 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<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) {
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
.iter_mut()
.last()

View file

@ -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

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;
@ -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<RefCell<Value>>,
}