Revise built-in functions; Add memory management
This commit is contained in:
parent
3d64883e2a
commit
70face6765
7
Cargo.lock
generated
7
Cargo.lock
generated
@ -356,7 +356,6 @@ dependencies = [
|
||||
"log",
|
||||
"rand",
|
||||
"rayon",
|
||||
"stanza",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1101,12 +1100,6 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stanza"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d230b987a5b524a015ded47fed54c5177598a71c90508acee1c5d0b4c955f74"
|
||||
|
||||
[[package]]
|
||||
name = "strip-ansi-escapes"
|
||||
version = "0.2.0"
|
||||
|
@ -17,4 +17,3 @@ env_logger = "0.11.3"
|
||||
log = "0.4.21"
|
||||
rand = "0.8.5"
|
||||
rayon = "1.9.0"
|
||||
stanza = "0.5.1"
|
||||
|
@ -69,8 +69,8 @@ impl AbstractNode for Assignment {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run(self, context: &Context) -> Result<Action, RuntimeError> {
|
||||
let action = self.statement.run(context)?;
|
||||
fn run(self, context: &mut Context, clear_variables: bool) -> Result<Action, RuntimeError> {
|
||||
let action = self.statement.run(context, clear_variables)?;
|
||||
let right = match action {
|
||||
Action::Return(value) => value,
|
||||
r#break => return Ok(r#break),
|
||||
@ -81,7 +81,7 @@ impl AbstractNode for Assignment {
|
||||
context.set_value(self.identifier.node, right)?;
|
||||
}
|
||||
AssignmentOperator::AddAssign => {
|
||||
if let Some(left) = context.get_value(&self.identifier.node)? {
|
||||
if let Some(left) = context.use_value(&self.identifier.node)? {
|
||||
let new_value = match (left.inner().as_ref(), right.inner().as_ref()) {
|
||||
(ValueInner::Integer(left), ValueInner::Integer(right)) => {
|
||||
let sum = left.saturating_add(*right);
|
||||
@ -120,7 +120,7 @@ impl AbstractNode for Assignment {
|
||||
}
|
||||
}
|
||||
AssignmentOperator::SubAssign => {
|
||||
if let Some(left) = context.get_value(&self.identifier.node)? {
|
||||
if let Some(left) = context.use_value(&self.identifier.node)? {
|
||||
let new_value = match (left.inner().as_ref(), right.inner().as_ref()) {
|
||||
(ValueInner::Integer(left), ValueInner::Integer(right)) => {
|
||||
let difference = left.saturating_sub(*right);
|
||||
@ -175,7 +175,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn assign_value() {
|
||||
let context = Context::new();
|
||||
let mut context = Context::new();
|
||||
|
||||
Assignment::new(
|
||||
Identifier::new("foobar").with_position((0, 0)),
|
||||
@ -185,18 +185,18 @@ mod tests {
|
||||
ValueNode::Integer(42).with_position((0, 0)),
|
||||
)),
|
||||
)
|
||||
.run(&context)
|
||||
.run(&mut context, true)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
context.get_value(&Identifier::new("foobar")),
|
||||
context.use_value(&Identifier::new("foobar")),
|
||||
Ok(Some(Value::integer(42)))
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn add_assign_value() {
|
||||
let context = Context::new();
|
||||
let mut context = Context::new();
|
||||
|
||||
context
|
||||
.set_value(Identifier::new("foobar"), Value::integer(1))
|
||||
@ -210,18 +210,18 @@ mod tests {
|
||||
ValueNode::Integer(41).with_position((0, 0)),
|
||||
)),
|
||||
)
|
||||
.run(&context)
|
||||
.run(&mut context, true)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
context.get_value(&Identifier::new("foobar")),
|
||||
context.use_value(&Identifier::new("foobar")),
|
||||
Ok(Some(Value::integer(42)))
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn subtract_assign_value() {
|
||||
let context = Context::new();
|
||||
let mut context = Context::new();
|
||||
|
||||
context
|
||||
.set_value(Identifier::new("foobar"), Value::integer(43))
|
||||
@ -235,11 +235,11 @@ mod tests {
|
||||
ValueNode::Integer(1).with_position((0, 0)),
|
||||
)),
|
||||
)
|
||||
.run(&context)
|
||||
.run(&mut context, true)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
context.get_value(&Identifier::new("foobar")),
|
||||
context.use_value(&Identifier::new("foobar")),
|
||||
Ok(Some(Value::integer(42)))
|
||||
)
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ impl AbstractNode for AsyncBlock {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run(self, _context: &Context) -> Result<Action, RuntimeError> {
|
||||
fn run(self, _context: &mut Context, _clear_variables: bool) -> Result<Action, RuntimeError> {
|
||||
let statement_count = self.statements.len();
|
||||
let final_result = RwLock::new(Ok(Action::None));
|
||||
|
||||
@ -41,7 +41,7 @@ impl AbstractNode for AsyncBlock {
|
||||
.into_par_iter()
|
||||
.enumerate()
|
||||
.find_map_first(|(index, statement)| {
|
||||
let result = statement.run(_context);
|
||||
let result = statement.run(&mut _context.clone(), _clear_variables);
|
||||
|
||||
if index == statement_count - 1 {
|
||||
let get_write_lock = final_result.write();
|
||||
|
@ -37,11 +37,11 @@ impl AbstractNode for Block {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run(self, _context: &Context) -> Result<Action, RuntimeError> {
|
||||
fn run(self, _context: &mut Context, _clear_variables: bool) -> Result<Action, RuntimeError> {
|
||||
let mut previous = Action::None;
|
||||
|
||||
for statement in self.statements {
|
||||
previous = statement.run(_context)?;
|
||||
previous = statement.run(_context, _clear_variables)?;
|
||||
}
|
||||
|
||||
Ok(previous)
|
||||
@ -72,7 +72,7 @@ mod tests {
|
||||
]);
|
||||
|
||||
assert_eq!(
|
||||
block.run(&Context::new()).unwrap(),
|
||||
block.run(&mut Context::new(), true).unwrap(),
|
||||
Action::Return(Value::integer(42))
|
||||
)
|
||||
}
|
||||
|
@ -27,10 +27,14 @@ impl AbstractNode for BuiltInFunctionCall {
|
||||
}
|
||||
|
||||
fn validate(&self, _context: &Context) -> Result<(), ValidationError> {
|
||||
Ok(())
|
||||
match self {
|
||||
BuiltInFunctionCall::ReadLine => Ok(()),
|
||||
BuiltInFunctionCall::Sleep(expression) => expression.validate(_context),
|
||||
BuiltInFunctionCall::WriteLine(expression) => expression.validate(_context),
|
||||
}
|
||||
}
|
||||
|
||||
fn run(self, context: &Context) -> Result<Action, RuntimeError> {
|
||||
fn run(self, context: &mut Context, _clear_variables: bool) -> Result<Action, RuntimeError> {
|
||||
match self {
|
||||
BuiltInFunctionCall::ReadLine => {
|
||||
let mut buffer = String::new();
|
||||
@ -40,7 +44,7 @@ impl AbstractNode for BuiltInFunctionCall {
|
||||
Ok(Action::Return(Value::string(buffer)))
|
||||
}
|
||||
BuiltInFunctionCall::Sleep(expression) => {
|
||||
let action = expression.clone().run(context)?;
|
||||
let action = expression.clone().run(context, _clear_variables)?;
|
||||
let value = if let Action::Return(value) = action {
|
||||
value
|
||||
} else {
|
||||
@ -56,7 +60,7 @@ impl AbstractNode for BuiltInFunctionCall {
|
||||
Ok(Action::None)
|
||||
}
|
||||
BuiltInFunctionCall::WriteLine(expression) => {
|
||||
let action = expression.clone().run(context)?;
|
||||
let action = expression.clone().run(context, _clear_variables)?;
|
||||
let value = if let Action::Return(value) = action {
|
||||
value
|
||||
} else {
|
||||
|
@ -65,7 +65,9 @@ impl AbstractNode for Expression {
|
||||
match self {
|
||||
Expression::FunctionCall(function_call) => function_call.node.validate(context),
|
||||
Expression::Identifier(identifier) => {
|
||||
if context.contains(&identifier.node)? {
|
||||
let found = context.add_expected_use(&identifier.node)?;
|
||||
|
||||
if found {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(ValidationError::VariableNotFound {
|
||||
@ -85,11 +87,13 @@ impl AbstractNode for Expression {
|
||||
}
|
||||
}
|
||||
|
||||
fn run(self, _context: &Context) -> Result<Action, RuntimeError> {
|
||||
fn run(self, context: &mut Context, _clear_variables: bool) -> Result<Action, RuntimeError> {
|
||||
match self {
|
||||
Expression::FunctionCall(function_call) => function_call.node.run(_context),
|
||||
Expression::FunctionCall(function_call) => {
|
||||
function_call.node.run(context, _clear_variables)
|
||||
}
|
||||
Expression::Identifier(identifier) => {
|
||||
if let Some(value) = _context.get_value(&identifier.node)? {
|
||||
if let Some(value) = context.use_value(&identifier.node)? {
|
||||
Ok(Action::Return(value))
|
||||
} else {
|
||||
Err(RuntimeError::ValidationFailure(
|
||||
@ -100,13 +104,13 @@ impl AbstractNode for Expression {
|
||||
))
|
||||
}
|
||||
}
|
||||
Expression::MapIndex(map_index) => map_index.node.run(_context),
|
||||
Expression::ListIndex(list_index) => list_index.node.run(_context),
|
||||
Expression::Logic(logic) => logic.node.run(_context),
|
||||
Expression::Math(math) => math.node.run(_context),
|
||||
Expression::Value(value_node) => value_node.node.run(_context),
|
||||
Expression::MapIndex(map_index) => map_index.node.run(context, _clear_variables),
|
||||
Expression::ListIndex(list_index) => list_index.node.run(context, _clear_variables),
|
||||
Expression::Logic(logic) => logic.node.run(context, _clear_variables),
|
||||
Expression::Math(math) => math.node.run(context, _clear_variables),
|
||||
Expression::Value(value_node) => value_node.node.run(context, _clear_variables),
|
||||
Expression::BuiltInFunctionCall(built_in_function_call) => {
|
||||
built_in_function_call.node.run(_context)
|
||||
built_in_function_call.node.run(context, _clear_variables)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -42,6 +42,8 @@ impl AbstractNode for FunctionCall {
|
||||
}
|
||||
|
||||
fn validate(&self, context: &Context) -> Result<(), ValidationError> {
|
||||
self.function.validate(context)?;
|
||||
|
||||
for expression in &self.arguments {
|
||||
expression.validate(context)?;
|
||||
}
|
||||
@ -95,9 +97,9 @@ impl AbstractNode for FunctionCall {
|
||||
}
|
||||
}
|
||||
|
||||
fn run(self, context: &Context) -> Result<Action, RuntimeError> {
|
||||
fn run(self, context: &mut Context, _clear_variables: bool) -> Result<Action, RuntimeError> {
|
||||
let function_position = self.function.position();
|
||||
let action = self.function.run(context)?;
|
||||
let action = self.function.run(context, _clear_variables)?;
|
||||
let value = if let Action::Return(value) = action {
|
||||
value
|
||||
} else {
|
||||
@ -119,7 +121,7 @@ impl AbstractNode for FunctionCall {
|
||||
|
||||
for expression in self.arguments {
|
||||
let expression_position = expression.position();
|
||||
let action = expression.run(context)?;
|
||||
let action = expression.run(context, _clear_variables)?;
|
||||
let value = if let Action::Return(value) = action {
|
||||
value
|
||||
} else {
|
||||
@ -131,7 +133,7 @@ impl AbstractNode for FunctionCall {
|
||||
arguments.push(value);
|
||||
}
|
||||
|
||||
let function_context = Context::new();
|
||||
let mut function_context = Context::new();
|
||||
|
||||
for (type_parameter, type_argument) in function
|
||||
.type_parameters()
|
||||
@ -145,6 +147,6 @@ impl AbstractNode for FunctionCall {
|
||||
}
|
||||
|
||||
function_context.inherit_data_from(&context)?;
|
||||
function.clone().call(arguments, function_context)
|
||||
function.clone().call(arguments, &mut function_context)
|
||||
}
|
||||
}
|
||||
|
@ -89,9 +89,9 @@ impl AbstractNode for IfElse {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run(self, context: &Context) -> Result<Action, RuntimeError> {
|
||||
fn run(self, context: &mut Context, _clear_variables: bool) -> Result<Action, RuntimeError> {
|
||||
let if_position = self.if_expression.position();
|
||||
let action = self.if_expression.run(context)?;
|
||||
let action = self.if_expression.run(context, _clear_variables)?;
|
||||
let value = if let Action::Return(value) = action {
|
||||
value
|
||||
} else {
|
||||
@ -102,11 +102,11 @@ impl AbstractNode for IfElse {
|
||||
|
||||
if let ValueInner::Boolean(if_boolean) = value.inner().as_ref() {
|
||||
if *if_boolean {
|
||||
self.if_block.node.run(context)
|
||||
self.if_block.node.run(context, _clear_variables)
|
||||
} else {
|
||||
for (expression, block) in self.else_ifs {
|
||||
let expression_position = expression.position();
|
||||
let action = expression.run(context)?;
|
||||
let action = expression.run(context, _clear_variables)?;
|
||||
let value = if let Action::Return(value) = action {
|
||||
value
|
||||
} else {
|
||||
@ -117,7 +117,7 @@ impl AbstractNode for IfElse {
|
||||
|
||||
if let ValueInner::Boolean(else_if_boolean) = value.inner().as_ref() {
|
||||
if *else_if_boolean {
|
||||
return block.node.run(context);
|
||||
return block.node.run(context, _clear_variables);
|
||||
}
|
||||
} else {
|
||||
return Err(RuntimeError::ValidationFailure(
|
||||
@ -130,7 +130,7 @@ impl AbstractNode for IfElse {
|
||||
}
|
||||
|
||||
if let Some(else_statement) = self.else_block {
|
||||
else_statement.node.run(context)
|
||||
else_statement.node.run(context, _clear_variables)
|
||||
} else {
|
||||
Ok(Action::None)
|
||||
}
|
||||
@ -167,7 +167,7 @@ mod tests {
|
||||
Vec::with_capacity(0),
|
||||
None
|
||||
)
|
||||
.run(&Context::new())
|
||||
.run(&mut Context::new(), true)
|
||||
.unwrap(),
|
||||
Action::Return(Value::string("foo".to_string()))
|
||||
)
|
||||
|
@ -74,9 +74,9 @@ impl AbstractNode for ListIndex {
|
||||
}
|
||||
}
|
||||
|
||||
fn run(self, context: &Context) -> Result<Action, RuntimeError> {
|
||||
fn run(self, context: &mut Context, _clear_variables: bool) -> Result<Action, RuntimeError> {
|
||||
let left_position = self.left.position();
|
||||
let left_action = self.left.run(context)?;
|
||||
let left_action = self.left.run(context, _clear_variables)?;
|
||||
let left_value = if let Action::Return(value) = left_action {
|
||||
value
|
||||
} else {
|
||||
@ -85,7 +85,7 @@ impl AbstractNode for ListIndex {
|
||||
));
|
||||
};
|
||||
let right_position = self.right.position();
|
||||
let right_action = self.right.run(context)?;
|
||||
let right_action = self.right.run(context, _clear_variables)?;
|
||||
let right_value = if let Action::Return(value) = right_action {
|
||||
value
|
||||
} else {
|
||||
|
@ -83,10 +83,10 @@ impl AbstractNode for Logic {
|
||||
}
|
||||
}
|
||||
|
||||
fn run(self, context: &Context) -> Result<Action, RuntimeError> {
|
||||
fn run(self, context: &mut Context, _clear_variables: bool) -> Result<Action, RuntimeError> {
|
||||
let run_and_expect_value = |expression: Expression| -> Result<Value, RuntimeError> {
|
||||
let expression_position = expression.position();
|
||||
let action = expression.run(context)?;
|
||||
let action = expression.run(&mut context.clone(), _clear_variables)?;
|
||||
let value = if let Action::Return(value) = action {
|
||||
value
|
||||
} else {
|
||||
@ -100,7 +100,7 @@ impl AbstractNode for Logic {
|
||||
|
||||
let run_and_expect_boolean = |expression: Expression| -> Result<bool, RuntimeError> {
|
||||
let expression_position = expression.position();
|
||||
let action = expression.run(context)?;
|
||||
let action = expression.run(&mut context.clone(), _clear_variables)?;
|
||||
let value = if let Action::Return(value) = action {
|
||||
value
|
||||
} else {
|
||||
@ -198,7 +198,7 @@ mod tests {
|
||||
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||
Expression::Value(ValueNode::Integer(42).with_position((0, 0)))
|
||||
)
|
||||
.run(&Context::new()),
|
||||
.run(&mut Context::new(), true),
|
||||
Ok(Action::Return(Value::boolean(true)))
|
||||
)
|
||||
}
|
||||
@ -210,7 +210,7 @@ mod tests {
|
||||
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||
Expression::Value(ValueNode::Integer(43).with_position((0, 0)))
|
||||
)
|
||||
.run(&Context::new()),
|
||||
.run(&mut Context::new(), true),
|
||||
Ok(Action::Return(Value::boolean(true)))
|
||||
)
|
||||
}
|
||||
@ -222,7 +222,7 @@ mod tests {
|
||||
Expression::Value(ValueNode::Integer(43).with_position((0, 0))),
|
||||
Expression::Value(ValueNode::Integer(42).with_position((0, 0)))
|
||||
)
|
||||
.run(&Context::new()),
|
||||
.run(&mut Context::new(), true),
|
||||
Ok(Action::Return(Value::boolean(true)))
|
||||
)
|
||||
}
|
||||
@ -234,7 +234,7 @@ mod tests {
|
||||
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||
Expression::Value(ValueNode::Integer(43).with_position((0, 0)))
|
||||
)
|
||||
.run(&Context::new()),
|
||||
.run(&mut Context::new(), true),
|
||||
Ok(Action::Return(Value::boolean(true)))
|
||||
)
|
||||
}
|
||||
@ -246,7 +246,7 @@ mod tests {
|
||||
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||
Expression::Value(ValueNode::Integer(41).with_position((0, 0)))
|
||||
)
|
||||
.run(&Context::new()),
|
||||
.run(&mut Context::new(), true),
|
||||
Ok(Action::Return(Value::boolean(true)))
|
||||
);
|
||||
|
||||
@ -255,7 +255,7 @@ mod tests {
|
||||
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||
)
|
||||
.run(&Context::new()),
|
||||
.run(&mut Context::new(), true),
|
||||
Ok(Action::Return(Value::boolean(true)))
|
||||
);
|
||||
}
|
||||
@ -267,7 +267,7 @@ mod tests {
|
||||
Expression::Value(ValueNode::Integer(41).with_position((0, 0))),
|
||||
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||
)
|
||||
.run(&Context::new()),
|
||||
.run(&mut Context::new(), true),
|
||||
Ok(Action::Return(Value::boolean(true)))
|
||||
);
|
||||
|
||||
@ -276,7 +276,7 @@ mod tests {
|
||||
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||
Expression::Value(ValueNode::Integer(42).with_position((0, 0))),
|
||||
)
|
||||
.run(&Context::new()),
|
||||
.run(&mut Context::new(), true),
|
||||
Ok(Action::Return(Value::boolean(true)))
|
||||
);
|
||||
}
|
||||
@ -288,7 +288,7 @@ mod tests {
|
||||
Expression::Value(ValueNode::Boolean(true).with_position((0, 0))),
|
||||
Expression::Value(ValueNode::Boolean(true).with_position((0, 0))),
|
||||
)
|
||||
.run(&Context::new()),
|
||||
.run(&mut Context::new(), true),
|
||||
Ok(Action::Return(Value::boolean(true)))
|
||||
)
|
||||
}
|
||||
@ -300,7 +300,7 @@ mod tests {
|
||||
Expression::Value(ValueNode::Boolean(true).with_position((0, 0))),
|
||||
Expression::Value(ValueNode::Boolean(false).with_position((0, 0))),
|
||||
)
|
||||
.run(&Context::new()),
|
||||
.run(&mut Context::new(), true),
|
||||
Ok(Action::Return(Value::boolean(true)))
|
||||
)
|
||||
}
|
||||
@ -311,7 +311,7 @@ mod tests {
|
||||
Logic::Not(Expression::Value(
|
||||
ValueNode::Boolean(false).with_position((0, 0))
|
||||
))
|
||||
.run(&Context::new()),
|
||||
.run(&mut Context::new(), true),
|
||||
Ok(Action::Return(Value::boolean(true)))
|
||||
)
|
||||
}
|
||||
|
@ -31,10 +31,10 @@ impl AbstractNode for Loop {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run(self, _context: &Context) -> Result<Action, RuntimeError> {
|
||||
fn run(self, _context: &mut Context, _clear_variables: bool) -> Result<Action, RuntimeError> {
|
||||
loop {
|
||||
for statement in &self.statements {
|
||||
let action = statement.clone().run(_context)?;
|
||||
let action = statement.clone().run(_context, _clear_variables)?;
|
||||
|
||||
match action {
|
||||
Action::Return(_) => {}
|
||||
@ -65,81 +65,3 @@ impl Ord for Loop {
|
||||
self.statements.cmp(&other.statements)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{
|
||||
abstract_tree::{
|
||||
Assignment, AssignmentOperator, Block, Expression, IfElse, Logic, ValueNode, WithPos,
|
||||
},
|
||||
identifier::Identifier,
|
||||
Value,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn basic_loop() {
|
||||
let action = Loop::new(vec![Statement::Break(().with_position((0, 0)))])
|
||||
.run(&Context::new())
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(action, Action::Break)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn complex_loop() {
|
||||
let action = Block::new(vec![
|
||||
Statement::Assignment(
|
||||
Assignment::new(
|
||||
Identifier::new("i").with_position((0, 0)),
|
||||
None,
|
||||
AssignmentOperator::Assign,
|
||||
Statement::Expression(Expression::Value(
|
||||
ValueNode::Integer(1).with_position((0, 0)),
|
||||
)),
|
||||
)
|
||||
.with_position((0, 0)),
|
||||
),
|
||||
Statement::Loop(
|
||||
Loop::new(vec![Statement::IfElse(
|
||||
IfElse::new(
|
||||
Expression::Logic(
|
||||
Box::new(Logic::Greater(
|
||||
Expression::Identifier(Identifier::new("i").with_position((0, 0))),
|
||||
Expression::Value(ValueNode::Integer(2).with_position((0, 0))),
|
||||
))
|
||||
.with_position((0, 0)),
|
||||
),
|
||||
Block::new(vec![Statement::Break(().with_position((0, 0)))])
|
||||
.with_position((0, 0)),
|
||||
Vec::with_capacity(0),
|
||||
Some(
|
||||
Block::new(vec![Statement::Assignment(
|
||||
Assignment::new(
|
||||
Identifier::new("i").with_position((0, 0)),
|
||||
None,
|
||||
AssignmentOperator::AddAssign,
|
||||
Statement::Expression(Expression::Value(
|
||||
ValueNode::Integer(1).with_position((0, 0)),
|
||||
)),
|
||||
)
|
||||
.with_position((0, 0)),
|
||||
)])
|
||||
.with_position((0, 0)),
|
||||
),
|
||||
)
|
||||
.with_position((0, 0)),
|
||||
)])
|
||||
.with_position((0, 0)),
|
||||
),
|
||||
Statement::Expression(Expression::Identifier(
|
||||
Identifier::new("i").with_position((0, 0)),
|
||||
)),
|
||||
])
|
||||
.run(&Context::new())
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(action, Action::Return(Value::integer(3)))
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
use crate::{
|
||||
context::Context,
|
||||
error::{RuntimeError, ValidationError},
|
||||
identifier::Identifier,
|
||||
value::ValueInner,
|
||||
};
|
||||
|
||||
@ -8,25 +9,26 @@ use super::{AbstractNode, Action, Expression, Type, ValueNode, WithPosition};
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct MapIndex {
|
||||
left: Expression,
|
||||
right: Expression,
|
||||
collection: Expression,
|
||||
index: WithPosition<Identifier>,
|
||||
}
|
||||
|
||||
impl MapIndex {
|
||||
pub fn new(left: Expression, right: Expression) -> Self {
|
||||
Self { left, right }
|
||||
pub fn new(left: Expression, right: WithPosition<Identifier>) -> Self {
|
||||
Self {
|
||||
collection: left,
|
||||
index: right,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AbstractNode for MapIndex {
|
||||
fn expected_type(&self, context: &Context) -> Result<Type, ValidationError> {
|
||||
if let (
|
||||
Expression::Identifier(collection_identifier),
|
||||
Expression::Identifier(index_identifier),
|
||||
) = (&self.left, &self.right)
|
||||
if let (Expression::Identifier(collection_identifier), index) =
|
||||
(&self.collection, &self.index)
|
||||
{
|
||||
let collection =
|
||||
if let Some(collection) = context.get_value(&collection_identifier.node)? {
|
||||
if let Some(collection) = context.use_value(&collection_identifier.node)? {
|
||||
collection
|
||||
} else {
|
||||
return Err(ValidationError::VariableNotFound {
|
||||
@ -36,12 +38,12 @@ impl AbstractNode for MapIndex {
|
||||
};
|
||||
|
||||
if let ValueInner::Map(map) = collection.inner().as_ref() {
|
||||
return if let Some(value) = map.get(&index_identifier.node) {
|
||||
return if let Some(value) = map.get(&index.node) {
|
||||
Ok(value.r#type(context)?)
|
||||
} else {
|
||||
Err(ValidationError::PropertyNotFound {
|
||||
identifier: index_identifier.node.clone(),
|
||||
position: self.right.position(),
|
||||
identifier: index.node.clone(),
|
||||
position: index.position,
|
||||
})
|
||||
};
|
||||
};
|
||||
@ -52,14 +54,14 @@ impl AbstractNode for MapIndex {
|
||||
node: ValueNode::Map(properties),
|
||||
..
|
||||
}),
|
||||
Expression::Identifier(identifier),
|
||||
) = (&self.left, &self.right)
|
||||
index,
|
||||
) = (&self.collection, &self.index)
|
||||
{
|
||||
return if let Some(type_result) =
|
||||
properties
|
||||
.iter()
|
||||
.find_map(|(property, type_option, expression)| {
|
||||
if property == &identifier.node {
|
||||
if property == &index.node {
|
||||
if let Some(r#type) = type_option {
|
||||
Some(r#type.node.expected_type(context))
|
||||
} else {
|
||||
@ -81,11 +83,11 @@ impl AbstractNode for MapIndex {
|
||||
node: ValueNode::Structure { fields, .. },
|
||||
..
|
||||
}),
|
||||
Expression::Identifier(identifier),
|
||||
) = (&self.left, &self.right)
|
||||
index,
|
||||
) = (&self.collection, &self.index)
|
||||
{
|
||||
return if let Some(type_result) = fields.iter().find_map(|(property, expression)| {
|
||||
if property == &identifier.node {
|
||||
if property == &index.node {
|
||||
Some(expression.expected_type(context))
|
||||
} else {
|
||||
None
|
||||
@ -97,43 +99,19 @@ impl AbstractNode for MapIndex {
|
||||
};
|
||||
}
|
||||
|
||||
Err(ValidationError::CannotIndexWith {
|
||||
collection_type: self.left.expected_type(context)?,
|
||||
collection_position: self.left.position(),
|
||||
index_type: self.right.expected_type(context)?,
|
||||
index_position: self.right.position(),
|
||||
Err(ValidationError::CannotIndex {
|
||||
r#type: self.collection.expected_type(context)?,
|
||||
position: self.collection.position(),
|
||||
})
|
||||
}
|
||||
|
||||
fn validate(&self, context: &Context) -> Result<(), ValidationError> {
|
||||
let left_type = self.left.expected_type(context)?;
|
||||
|
||||
if let (
|
||||
Expression::Value(WithPosition {
|
||||
node: ValueNode::Map(_),
|
||||
..
|
||||
}),
|
||||
Expression::Identifier(_),
|
||||
) = (&self.left, &self.right)
|
||||
{
|
||||
Ok(())
|
||||
} else if let (Expression::Identifier(_), Expression::Identifier(_)) =
|
||||
(&self.left, &self.right)
|
||||
{
|
||||
Ok(())
|
||||
} else {
|
||||
Err(ValidationError::CannotIndexWith {
|
||||
collection_type: left_type,
|
||||
collection_position: self.left.position(),
|
||||
index_type: self.right.expected_type(context)?,
|
||||
index_position: self.right.position(),
|
||||
})
|
||||
}
|
||||
self.collection.validate(context)
|
||||
}
|
||||
|
||||
fn run(self, context: &Context) -> Result<Action, RuntimeError> {
|
||||
let collection_position = self.left.position();
|
||||
let action = self.left.run(context)?;
|
||||
fn run(self, context: &mut Context, _clear_variables: bool) -> Result<Action, RuntimeError> {
|
||||
let collection_position = self.collection.position();
|
||||
let action = self.collection.run(context, _clear_variables)?;
|
||||
let collection = if let Action::Return(value) = action {
|
||||
value
|
||||
} else {
|
||||
@ -142,22 +120,18 @@ impl AbstractNode for MapIndex {
|
||||
));
|
||||
};
|
||||
|
||||
if let (ValueInner::Map(map), Expression::Identifier(identifier)) =
|
||||
(collection.inner().as_ref(), &self.right)
|
||||
{
|
||||
if let ValueInner::Map(map) = collection.inner().as_ref() {
|
||||
let action = map
|
||||
.get(&identifier.node)
|
||||
.get(&self.index.node)
|
||||
.map(|value| Action::Return(value.clone()))
|
||||
.unwrap_or(Action::None);
|
||||
|
||||
Ok(action)
|
||||
} else {
|
||||
Err(RuntimeError::ValidationFailure(
|
||||
ValidationError::CannotIndexWith {
|
||||
collection_type: collection.r#type(context)?,
|
||||
collection_position,
|
||||
index_type: self.right.expected_type(context)?,
|
||||
index_position: self.right.position(),
|
||||
ValidationError::CannotIndex {
|
||||
r#type: collection.r#type(context)?,
|
||||
position: collection_position,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
@ -88,10 +88,10 @@ impl AbstractNode for Math {
|
||||
}
|
||||
}
|
||||
|
||||
fn run(self, _context: &Context) -> Result<Action, RuntimeError> {
|
||||
fn run(self, _context: &mut Context, _clear_variables: bool) -> Result<Action, RuntimeError> {
|
||||
let run_and_expect_value =
|
||||
|position: SourcePosition, expression: Expression| -> Result<Value, RuntimeError> {
|
||||
let action = expression.run(_context)?;
|
||||
let action = expression.run(&mut _context.clone(), _clear_variables)?;
|
||||
let value = if let Action::Return(value) = action {
|
||||
value
|
||||
} else {
|
||||
|
@ -98,13 +98,17 @@ impl AbstractTree {
|
||||
AbstractTree(statements)
|
||||
}
|
||||
|
||||
pub fn run(self, context: &Context) -> Result<Option<Value>, Vec<Error>> {
|
||||
pub fn run(
|
||||
self,
|
||||
context: &mut Context,
|
||||
clear_variables: bool,
|
||||
) -> Result<Option<Value>, Vec<Error>> {
|
||||
let valid_statements = self.validate(context)?;
|
||||
let mut previous_value = None;
|
||||
|
||||
for statement in valid_statements {
|
||||
let position = statement.position();
|
||||
let run = statement.run(context);
|
||||
let run = statement.run(context, clear_variables);
|
||||
|
||||
match run {
|
||||
Ok(action) => match action {
|
||||
@ -124,7 +128,7 @@ impl AbstractTree {
|
||||
Ok(previous_value)
|
||||
}
|
||||
|
||||
fn validate(self, context: &Context) -> Result<Vec<Statement>, Vec<Error>> {
|
||||
fn validate(self, context: &mut Context) -> Result<Vec<Statement>, Vec<Error>> {
|
||||
let mut errors = Vec::new();
|
||||
let mut valid_statements = Vec::new();
|
||||
|
||||
@ -139,7 +143,7 @@ impl AbstractTree {
|
||||
} else if errors.is_empty() {
|
||||
if let Statement::StructureDefinition(_) = statement {
|
||||
let position = statement.position();
|
||||
let run = statement.run(context);
|
||||
let run = statement.run(context, true);
|
||||
|
||||
if let Err(runtime_error) = run {
|
||||
errors.push(Error::Runtime {
|
||||
@ -176,5 +180,5 @@ impl Index<usize> for AbstractTree {
|
||||
pub trait AbstractNode: Sized {
|
||||
fn expected_type(&self, context: &Context) -> Result<Type, ValidationError>;
|
||||
fn validate(&self, context: &Context) -> Result<(), ValidationError>;
|
||||
fn run(self, context: &Context) -> Result<Action, RuntimeError>;
|
||||
fn run(self, context: &mut Context, clear_variables: bool) -> Result<Action, RuntimeError>;
|
||||
}
|
||||
|
@ -70,19 +70,25 @@ impl AbstractNode for Statement {
|
||||
}
|
||||
}
|
||||
|
||||
fn run(self, _context: &Context) -> Result<Action, RuntimeError> {
|
||||
match self {
|
||||
Statement::Assignment(assignment) => assignment.node.run(_context),
|
||||
Statement::AsyncBlock(async_block) => async_block.node.run(_context),
|
||||
Statement::Block(block) => block.node.run(_context),
|
||||
fn run(self, context: &mut Context, clear_variables: bool) -> Result<Action, RuntimeError> {
|
||||
let result = match self {
|
||||
Statement::Assignment(assignment) => assignment.node.run(context, clear_variables),
|
||||
Statement::AsyncBlock(async_block) => async_block.node.run(context, clear_variables),
|
||||
Statement::Block(block) => block.node.run(context, clear_variables),
|
||||
Statement::Break(_) => Ok(Action::Break),
|
||||
Statement::Expression(expression) => expression.run(_context),
|
||||
Statement::IfElse(if_else) => if_else.node.run(_context),
|
||||
Statement::Loop(r#loop) => r#loop.node.run(_context),
|
||||
Statement::While(r#while) => r#while.node.run(_context),
|
||||
Statement::Expression(expression) => expression.run(context, clear_variables),
|
||||
Statement::IfElse(if_else) => if_else.node.run(context, clear_variables),
|
||||
Statement::Loop(r#loop) => r#loop.node.run(context, clear_variables),
|
||||
Statement::While(r#while) => r#while.node.run(context, clear_variables),
|
||||
Statement::StructureDefinition(structure_definition) => {
|
||||
structure_definition.node.run(_context)
|
||||
}
|
||||
}
|
||||
structure_definition.node.run(context, clear_variables)
|
||||
}
|
||||
};
|
||||
|
||||
if clear_variables {
|
||||
context.clean()?;
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ impl AbstractNode for StructureDefinition {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run(self, context: &Context) -> Result<Action, RuntimeError> {
|
||||
fn run(self, context: &mut Context, _clear_variables: bool) -> Result<Action, RuntimeError> {
|
||||
let struct_type = Type::Structure {
|
||||
name: self.name.clone(),
|
||||
fields: self.fields,
|
||||
|
@ -152,7 +152,7 @@ impl AbstractNode for Type {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run(self, _: &Context) -> Result<Action, RuntimeError> {
|
||||
fn run(self, _context: &mut Context, _clear_variables: bool) -> Result<Action, RuntimeError> {
|
||||
Ok(Action::None)
|
||||
}
|
||||
}
|
||||
|
@ -181,7 +181,7 @@ impl AbstractNode for ValueNode {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run(self, _context: &Context) -> Result<Action, RuntimeError> {
|
||||
fn run(self, _context: &mut Context, _clear_variables: bool) -> Result<Action, RuntimeError> {
|
||||
let value = match self {
|
||||
ValueNode::Boolean(boolean) => Value::boolean(boolean),
|
||||
ValueNode::Float(float) => Value::float(float),
|
||||
@ -191,7 +191,7 @@ impl AbstractNode for ValueNode {
|
||||
|
||||
for expression in expression_list {
|
||||
let expression_position = expression.position();
|
||||
let action = expression.run(_context)?;
|
||||
let action = expression.run(_context, _clear_variables)?;
|
||||
let value = if let Action::Return(value) = action {
|
||||
WithPosition {
|
||||
node: value,
|
||||
@ -213,7 +213,7 @@ impl AbstractNode for ValueNode {
|
||||
|
||||
for (identifier, _type, expression) in property_list {
|
||||
let expression_position = expression.position();
|
||||
let action = expression.run(_context)?;
|
||||
let action = expression.run(_context, _clear_variables)?;
|
||||
let value = if let Action::Return(value) = action {
|
||||
value
|
||||
} else {
|
||||
@ -243,7 +243,7 @@ impl AbstractNode for ValueNode {
|
||||
|
||||
for (identifier, expression) in expressions {
|
||||
let expression_position = expression.position();
|
||||
let action = expression.run(_context)?;
|
||||
let action = expression.run(_context, _clear_variables)?;
|
||||
let value = if let Action::Return(value) = action {
|
||||
value
|
||||
} else {
|
||||
|
@ -37,10 +37,13 @@ impl AbstractNode for While {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run(self, _context: &Context) -> Result<Action, RuntimeError> {
|
||||
fn run(self, _context: &mut Context, _clear_variables: bool) -> Result<Action, RuntimeError> {
|
||||
let get_boolean = || -> Result<Value, RuntimeError> {
|
||||
let expression_position = self.expression.position();
|
||||
let action = self.expression.clone().run(_context)?;
|
||||
let action = self
|
||||
.expression
|
||||
.clone()
|
||||
.run(&mut _context.clone(), _clear_variables)?;
|
||||
|
||||
if let Action::Return(value) = action {
|
||||
Ok(value)
|
||||
@ -53,7 +56,9 @@ impl AbstractNode for While {
|
||||
|
||||
while let ValueInner::Boolean(true) = get_boolean()?.inner().as_ref() {
|
||||
for statement in &self.statements {
|
||||
let action = statement.clone().run(_context)?;
|
||||
let action = statement
|
||||
.clone()
|
||||
.run(&mut _context.clone(), _clear_variables)?;
|
||||
|
||||
match action {
|
||||
Action::Return(_) => {}
|
||||
@ -66,63 +71,3 @@ impl AbstractNode for While {
|
||||
Ok(Action::None)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{
|
||||
abstract_tree::{Assignment, AssignmentOperator, Block, Logic, ValueNode, WithPos},
|
||||
identifier::Identifier,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn simple_while_loop() {
|
||||
let action = Statement::Block(
|
||||
Block::new(vec![
|
||||
Statement::Assignment(
|
||||
Assignment::new(
|
||||
Identifier::new("i").with_position((0, 0)),
|
||||
None,
|
||||
AssignmentOperator::Assign,
|
||||
Statement::Expression(Expression::Value(
|
||||
ValueNode::Integer(3).with_position((0, 0)),
|
||||
)),
|
||||
)
|
||||
.with_position((0, 0)),
|
||||
),
|
||||
Statement::While(
|
||||
While::new(
|
||||
Expression::Logic(
|
||||
Box::new(Logic::Less(
|
||||
Expression::Identifier(Identifier::new("i").with_position((0, 0))),
|
||||
Expression::Value(ValueNode::Integer(3).with_position((0, 0))),
|
||||
))
|
||||
.with_position((0, 0)),
|
||||
),
|
||||
vec![Statement::Assignment(
|
||||
Assignment::new(
|
||||
Identifier::new("i").with_position((0, 0)),
|
||||
None,
|
||||
AssignmentOperator::AddAssign,
|
||||
Statement::Expression(Expression::Value(
|
||||
ValueNode::Integer(1).with_position((0, 0)),
|
||||
)),
|
||||
)
|
||||
.with_position((0, 0)),
|
||||
)],
|
||||
)
|
||||
.with_position((0, 0)),
|
||||
),
|
||||
Statement::Expression(Expression::Identifier(
|
||||
Identifier::new("i").with_position((0, 0)),
|
||||
)),
|
||||
])
|
||||
.with_position((0, 0)),
|
||||
)
|
||||
.run(&Context::new())
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(action, Action::Return(Value::integer(3)))
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,8 @@ use std::{
|
||||
sync::{Arc, RwLock, RwLockReadGuard},
|
||||
};
|
||||
|
||||
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
||||
|
||||
use crate::{
|
||||
abstract_tree::Type,
|
||||
error::{RwLockPoisonError, ValidationError},
|
||||
@ -12,7 +14,7 @@ use crate::{
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Context {
|
||||
inner: Arc<RwLock<BTreeMap<Identifier, ValueData>>>,
|
||||
inner: Arc<RwLock<BTreeMap<Identifier, (ValueData, UsageData)>>>,
|
||||
}
|
||||
|
||||
impl Context {
|
||||
@ -22,7 +24,7 @@ impl Context {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_data(data: BTreeMap<Identifier, ValueData>) -> Self {
|
||||
pub fn with_data(data: BTreeMap<Identifier, (ValueData, UsageData)>) -> Self {
|
||||
Self {
|
||||
inner: Arc::new(RwLock::new(data)),
|
||||
}
|
||||
@ -30,16 +32,17 @@ impl Context {
|
||||
|
||||
pub fn inner(
|
||||
&self,
|
||||
) -> Result<RwLockReadGuard<BTreeMap<Identifier, ValueData>>, RwLockPoisonError> {
|
||||
) -> Result<RwLockReadGuard<BTreeMap<Identifier, (ValueData, UsageData)>>, RwLockPoisonError>
|
||||
{
|
||||
Ok(self.inner.read()?)
|
||||
}
|
||||
|
||||
pub fn inherit_types_from(&self, other: &Context) -> Result<(), RwLockPoisonError> {
|
||||
let mut self_data = self.inner.write()?;
|
||||
|
||||
for (identifier, value_data) in other.inner.read()?.iter() {
|
||||
for (identifier, (value_data, usage_data)) in other.inner.read()?.iter() {
|
||||
if let ValueData::Type(Type::Function { .. }) = value_data {
|
||||
self_data.insert(identifier.clone(), value_data.clone());
|
||||
self_data.insert(identifier.clone(), (value_data.clone(), usage_data.clone()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,8 +52,8 @@ impl Context {
|
||||
pub fn inherit_data_from(&self, other: &Context) -> Result<(), RwLockPoisonError> {
|
||||
let mut self_data = self.inner.write()?;
|
||||
|
||||
for (identifier, value_data) in other.inner.read()?.iter() {
|
||||
self_data.insert(identifier.clone(), value_data.clone());
|
||||
for (identifier, (value_data, usage_data)) in other.inner.read()?.iter() {
|
||||
self_data.insert(identifier.clone(), (value_data.clone(), usage_data.clone()));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@ -61,7 +64,9 @@ impl Context {
|
||||
}
|
||||
|
||||
pub fn get_type(&self, identifier: &Identifier) -> Result<Option<Type>, ValidationError> {
|
||||
if let Some(value_data) = self.inner.read()?.get(identifier) {
|
||||
if let Some((value_data, _)) = self.inner.read()?.get(identifier) {
|
||||
log::trace!("Using {identifier}'s type.");
|
||||
|
||||
let r#type = match value_data {
|
||||
ValueData::Type(r#type) => r#type.clone(),
|
||||
ValueData::Value(value) => value.r#type(self)?,
|
||||
@ -73,8 +78,13 @@ impl Context {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_value(&self, identifier: &Identifier) -> Result<Option<Value>, RwLockPoisonError> {
|
||||
if let Some(ValueData::Value(value)) = self.inner.read()?.get(identifier) {
|
||||
pub fn use_value(&self, identifier: &Identifier) -> Result<Option<Value>, RwLockPoisonError> {
|
||||
if let Some((ValueData::Value(value), usage_data)) = self.inner.write()?.get_mut(identifier)
|
||||
{
|
||||
log::trace!("Using {identifier}'s value.");
|
||||
|
||||
usage_data.actual += 1;
|
||||
|
||||
Ok(Some(value.clone()))
|
||||
} else {
|
||||
Ok(None)
|
||||
@ -82,26 +92,75 @@ impl Context {
|
||||
}
|
||||
|
||||
pub fn set_type(&self, identifier: Identifier, r#type: Type) -> Result<(), RwLockPoisonError> {
|
||||
log::info!("Setting {identifier} to type {}.", r#type);
|
||||
|
||||
self.inner
|
||||
.write()?
|
||||
.insert(identifier, ValueData::Type(r#type));
|
||||
.insert(identifier, (ValueData::Type(r#type), UsageData::new()));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_value(&self, identifier: Identifier, value: Value) -> Result<(), RwLockPoisonError> {
|
||||
self.inner
|
||||
.write()?
|
||||
.insert(identifier, ValueData::Value(value));
|
||||
log::info!("Setting {identifier} to value {value}.");
|
||||
|
||||
let mut inner = self.inner.write()?;
|
||||
let old_usage_data = inner.remove(&identifier).map(|(_, usage_data)| usage_data);
|
||||
|
||||
if let Some(usage_data) = old_usage_data {
|
||||
inner.insert(identifier, (ValueData::Value(value), usage_data));
|
||||
} else {
|
||||
inner.insert(identifier, (ValueData::Value(value), UsageData::new()));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn remove(&self, identifier: &Identifier) -> Result<Option<ValueData>, RwLockPoisonError> {
|
||||
let removed = self.inner.write()?.remove(identifier);
|
||||
let removed = self
|
||||
.inner
|
||||
.write()?
|
||||
.remove(identifier)
|
||||
.map(|(value_data, _)| value_data);
|
||||
|
||||
Ok(removed)
|
||||
}
|
||||
|
||||
pub fn clean(&mut self) -> Result<(), RwLockPoisonError> {
|
||||
let clean_variables = self
|
||||
.inner
|
||||
.write()?
|
||||
.clone()
|
||||
.into_par_iter()
|
||||
.filter(|(identifier, (_, usage_data))| {
|
||||
if usage_data.actual < usage_data.expected {
|
||||
true
|
||||
} else {
|
||||
log::debug!("Removing variable {identifier}.");
|
||||
|
||||
false
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
self.inner = Arc::new(RwLock::new(clean_variables));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn add_expected_use(&self, identifier: &Identifier) -> Result<bool, RwLockPoisonError> {
|
||||
let mut inner = self.inner.write()?;
|
||||
|
||||
if let Some((_, usage_data)) = inner.get_mut(identifier) {
|
||||
log::trace!("Adding expected use for variable {identifier}.");
|
||||
|
||||
usage_data.expected += 1;
|
||||
|
||||
Ok(true)
|
||||
} else {
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
@ -109,3 +168,18 @@ pub enum ValueData {
|
||||
Type(Type),
|
||||
Value(Value),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct UsageData {
|
||||
pub actual: u32,
|
||||
pub expected: u32,
|
||||
}
|
||||
|
||||
impl UsageData {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
actual: 0,
|
||||
expected: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ pub fn interpret_without_std(
|
||||
source_id: &str,
|
||||
source: &str,
|
||||
) -> Result<Option<Value>, InterpreterError> {
|
||||
let interpreter = Interpreter::new(Context::new());
|
||||
let mut interpreter = Interpreter::new(Context::new());
|
||||
|
||||
interpreter.run(Arc::from(source_id.to_string()), Arc::from(source))
|
||||
}
|
||||
@ -52,7 +52,7 @@ impl Interpreter {
|
||||
}
|
||||
|
||||
pub fn run(
|
||||
&self,
|
||||
&mut self,
|
||||
source_id: Arc<str>,
|
||||
source: Arc<str>,
|
||||
) -> Result<Option<Value>, InterpreterError> {
|
||||
@ -70,7 +70,7 @@ impl Interpreter {
|
||||
errors,
|
||||
})?;
|
||||
let value_option = abstract_tree
|
||||
.run(&self.context)
|
||||
.run(&mut self.context, true)
|
||||
.map_err(|errors| InterpreterError { source_id, errors })?;
|
||||
|
||||
Ok(value_option)
|
||||
@ -134,7 +134,7 @@ impl Interpreter {
|
||||
};
|
||||
|
||||
abstract_tree
|
||||
.run(&self.context)
|
||||
.run(&mut self.context.clone(), false)
|
||||
.map_err(|errors| InterpreterError { source_id, errors })
|
||||
.err()
|
||||
});
|
||||
|
@ -322,13 +322,29 @@ pub fn parser<'src>(
|
||||
just(Token::Control(Control::DoubleColon)),
|
||||
);
|
||||
|
||||
let atom = choice((
|
||||
range.clone(),
|
||||
let map_atom = choice((
|
||||
map.clone(),
|
||||
structure_instance.clone(),
|
||||
identifier_expression.clone(),
|
||||
));
|
||||
|
||||
let map_index = map_atom
|
||||
.then_ignore(just(Token::Control(Control::Dot)))
|
||||
.then(positioned_identifier.clone())
|
||||
.map_with(|(expression, identifier), state| {
|
||||
Expression::MapIndex(
|
||||
Box::new(MapIndex::new(expression, identifier)).with_position(state.span()),
|
||||
)
|
||||
});
|
||||
|
||||
let atom = choice((
|
||||
map_index.clone(),
|
||||
range.clone(),
|
||||
parsed_function.clone(),
|
||||
list.clone(),
|
||||
map.clone(),
|
||||
basic_value.clone(),
|
||||
map.clone(),
|
||||
structure_instance.clone(),
|
||||
identifier_expression.clone(),
|
||||
expression.clone().delimited_by(
|
||||
just(Token::Control(Control::ParenOpen)),
|
||||
@ -384,15 +400,6 @@ pub fn parser<'src>(
|
||||
)
|
||||
},
|
||||
),
|
||||
infix(
|
||||
left(4),
|
||||
just(Token::Control(Control::Dot)),
|
||||
|left, _, right, span| {
|
||||
Expression::MapIndex(
|
||||
Box::new(MapIndex::new(left, right)).with_position(span),
|
||||
)
|
||||
},
|
||||
),
|
||||
infix(
|
||||
left(1),
|
||||
just(Token::Operator(Operator::Equal)),
|
||||
@ -493,8 +500,9 @@ pub fn parser<'src>(
|
||||
));
|
||||
|
||||
choice((
|
||||
built_in_function_call,
|
||||
logic_math_indexes_and_function_calls,
|
||||
map_index,
|
||||
built_in_function_call,
|
||||
range,
|
||||
structure_instance,
|
||||
parsed_function,
|
||||
@ -765,7 +773,7 @@ mod tests {
|
||||
)])
|
||||
.with_position((0, 10))
|
||||
),
|
||||
Expression::Identifier(Identifier::new("x").with_position((11, 12)))
|
||||
Identifier::new("x").with_position((11, 12))
|
||||
))
|
||||
.with_position((0, 12))
|
||||
))
|
||||
@ -775,7 +783,7 @@ mod tests {
|
||||
Statement::Expression(Expression::MapIndex(
|
||||
Box::new(MapIndex::new(
|
||||
Expression::Identifier(Identifier::new("foo").with_position((0, 3))),
|
||||
Expression::Identifier(Identifier::new("x").with_position((4, 5)))
|
||||
Identifier::new("x").with_position((4, 5))
|
||||
))
|
||||
.with_position((0, 5))
|
||||
))
|
||||
@ -924,22 +932,14 @@ mod tests {
|
||||
#[test]
|
||||
fn function_call() {
|
||||
assert_eq!(
|
||||
parse(&lex("io.read_line()").unwrap()).unwrap()[0],
|
||||
parse(&lex("foobar()").unwrap()).unwrap()[0],
|
||||
Statement::Expression(Expression::FunctionCall(
|
||||
FunctionCall::new(
|
||||
Expression::MapIndex(
|
||||
Box::new(MapIndex::new(
|
||||
Expression::Identifier(Identifier::new("io").with_position((0, 2))),
|
||||
Expression::Identifier(
|
||||
Identifier::new("read_line").with_position((3, 12))
|
||||
)
|
||||
))
|
||||
.with_position((0, 12))
|
||||
),
|
||||
Expression::Identifier(Identifier::new("foobar").with_position((0, 6))),
|
||||
Vec::with_capacity(0),
|
||||
Vec::with_capacity(0),
|
||||
)
|
||||
.with_position((0, 14))
|
||||
.with_position((0, 8))
|
||||
))
|
||||
)
|
||||
}
|
||||
|
@ -6,12 +6,6 @@ use std::{
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use stanza::{
|
||||
renderer::{console::Console, Renderer},
|
||||
style::{HAlign, MinWidth, Styles},
|
||||
table::Table,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
abstract_tree::{AbstractNode, Action, Block, Type, WithPos, WithPosition},
|
||||
context::Context,
|
||||
@ -104,31 +98,31 @@ impl Value {
|
||||
|
||||
impl Display for Value {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
fn create_table() -> Table {
|
||||
Table::with_styles(Styles::default().with(HAlign::Centred).with(MinWidth(3)))
|
||||
}
|
||||
|
||||
match self.inner().as_ref() {
|
||||
ValueInner::Boolean(boolean) => write!(f, "{boolean}"),
|
||||
ValueInner::Float(float) => write!(f, "{float}"),
|
||||
ValueInner::Integer(integer) => write!(f, "{integer}"),
|
||||
ValueInner::List(list) => {
|
||||
let mut table = create_table();
|
||||
write!(f, "[")?;
|
||||
|
||||
for value in list {
|
||||
table = table.with_row([value.node.to_string()]);
|
||||
for (index, value) in list.into_iter().enumerate() {
|
||||
if index == list.len() - 1 {
|
||||
write!(f, "{}", value.node)?;
|
||||
} else {
|
||||
write!(f, "{}, ", value.node)?;
|
||||
}
|
||||
}
|
||||
|
||||
write!(f, "{}", Console::default().render(&table))
|
||||
write!(f, "]")
|
||||
}
|
||||
ValueInner::Map(map) => {
|
||||
let mut table = create_table();
|
||||
write!(f, "[")?;
|
||||
|
||||
for (identifier, value) in map {
|
||||
table = table.with_row([identifier.as_str(), &value.to_string()]);
|
||||
for (key, value) in map {
|
||||
writeln!(f, "{key} = {value},")?;
|
||||
}
|
||||
|
||||
write!(f, "{}", Console::default().render(&table))
|
||||
write!(f, "]")
|
||||
}
|
||||
ValueInner::Range(_) => todo!(),
|
||||
ValueInner::String(string) => write!(f, "{string}"),
|
||||
@ -161,13 +155,13 @@ impl Display for Value {
|
||||
write!(f, "): {} {:?}", return_type.node, body.node)
|
||||
}
|
||||
ValueInner::Structure { name, fields } => {
|
||||
let mut table = create_table();
|
||||
write!(f, "{}\n{{", name.node)?;
|
||||
|
||||
for (identifier, value) in fields {
|
||||
table = table.with_row([identifier.as_str(), &value.to_string()]);
|
||||
for (key, value) in fields {
|
||||
writeln!(f, "{key} = {value},")?;
|
||||
}
|
||||
|
||||
write!(f, "{}\n{}", name.node, Console::default().render(&table))
|
||||
write!(f, "}}")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -318,11 +312,15 @@ impl Function {
|
||||
&self.type_parameters
|
||||
}
|
||||
|
||||
pub fn call(self, arguments: Vec<Value>, context: Context) -> Result<Action, RuntimeError> {
|
||||
pub fn call(
|
||||
self,
|
||||
arguments: Vec<Value>,
|
||||
context: &mut Context,
|
||||
) -> Result<Action, RuntimeError> {
|
||||
for ((identifier, _), value) in self.parameters.into_iter().zip(arguments.into_iter()) {
|
||||
context.set_value(identifier.clone(), value)?;
|
||||
}
|
||||
|
||||
self.body.node.run(&context)
|
||||
self.body.node.run(context, true)
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ use reedline::{
|
||||
};
|
||||
|
||||
pub fn run_shell(context: Context) -> Result<(), io::Error> {
|
||||
let interpreter = Interpreter::new(context.clone());
|
||||
let mut interpreter = Interpreter::new(context.clone());
|
||||
let mut keybindings = default_emacs_keybindings();
|
||||
|
||||
keybindings.add_binding(
|
||||
@ -222,7 +222,7 @@ impl Completer for DustCompleter {
|
||||
}
|
||||
}
|
||||
|
||||
for (key, value_data) in self.context.inner().unwrap().iter() {
|
||||
for (key, (value_data, _)) in self.context.inner().unwrap().iter() {
|
||||
let description = match value_data {
|
||||
ValueData::Value(value) => value.to_string(),
|
||||
ValueData::Type(r#type) => r#type.to_string(),
|
||||
|
Loading…
Reference in New Issue
Block a user