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 {
|
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),
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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>>,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue