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