Move block contexts to loops and function
This commit is contained in:
parent
1e665a6f13
commit
daf78919da
@ -23,15 +23,6 @@ use crate::{
|
||||
pub struct Block {
|
||||
is_async: bool,
|
||||
statements: Vec<Statement>,
|
||||
|
||||
#[serde(skip)]
|
||||
context: Context,
|
||||
}
|
||||
|
||||
impl Block {
|
||||
pub fn context(&self) -> &Context {
|
||||
&self.context
|
||||
}
|
||||
}
|
||||
|
||||
impl AbstractTree for Block {
|
||||
@ -62,23 +53,18 @@ impl AbstractTree for Block {
|
||||
Ok(Block {
|
||||
is_async,
|
||||
statements,
|
||||
context: block_context,
|
||||
})
|
||||
}
|
||||
|
||||
fn validate(&self, _source: &str, _context: &Context) -> Result<(), ValidationError> {
|
||||
self.context.inherit_from(_context)?;
|
||||
|
||||
for statement in &self.statements {
|
||||
statement.validate(_source, &self.context)?;
|
||||
statement.validate(_source, _context)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run(&self, source: &str, context: &Context) -> Result<Value, RuntimeError> {
|
||||
self.context.inherit_from(context)?;
|
||||
|
||||
fn run(&self, _source: &str, _context: &Context) -> Result<Value, RuntimeError> {
|
||||
if self.is_async {
|
||||
let statements = &self.statements;
|
||||
let final_result = RwLock::new(Ok(Value::none()));
|
||||
@ -87,7 +73,7 @@ impl AbstractTree for Block {
|
||||
.into_par_iter()
|
||||
.enumerate()
|
||||
.find_map_first(|(index, statement)| {
|
||||
let result = statement.run(source, &self.context);
|
||||
let result = statement.run(_source, _context);
|
||||
let is_last_statement = index == statements.len() - 1;
|
||||
let is_return_statement = if let Statement::Return(_) = statement {
|
||||
true
|
||||
@ -117,10 +103,10 @@ impl AbstractTree for Block {
|
||||
|
||||
for statement in &self.statements {
|
||||
if let Statement::Return(inner_statement) = statement {
|
||||
return inner_statement.run(source, &self.context);
|
||||
return inner_statement.run(_source, _context);
|
||||
}
|
||||
|
||||
prev_result = Some(statement.run(source, &self.context));
|
||||
prev_result = Some(statement.run(_source, _context));
|
||||
}
|
||||
|
||||
prev_result.unwrap_or(Ok(Value::none()))
|
||||
@ -135,9 +121,9 @@ impl AbstractTree for Block {
|
||||
false
|
||||
}
|
||||
}) {
|
||||
statement.expected_type(&self.context)
|
||||
statement.expected_type(_context)
|
||||
} else if let Some(statement) = self.statements.last() {
|
||||
statement.expected_type(&self.context)
|
||||
statement.expected_type(_context)
|
||||
} else {
|
||||
Ok(Type::None)
|
||||
}
|
||||
|
@ -15,6 +15,9 @@ pub struct For {
|
||||
collection: Expression,
|
||||
block: Block,
|
||||
source_position: SourcePosition,
|
||||
|
||||
#[serde(skip)]
|
||||
context: Context,
|
||||
}
|
||||
|
||||
impl AbstractTree for For {
|
||||
@ -41,6 +44,8 @@ impl AbstractTree for For {
|
||||
let expression_node = node.child(3).unwrap();
|
||||
let expression = Expression::from_syntax(expression_node, source, context)?;
|
||||
|
||||
let loop_context = Context::with_variables_from(context)?;
|
||||
|
||||
let item_node = node.child(4).unwrap();
|
||||
let item = Block::from_syntax(item_node, source, context)?;
|
||||
|
||||
@ -50,6 +55,7 @@ impl AbstractTree for For {
|
||||
collection: expression,
|
||||
block: item,
|
||||
source_position: SourcePosition::from(node.range()),
|
||||
context: loop_context,
|
||||
})
|
||||
}
|
||||
|
||||
@ -72,8 +78,8 @@ impl AbstractTree for For {
|
||||
};
|
||||
let key = self.item_id.inner().clone();
|
||||
|
||||
self.block.context().set_type(key, item_type)?;
|
||||
self.block.validate(_source, context)
|
||||
self.context.set_type(key, item_type)?;
|
||||
self.block.validate(_source, &self.context)
|
||||
}
|
||||
|
||||
fn run(&self, source: &str, context: &Context) -> Result<Value, RuntimeError> {
|
||||
@ -83,17 +89,14 @@ impl AbstractTree for For {
|
||||
if let Value::Range(range) = expression_run {
|
||||
if self.is_async {
|
||||
range.into_par_iter().try_for_each(|integer| {
|
||||
self.block
|
||||
.context()
|
||||
self.context
|
||||
.set_value(key.clone(), Value::Integer(integer))?;
|
||||
self.block.run(source, context).map(|_value| ())
|
||||
self.block.run(source, &self.context).map(|_value| ())
|
||||
})?;
|
||||
} else {
|
||||
for i in range {
|
||||
self.block
|
||||
.context()
|
||||
.set_value(key.clone(), Value::Integer(i))?;
|
||||
self.block.run(source, context)?;
|
||||
self.context.set_value(key.clone(), Value::Integer(i))?;
|
||||
self.block.run(source, &self.context)?;
|
||||
}
|
||||
}
|
||||
|
||||
@ -103,20 +106,17 @@ impl AbstractTree for For {
|
||||
if let Value::List(list) = &expression_run {
|
||||
if self.is_async {
|
||||
list.items().par_iter().try_for_each(|value| {
|
||||
self.block.context().set_value(key.clone(), value.clone())?;
|
||||
self.block.run(source, context).map(|_value| ())
|
||||
self.context.set_value(key.clone(), value.clone())?;
|
||||
self.block.run(source, &self.context).map(|_value| ())
|
||||
})?;
|
||||
} else {
|
||||
for value in list.items().iter() {
|
||||
self.block.context().set_value(key.clone(), value.clone())?;
|
||||
self.block.run(source, context)?;
|
||||
self.context.set_value(key.clone(), value.clone())?;
|
||||
self.block.run(source, &self.context)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.block.context().unset(&key)?;
|
||||
context.inherit_from(self.block.context())?;
|
||||
|
||||
Ok(Value::none())
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,9 @@ pub struct FunctionNode {
|
||||
body: Block,
|
||||
r#type: Type,
|
||||
syntax_position: SourcePosition,
|
||||
|
||||
#[serde(skip)]
|
||||
context: Context,
|
||||
}
|
||||
|
||||
impl FunctionNode {
|
||||
@ -28,6 +31,7 @@ impl FunctionNode {
|
||||
body,
|
||||
r#type,
|
||||
syntax_position,
|
||||
context: Context::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -61,28 +65,24 @@ impl FunctionNode {
|
||||
&self,
|
||||
arguments: &[Value],
|
||||
source: &str,
|
||||
outer_context: &Context,
|
||||
_context: &Context,
|
||||
) -> Result<Value, RuntimeError> {
|
||||
let parameter_argument_pairs = self.parameters.iter().zip(arguments.iter());
|
||||
|
||||
for (identifier, value) in parameter_argument_pairs {
|
||||
let key = identifier.inner().clone();
|
||||
|
||||
self.body.context().set_value(key, value.clone())?;
|
||||
self.context.set_value(key, value.clone())?;
|
||||
}
|
||||
|
||||
let return_value = self.body.run(source, outer_context)?;
|
||||
let return_value = self.body.run(source, &self.context)?;
|
||||
|
||||
Ok(return_value)
|
||||
}
|
||||
}
|
||||
|
||||
impl AbstractTree for FunctionNode {
|
||||
fn from_syntax(
|
||||
node: SyntaxNode,
|
||||
source: &str,
|
||||
outer_context: &Context,
|
||||
) -> Result<Self, SyntaxError> {
|
||||
fn from_syntax(node: SyntaxNode, source: &str, context: &Context) -> Result<Self, SyntaxError> {
|
||||
SyntaxError::expect_syntax_node(source, "function", node)?;
|
||||
|
||||
let child_count = node.child_count();
|
||||
@ -93,28 +93,28 @@ impl AbstractTree for FunctionNode {
|
||||
let child = node.child(index).unwrap();
|
||||
|
||||
if child.kind() == "identifier" {
|
||||
let identifier = Identifier::from_syntax(child, source, outer_context)?;
|
||||
let identifier = Identifier::from_syntax(child, source, context)?;
|
||||
|
||||
parameters.push(identifier);
|
||||
}
|
||||
|
||||
if child.kind() == "type_specification" {
|
||||
let type_specification =
|
||||
TypeSpecification::from_syntax(child, source, outer_context)?;
|
||||
let type_specification = TypeSpecification::from_syntax(child, source, context)?;
|
||||
|
||||
parameter_types.push(type_specification.take_inner());
|
||||
}
|
||||
}
|
||||
|
||||
let return_type_node = node.child(child_count - 2).unwrap();
|
||||
let return_type = TypeSpecification::from_syntax(return_type_node, source, outer_context)?;
|
||||
let return_type = TypeSpecification::from_syntax(return_type_node, source, context)?;
|
||||
|
||||
let function_context = Context::with_variables_from(context)?;
|
||||
|
||||
let body_node = node.child(child_count - 1).unwrap();
|
||||
let body = Block::from_syntax(body_node, source, &outer_context)?;
|
||||
let body = Block::from_syntax(body_node, source, &context)?;
|
||||
|
||||
for (parameter, parameter_type) in parameters.iter().zip(parameter_types.iter()) {
|
||||
body.context()
|
||||
.set_type(parameter.inner().clone(), parameter_type.clone())?;
|
||||
function_context.set_type(parameter.inner().clone(), parameter_type.clone())?;
|
||||
}
|
||||
|
||||
let r#type = Type::function(parameter_types, return_type.take_inner());
|
||||
@ -125,6 +125,7 @@ impl AbstractTree for FunctionNode {
|
||||
body,
|
||||
r#type,
|
||||
syntax_position,
|
||||
context: function_context,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,13 @@ impl Context {
|
||||
let mut self_variables = self.inner.write()?;
|
||||
|
||||
for (identifier, value_data) in other.inner.read()?.iter() {
|
||||
self_variables.insert(identifier.clone(), value_data.clone());
|
||||
let existing_data = self_variables.get(identifier);
|
||||
|
||||
if let Some(ValueData::Value { .. }) = existing_data {
|
||||
continue;
|
||||
} else {
|
||||
self_variables.insert(identifier.clone(), value_data.clone());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -74,7 +74,7 @@ fn modify_map() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn modify_list_values() {
|
||||
fn do_not_modify_list_values() {
|
||||
let result = interpret(
|
||||
"
|
||||
list = [1 2 3]
|
||||
@ -85,39 +85,14 @@ fn modify_list_values() {
|
||||
|
||||
assert_eq!(
|
||||
Ok(Value::List(List::with_items(vec![
|
||||
Value::Integer(1),
|
||||
Value::Integer(2),
|
||||
Value::Integer(3),
|
||||
Value::Integer(4),
|
||||
]))),
|
||||
result
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn modify_map_values() {
|
||||
let result = interpret(
|
||||
"
|
||||
map = {
|
||||
x = 0
|
||||
y = 1
|
||||
}
|
||||
|
||||
for [key, value] in map {
|
||||
value += 1
|
||||
}
|
||||
|
||||
map
|
||||
",
|
||||
);
|
||||
|
||||
let map = Map::new();
|
||||
|
||||
map.set("x".to_string(), Value::Integer(1)).unwrap();
|
||||
map.set("y".to_string(), Value::Integer(2)).unwrap();
|
||||
|
||||
assert_eq!(Ok(Value::Map(map)), result);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn r#break() {
|
||||
let result = interpret(
|
||||
|
Loading…
Reference in New Issue
Block a user