Add Binder helper for binding variables and then unbinding them afterwards
This commit is contained in:
parent
3b369200aa
commit
cbfdece2cb
@ -110,6 +110,41 @@ impl Clone for Value {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct Binder {
|
||||
variables_to_unbind: Vec<String>,
|
||||
}
|
||||
|
||||
impl Binder {
|
||||
pub fn new() -> Self {
|
||||
Binder {
|
||||
variables_to_unbind: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bind(
|
||||
&mut self,
|
||||
variables: &mut BTreeMap<String, Value>,
|
||||
binding: &Binding,
|
||||
value: Value,
|
||||
) {
|
||||
// TODO duplicated code
|
||||
match binding {
|
||||
Binding::Variable(var_name) => {
|
||||
let var_name = String::from(var_name as &str);
|
||||
variables.insert(var_name.clone(), value);
|
||||
self.variables_to_unbind.push(var_name);
|
||||
}
|
||||
Binding::Ignore => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unbind(self, variables: &mut BTreeMap<String, Value>) {
|
||||
for var_name in self.variables_to_unbind {
|
||||
variables.remove(&var_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, O: OutputSystem + Send, LS: LocalisationSystem + Sync + Send> Interpreter<'a, O, LS> {
|
||||
#[async_recursion]
|
||||
pub async fn run_steps(
|
||||
@ -197,25 +232,10 @@ impl<'a, O: OutputSystem + Send, LS: LocalisationSystem + Sync + Send> Interpret
|
||||
self.run_steps(scope_idx, empty_steps).await?;
|
||||
} else {
|
||||
for val in list {
|
||||
// TODO duplicated code
|
||||
match binding {
|
||||
Binding::Variable(var) => {
|
||||
self.scopes[scope_idx]
|
||||
.variables
|
||||
.insert(String::from(var as &str), val);
|
||||
}
|
||||
Binding::Ignore => {}
|
||||
}
|
||||
|
||||
let mut binder = Binder::new();
|
||||
binder.bind(&mut self.scopes[scope_idx].variables, &binding, val);
|
||||
self.run_steps(scope_idx, body_steps).await?;
|
||||
}
|
||||
|
||||
// TODO duplicated code
|
||||
match binding {
|
||||
Binding::Variable(var) => {
|
||||
self.scopes[scope_idx].variables.remove(var as &str);
|
||||
}
|
||||
Binding::Ignore => {}
|
||||
binder.unbind(&mut self.scopes[scope_idx].variables);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -228,25 +248,14 @@ impl<'a, O: OutputSystem + Send, LS: LocalisationSystem + Sync + Send> Interpret
|
||||
// TODO(performance) I'd like to remove this clone!
|
||||
// Can possibly do so with a Yoke or something...
|
||||
let val = list.get(idx).expect("checked iter").clone_value();
|
||||
// TODO duplicated code
|
||||
match binding {
|
||||
Binding::Variable(var) => {
|
||||
self.scopes[scope_idx].variables.insert(
|
||||
String::from(var as &str),
|
||||
Value::from_reflect(val),
|
||||
);
|
||||
}
|
||||
Binding::Ignore => {}
|
||||
}
|
||||
let mut binder = Binder::new();
|
||||
binder.bind(
|
||||
&mut self.scopes[scope_idx].variables,
|
||||
&binding,
|
||||
Value::from_reflect(val),
|
||||
);
|
||||
self.run_steps(scope_idx, body_steps).await?;
|
||||
}
|
||||
|
||||
// TODO duplicated code
|
||||
match binding {
|
||||
Binding::Variable(var) => {
|
||||
self.scopes[scope_idx].variables.remove(var as &str);
|
||||
}
|
||||
Binding::Ignore => {}
|
||||
binder.unbind(&mut self.scopes[scope_idx].variables);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -273,6 +282,8 @@ impl<'a, O: OutputSystem + Send, LS: LocalisationSystem + Sync + Send> Interpret
|
||||
let matchable_evaled =
|
||||
self.evaluate_expression(scope_idx, matchable, &step.locator)?;
|
||||
|
||||
let mut binder = Binder::new();
|
||||
|
||||
for (arm_binding, arm_steps) in arms {
|
||||
// if this arm's binding matches, then bind the variable...
|
||||
match arm_binding {
|
||||
@ -331,21 +342,11 @@ impl<'a, O: OutputSystem + Send, LS: LocalisationSystem + Sync + Send> Interpret
|
||||
for (piece, field) in
|
||||
pieces.iter().zip(reflenum.iter_fields())
|
||||
{
|
||||
// TODO duplicated code. Should probably make some 'Binder' tool that also makes it easy to unbind afterwards!
|
||||
match piece {
|
||||
Binding::Variable(var) => {
|
||||
self.scopes[scope_idx].variables.insert(
|
||||
String::from(var as &str),
|
||||
// TODO would be nice to avoid this clone!
|
||||
Value::from_reflect(
|
||||
field.value().clone_value(),
|
||||
),
|
||||
);
|
||||
}
|
||||
Binding::Ignore => {
|
||||
// nop.
|
||||
}
|
||||
}
|
||||
binder.bind(
|
||||
&mut self.scopes[scope_idx].variables,
|
||||
piece,
|
||||
Value::from_reflect(field.value().clone_value()),
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
@ -371,24 +372,7 @@ impl<'a, O: OutputSystem + Send, LS: LocalisationSystem + Sync + Send> Interpret
|
||||
self.run_steps(scope_idx, arm_steps).await?;
|
||||
|
||||
// and then unbind the variables.
|
||||
match arm_binding {
|
||||
MatchBinding::TupleVariant { pieces, .. } => {
|
||||
for piece in pieces {
|
||||
// TODO duplicated code. Should probably make some 'Binder' tool that also makes it easy to unbind afterwards!
|
||||
match piece {
|
||||
Binding::Variable(var) => {
|
||||
self.scopes[scope_idx].variables.remove(var as &str);
|
||||
}
|
||||
Binding::Ignore => {
|
||||
// nop.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
MatchBinding::UnitVariant { .. } | MatchBinding::Ignore => {
|
||||
// no variables to unbind
|
||||
}
|
||||
};
|
||||
binder.unbind(&mut self.scopes[scope_idx].variables);
|
||||
|
||||
// (don't fall through to other arms since we matched this one)
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user