interpreter: fix variable resolution and assignment
This commit is contained in:
parent
56f0550829
commit
99ade72756
@ -351,21 +351,25 @@ impl Interpret for Operation {
|
|||||||
impl Interpret for Assign {
|
impl Interpret for Assign {
|
||||||
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
||||||
use operator::Assign;
|
use operator::Assign;
|
||||||
let math::Assign { target, operator, init } = self;
|
let math::Assign { target: Identifier { name, .. }, operator, init } = self;
|
||||||
let init = init.interpret(env)?;
|
let init = init.interpret(env)?;
|
||||||
let target = env.get_mut(&target.name)?;
|
let target = env.get_mut(name)?;
|
||||||
|
|
||||||
if let Assign::Assign = operator {
|
if let Assign::Assign = operator {
|
||||||
use std::mem::discriminant as variant;
|
use std::mem::discriminant as variant;
|
||||||
// runtime typecheck
|
// runtime typecheck
|
||||||
match target {
|
match target {
|
||||||
value if variant(value) == variant(&init) => {
|
Some(value) if variant(value) == variant(&init) => {
|
||||||
*value = init;
|
*value = init;
|
||||||
}
|
}
|
||||||
|
value @ None => *value = Some(init),
|
||||||
_ => Err(Error::TypeError)?,
|
_ => Err(Error::TypeError)?,
|
||||||
}
|
}
|
||||||
return Ok(ConValue::Empty);
|
return Ok(ConValue::Empty);
|
||||||
}
|
}
|
||||||
|
let Some(target) = target else {
|
||||||
|
return Err(Error::NotInitialized(name.into()));
|
||||||
|
};
|
||||||
|
|
||||||
match operator {
|
match operator {
|
||||||
Assign::AddAssign => target.add_assign(init)?,
|
Assign::AddAssign => target.add_assign(init)?,
|
||||||
@ -803,22 +807,22 @@ pub mod env {
|
|||||||
pub fn frame(&mut self, name: &'static str) -> Frame {
|
pub fn frame(&mut self, name: &'static str) -> Frame {
|
||||||
Frame::new(self, name)
|
Frame::new(self, name)
|
||||||
}
|
}
|
||||||
/// Resolves a variable mutably
|
/// Resolves a variable mutably.
|
||||||
///
|
///
|
||||||
/// Returns a mutable reference to the variable's record, if it exists
|
/// Returns a mutable reference to the variable's record, if it exists.
|
||||||
pub fn get_mut(&mut self, id: &str) -> IResult<&mut ConValue> {
|
pub fn get_mut(&mut self, id: &str) -> IResult<&mut Option<ConValue>> {
|
||||||
for (frame, _) in self.frames.iter_mut() {
|
for (frame, _) in self.frames.iter_mut().rev() {
|
||||||
match frame.get_mut(id) {
|
if let Some(var) = frame.get_mut(id) {
|
||||||
Some(Some(var)) => return Ok(var),
|
return Ok(var);
|
||||||
Some(None) => return Err(Error::NotInitialized(id.into())),
|
|
||||||
_ => (),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(Error::NotDefined(id.into()))
|
Err(Error::NotDefined(id.into()))
|
||||||
}
|
}
|
||||||
/// Resolves a variable immutably
|
/// Resolves a variable immutably.
|
||||||
|
///
|
||||||
|
/// Returns a reference to the variable's contents, if it is defined and initialized.
|
||||||
pub fn get(&self, id: &str) -> IResult<&ConValue> {
|
pub fn get(&self, id: &str) -> IResult<&ConValue> {
|
||||||
for (frame, _) in self.frames.iter() {
|
for (frame, _) in self.frames.iter().rev() {
|
||||||
match frame.get(id) {
|
match frame.get(id) {
|
||||||
Some(Some(var)) => return Ok(var),
|
Some(Some(var)) => return Ok(var),
|
||||||
Some(None) => return Err(Error::NotInitialized(id.into())),
|
Some(None) => return Err(Error::NotInitialized(id.into())),
|
||||||
|
Loading…
Reference in New Issue
Block a user