forked from AbleScript/ablescript
Reimplemented Melo
- Variable made into enum of `ValueRef or Melo` - Melo-ing variable causes dropping of the Rc, decreasing reference count
This commit is contained in:
parent
57bbc44b82
commit
a103a6e7f6
|
@ -198,7 +198,9 @@ impl ExecEnv {
|
|||
|
||||
// TODO: not too happy with constructing an artificial
|
||||
// Ident here.
|
||||
Variable(name) => self.get_var(&Spanned::new(name.to_owned(), expr.span.clone()))?,
|
||||
Variable(name) => {
|
||||
self.get_var_value(&Spanned::new(name.to_owned(), expr.span.clone()))?
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -275,7 +277,7 @@ impl ExecEnv {
|
|||
return Ok(HaltStatus::Hopback(stmt.span.clone()));
|
||||
}
|
||||
Stmt::Melo(ident) => {
|
||||
self.get_var_mut(ident)?.melo = true;
|
||||
*self.get_var_mut(ident)? = Variable::Melo;
|
||||
}
|
||||
Stmt::Rlyeh => {
|
||||
// Maybe print a creepy error message or something
|
||||
|
@ -305,7 +307,7 @@ impl ExecEnv {
|
|||
fn assign(&mut self, dest: &Assignable, value: Value) -> Result<(), Error> {
|
||||
match dest.kind {
|
||||
AssignableKind::Variable => {
|
||||
self.get_var_mut(&dest.ident)?.value.replace(value);
|
||||
self.get_var_rc(&dest.ident)?.replace(value);
|
||||
}
|
||||
AssignableKind::Index { ref indices } => {
|
||||
let mut cell = self.get_var_rc(&dest.ident)?;
|
||||
|
@ -514,7 +516,7 @@ impl ExecEnv {
|
|||
|
||||
/// Get the value of a variable. Throw an error if the variable is
|
||||
/// inaccessible or banned.
|
||||
fn get_var(&self, name: &Spanned<String>) -> Result<Value, Error> {
|
||||
fn get_var_value(&self, name: &Spanned<String>) -> Result<Value, Error> {
|
||||
// Search for the name in the stack from top to bottom.
|
||||
match self
|
||||
.stack
|
||||
|
@ -522,16 +524,11 @@ impl ExecEnv {
|
|||
.rev()
|
||||
.find_map(|scope| scope.variables.get(&name.item))
|
||||
{
|
||||
Some(var) => {
|
||||
if !var.melo {
|
||||
Ok(var.value.borrow().clone())
|
||||
} else {
|
||||
Err(Error {
|
||||
Some(Variable::Ref(r)) => Ok(r.borrow().clone()),
|
||||
Some(Variable::Melo) => Err(Error {
|
||||
kind: ErrorKind::MeloVariable(name.item.to_owned()),
|
||||
span: name.span.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
}),
|
||||
None => Err(Error {
|
||||
kind: ErrorKind::UnknownVariable(name.item.to_owned()),
|
||||
span: name.span.clone(),
|
||||
|
@ -550,16 +547,7 @@ impl ExecEnv {
|
|||
.rev()
|
||||
.find_map(|scope| scope.variables.get_mut(&name.item))
|
||||
{
|
||||
Some(var) => {
|
||||
if !var.melo {
|
||||
Ok(var)
|
||||
} else {
|
||||
Err(Error {
|
||||
kind: ErrorKind::MeloVariable(name.item.to_owned()),
|
||||
span: name.span.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
Some(var) => Ok(var),
|
||||
None => Err(Error {
|
||||
kind: ErrorKind::UnknownVariable(name.item.to_owned()),
|
||||
span: name.span.clone(),
|
||||
|
@ -570,7 +558,13 @@ impl ExecEnv {
|
|||
/// 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: &Spanned<String>) -> Result<ValueRef, Error> {
|
||||
Ok(self.get_var_mut(name)?.value.clone())
|
||||
match self.get_var_mut(name)? {
|
||||
Variable::Ref(r) => Ok(r.clone()),
|
||||
Variable::Melo => Err(Error {
|
||||
kind: ErrorKind::MeloVariable(name.item.to_owned()),
|
||||
span: name.span.clone(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Declare a new variable, with the given initial value.
|
||||
|
@ -585,7 +579,7 @@ impl ExecEnv {
|
|||
.last()
|
||||
.expect("Declaring variable on empty stack")
|
||||
.variables
|
||||
.insert(name.to_owned(), Variable { melo: false, value });
|
||||
.insert(name.to_owned(), Variable::Ref(value));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -709,7 +703,7 @@ mod tests {
|
|||
// Declaring and reading from a variable.
|
||||
eval(&mut env, "dim foo 32; dim bar foo + 1;").unwrap();
|
||||
assert_eq!(
|
||||
env.get_var(&Spanned {
|
||||
env.get_var_value(&Spanned {
|
||||
item: "bar".to_owned(),
|
||||
span: 1..1,
|
||||
})
|
||||
|
@ -720,7 +714,7 @@ mod tests {
|
|||
// Assigning an existing variable.
|
||||
eval(&mut env, "/*hi*/ =: foo;").unwrap();
|
||||
assert_eq!(
|
||||
env.get_var(&Spanned {
|
||||
env.get_var_value(&Spanned {
|
||||
item: "foo".to_owned(),
|
||||
span: 1..1,
|
||||
})
|
||||
|
@ -746,7 +740,7 @@ mod tests {
|
|||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
env.get_var(&Spanned {
|
||||
env.get_var_value(&Spanned {
|
||||
item: "foo".to_owned(),
|
||||
span: 1..1,
|
||||
})
|
||||
|
|
|
@ -971,19 +971,13 @@ impl ValueRef {
|
|||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Variable {
|
||||
pub melo: bool,
|
||||
|
||||
// Multiple Variables can reference the same underlying Value when
|
||||
// pass-by-reference is used, therefore we use Rc here.
|
||||
pub value: ValueRef,
|
||||
pub enum Variable {
|
||||
Ref(ValueRef),
|
||||
Melo,
|
||||
}
|
||||
|
||||
impl Variable {
|
||||
pub fn from_value(value: Value) -> Self {
|
||||
Self {
|
||||
melo: false,
|
||||
value: ValueRef::new(value),
|
||||
}
|
||||
Self::Ref(ValueRef::new(value))
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue