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