Move block contexts to loops and function

This commit is contained in:
Jeff 2024-02-12 16:51:06 -05:00
parent 1e665a6f13
commit daf78919da
5 changed files with 48 additions and 80 deletions

View File

@ -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)
}

View File

@ -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())
}
}

View File

@ -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,
})
}

View File

@ -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(())

View File

@ -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(