forked from AbleScript/ablescript
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:
parent
4b0aa1602b
commit
66d4f4f82d
|
@ -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),
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>>,
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue