Implement type checking for functions and indexes
This commit is contained in:
parent
b91e23fef3
commit
ce4d366bab
@ -1,4 +1,4 @@
|
||||
create_random_numbers <(int)> = fn |count| {
|
||||
create_random_numbers = (fn count <int>) <any> {
|
||||
numbers = []
|
||||
|
||||
while (length numbers) < count {
|
||||
|
@ -4,26 +4,26 @@ all_cards = {
|
||||
weapons = ['Rope' 'Lead_Pipe' 'Knife']
|
||||
}
|
||||
|
||||
is_ready_to_solve <(map) -> bool> = fn |cards| {
|
||||
is_ready_to_solve = (fn cards <map>) <bool> {
|
||||
((length cards:suspects) == 1)
|
||||
&& ((length cards:rooms) == 1)
|
||||
&& ((length cards:weapons) == 1)
|
||||
}
|
||||
|
||||
take_turn <(map str str) -> map> = fn |cards opponent_card current_room| {
|
||||
take_turn = (fn cards <map>, opponent_card <str>, current_room <str>) <map> {
|
||||
cards = (remove_card opponent_card cards)
|
||||
cards = (make_guess current_room cards)
|
||||
cards
|
||||
}
|
||||
|
||||
remove_card <(map str) -> map> = fn |cards opponent_card| {
|
||||
remove_card = (fn cards <map>, opponent_card <str>) <map> {
|
||||
cards:rooms -= opponent_card
|
||||
cards:suspects -= opponent_card
|
||||
cards:weapons -= opponent_card
|
||||
cards
|
||||
}
|
||||
|
||||
make_guess <(map str)> = fn |cards current_room| {
|
||||
make_guess = (fn cards <map> current_room <str>) <map> {
|
||||
if (is_ready_to_solve cards) {
|
||||
(output 'It was '
|
||||
+ cards:suspects:0
|
||||
|
@ -1,6 +1,6 @@
|
||||
1 -> (output)
|
||||
|
||||
add_one <([int]) -> [int]> = fn |numbers| {
|
||||
add_one = (fn numbers <[int]>) <[int]> {
|
||||
new_numbers = []
|
||||
|
||||
for number in numbers {
|
||||
|
@ -57,9 +57,14 @@ impl AbstractTree for Assignment {
|
||||
|
||||
let statement_node = node.child(child_count - 1).unwrap();
|
||||
let statement = Statement::from_syntax_node(source, statement_node, context)?;
|
||||
let statement_type = statement.expected_type(context)?;
|
||||
|
||||
if let Some(type_definition) = &type_definition {
|
||||
let statement_type = statement.expected_type(context)?;
|
||||
context.set(
|
||||
identifier.inner().clone(),
|
||||
Value::Empty,
|
||||
Some(type_definition.inner().clone()),
|
||||
)?;
|
||||
|
||||
match operator {
|
||||
AssignmentOperator::Equal => {
|
||||
@ -78,22 +83,6 @@ impl AbstractTree for Assignment {
|
||||
}
|
||||
AssignmentOperator::MinusEqual => todo!(),
|
||||
}
|
||||
} else if let Some((_previous_value, previous_type)) =
|
||||
context.variables()?.get(identifier.inner())
|
||||
{
|
||||
let statement_type = statement.expected_type(context)?;
|
||||
let type_check = if let Type::List(item_type) = previous_type {
|
||||
item_type.check(&statement_type)
|
||||
} else {
|
||||
previous_type.check(&statement_type)
|
||||
};
|
||||
|
||||
if let Err(error) = type_check {
|
||||
return Err(error.with_context(
|
||||
statement_node.start_position(),
|
||||
source[statement_node.byte_range()].to_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Assignment {
|
||||
@ -129,6 +118,8 @@ impl AbstractTree for Assignment {
|
||||
};
|
||||
|
||||
if let Some(type_defintion) = &self.type_definition {
|
||||
type_defintion.inner().check(&new_value.r#type())?;
|
||||
|
||||
context.set(key.clone(), new_value, Some(type_defintion.inner().clone()))?;
|
||||
} else {
|
||||
context.set(key.clone(), new_value, None)?;
|
||||
|
@ -57,9 +57,7 @@ impl AbstractTree for For {
|
||||
values.par_iter().try_for_each(|value| {
|
||||
let mut iter_context = Map::clone_from(context)?;
|
||||
|
||||
iter_context
|
||||
.variables_mut()?
|
||||
.insert(key.clone(), (value.clone(), value.r#type()));
|
||||
iter_context.set(key.clone(), value.clone(), None)?;
|
||||
|
||||
self.block.run(source, &mut iter_context).map(|_value| ())
|
||||
})?;
|
||||
@ -67,9 +65,7 @@ impl AbstractTree for For {
|
||||
let loop_context = Map::clone_from(context)?;
|
||||
|
||||
for value in values.iter() {
|
||||
loop_context
|
||||
.variables_mut()?
|
||||
.insert(key.clone(), (value.clone(), value.r#type()));
|
||||
loop_context.set(key.clone(), value.clone(), None)?;
|
||||
|
||||
self.block.run(source, &mut loop_context.clone())?;
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ impl AbstractTree for FunctionCall {
|
||||
|
||||
let expression_node = node.child(1).unwrap();
|
||||
let function_expression = Expression::from_syntax_node(source, expression_node, context)?;
|
||||
let function_type = function_expression.expected_type(context)?;
|
||||
|
||||
let mut arguments = Vec::new();
|
||||
|
||||
@ -34,24 +35,28 @@ impl AbstractTree for FunctionCall {
|
||||
|
||||
if child.is_named() {
|
||||
let expression = Expression::from_syntax_node(source, child, context)?;
|
||||
|
||||
arguments.push(expression);
|
||||
}
|
||||
}
|
||||
|
||||
let function_type = function_expression.expected_type(context)?;
|
||||
let expression_type = expression.expected_type(context)?;
|
||||
let argument_index = arguments.len();
|
||||
|
||||
if let Type::Function {
|
||||
parameter_types,
|
||||
return_type: _,
|
||||
} = function_type
|
||||
} = &function_type
|
||||
{
|
||||
let argument_type_pairs = arguments.iter().zip(parameter_types.iter());
|
||||
let expected_type = parameter_types.get(argument_index).unwrap();
|
||||
|
||||
for (argument, r#type) in argument_type_pairs {
|
||||
let argument_type = argument.expected_type(context)?;
|
||||
println!("{expected_type} {expression_type}");
|
||||
|
||||
r#type.check(&argument_type)?;
|
||||
expected_type
|
||||
.check(&expression_type)
|
||||
.map_err(|error| Error::WithContext {
|
||||
error: Box::new(error),
|
||||
location: child.start_position(),
|
||||
source: source[child.byte_range()].to_string(),
|
||||
})?;
|
||||
}
|
||||
|
||||
arguments.push(expression);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -47,7 +47,9 @@ impl AbstractTree for Identifier {
|
||||
} else {
|
||||
for built_in_function in BUILT_IN_FUNCTIONS {
|
||||
if self.0 == built_in_function.name() {
|
||||
return Ok(built_in_function.r#type());
|
||||
if let Type::Function { return_type, .. } = built_in_function.r#type() {
|
||||
return Ok(*return_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -88,7 +88,12 @@ impl AbstractTree for Index {
|
||||
}
|
||||
|
||||
fn expected_type(&self, context: &Map) -> Result<Type> {
|
||||
self.collection.expected_type(context)
|
||||
match self.collection.expected_type(context)? {
|
||||
Type::List(item_type) => Ok(*item_type.clone()),
|
||||
Type::Map => Ok(Type::Any),
|
||||
Type::Empty => Ok(Type::Empty),
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -85,11 +85,8 @@ impl AbstractTree for IndexAssignment {
|
||||
}
|
||||
AssignmentOperator::Equal => value,
|
||||
};
|
||||
let new_value_type = new_value.r#type();
|
||||
|
||||
index_context
|
||||
.variables_mut()?
|
||||
.insert(index_key.clone(), (new_value, new_value_type));
|
||||
index_context.set(index_key.clone(), new_value, None)?;
|
||||
|
||||
Ok(Value::Empty)
|
||||
}
|
||||
|
@ -76,8 +76,10 @@ impl AbstractTree for Match {
|
||||
}
|
||||
}
|
||||
|
||||
fn expected_type(&self, _context: &Map) -> Result<Type> {
|
||||
todo!()
|
||||
fn expected_type(&self, context: &Map) -> Result<Type> {
|
||||
let (_, first_statement) = self.options.first().unwrap();
|
||||
|
||||
first_statement.expected_type(context)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,7 @@ pub mod logic;
|
||||
pub mod r#match;
|
||||
pub mod math;
|
||||
pub mod statement;
|
||||
pub mod type_defintion;
|
||||
pub mod type_definition;
|
||||
pub mod r#use;
|
||||
pub mod value_node;
|
||||
pub mod r#while;
|
||||
@ -28,7 +28,7 @@ pub mod r#yield;
|
||||
pub use {
|
||||
assignment::*, block::*, expression::*, function_call::*, identifier::*, if_else::*, index::*,
|
||||
index_assignment::IndexAssignment, logic::*, math::*, r#for::*, r#match::*, r#use::*,
|
||||
r#while::*, r#yield::*, statement::*, type_defintion::*, value_node::*,
|
||||
r#while::*, r#yield::*, statement::*, type_definition::*, value_node::*,
|
||||
};
|
||||
|
||||
use tree_sitter::Node;
|
||||
|
@ -100,10 +100,24 @@ impl Type {
|
||||
.zip(other_parameter_types.iter());
|
||||
|
||||
for (self_parameter_type, other_parameter_type) in parameter_type_pairs {
|
||||
self_parameter_type.check(&other_parameter_type)?;
|
||||
let check = self_parameter_type.check(&other_parameter_type);
|
||||
|
||||
if let Err(Error::TypeCheck { .. }) = check {
|
||||
return Err(Error::TypeCheck {
|
||||
expected: self.clone(),
|
||||
actual: other.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
self_return_type.check(other_return_type)?;
|
||||
let check = self_return_type.check(other_return_type);
|
||||
|
||||
if let Err(Error::TypeCheck { .. }) = check {
|
||||
return Err(Error::TypeCheck {
|
||||
expected: self.clone(),
|
||||
actual: other.clone(),
|
||||
});
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1,217 +0,0 @@
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tree_sitter::Node;
|
||||
|
||||
use crate::{AbstractTree, Error, Map, Result, Value};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct TypeDefinition {
|
||||
r#type: Type,
|
||||
}
|
||||
|
||||
impl TypeDefinition {
|
||||
pub fn new(r#type: Type) -> Self {
|
||||
Self { r#type }
|
||||
}
|
||||
|
||||
pub fn inner(&self) -> &Type {
|
||||
&self.r#type
|
||||
}
|
||||
|
||||
pub fn take_inner(self) -> Type {
|
||||
self.r#type
|
||||
}
|
||||
}
|
||||
|
||||
impl AbstractTree for TypeDefinition {
|
||||
fn from_syntax_node(source: &str, node: Node, context: &Map) -> Result<Self> {
|
||||
Error::expect_syntax_node(source, "type_definition", node)?;
|
||||
|
||||
let type_node = node.child(1).unwrap();
|
||||
let r#type = Type::from_syntax_node(source, type_node, context)?;
|
||||
|
||||
Ok(TypeDefinition { r#type })
|
||||
}
|
||||
|
||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
||||
self.r#type.run(source, context)
|
||||
}
|
||||
|
||||
fn expected_type(&self, context: &Map) -> Result<Type> {
|
||||
self.r#type.expected_type(context)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for TypeDefinition {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "<{}>", self.r#type)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub enum Type {
|
||||
Any,
|
||||
Boolean,
|
||||
Empty,
|
||||
Float,
|
||||
Function {
|
||||
parameter_types: Vec<Type>,
|
||||
return_type: Box<Type>,
|
||||
},
|
||||
Integer,
|
||||
List(Box<Type>),
|
||||
Map,
|
||||
Number,
|
||||
String,
|
||||
}
|
||||
|
||||
impl Type {
|
||||
pub fn check(&self, other: &Type) -> Result<()> {
|
||||
match (self, other) {
|
||||
(Type::Any, _)
|
||||
| (_, Type::Any)
|
||||
| (Type::Boolean, Type::Boolean)
|
||||
| (Type::Empty, Type::Empty)
|
||||
| (Type::Float, Type::Float)
|
||||
| (Type::Integer, Type::Integer)
|
||||
| (Type::Map, Type::Map)
|
||||
| (Type::Number, Type::Number)
|
||||
| (Type::Number, Type::Integer)
|
||||
| (Type::Number, Type::Float)
|
||||
| (Type::Integer, Type::Number)
|
||||
| (Type::Float, Type::Number)
|
||||
| (Type::String, Type::String) => Ok(()),
|
||||
(Type::List(self_item_type), Type::List(other_item_type)) => {
|
||||
self_item_type.check(&other_item_type)
|
||||
}
|
||||
(
|
||||
Type::Function {
|
||||
parameter_types: self_parameter_types,
|
||||
return_type: self_return_type,
|
||||
},
|
||||
Type::Function {
|
||||
parameter_types: other_parameter_types,
|
||||
return_type: other_return_type,
|
||||
},
|
||||
) => {
|
||||
let parameter_type_pairs = self_parameter_types
|
||||
.iter()
|
||||
.zip(other_parameter_types.iter());
|
||||
|
||||
for (self_parameter_type, other_parameter_type) in parameter_type_pairs {
|
||||
self_parameter_type.check(&other_parameter_type)?;
|
||||
}
|
||||
|
||||
self_return_type.check(other_return_type)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
_ => Err(Error::TypeCheck {
|
||||
expected: self.clone(),
|
||||
actual: other.clone(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AbstractTree for Type {
|
||||
fn from_syntax_node(source: &str, node: Node, context: &Map) -> Result<Self> {
|
||||
Error::expect_syntax_node(source, "type", node)?;
|
||||
|
||||
let type_node = node.child(0).unwrap();
|
||||
|
||||
let r#type = match type_node.kind() {
|
||||
"[" => {
|
||||
let item_type_node = node.child(1).unwrap();
|
||||
let item_type = Type::from_syntax_node(source, item_type_node, context)?;
|
||||
|
||||
Type::List(Box::new(item_type))
|
||||
}
|
||||
"any" => Type::Any,
|
||||
"bool" => Type::Boolean,
|
||||
"float" => Type::Float,
|
||||
"(" => {
|
||||
let child_count = node.child_count();
|
||||
let mut parameter_types = Vec::new();
|
||||
|
||||
for index in 1..child_count - 2 {
|
||||
let child = node.child(index).unwrap();
|
||||
|
||||
if child.is_named() {
|
||||
let parameter_type = Type::from_syntax_node(source, child, context)?;
|
||||
|
||||
parameter_types.push(parameter_type);
|
||||
}
|
||||
}
|
||||
|
||||
let final_node = node.child(child_count - 1).unwrap();
|
||||
let return_type = if final_node.is_named() {
|
||||
Type::from_syntax_node(source, final_node, context)?
|
||||
} else {
|
||||
Type::Empty
|
||||
};
|
||||
|
||||
Type::Function {
|
||||
parameter_types,
|
||||
return_type: Box::new(return_type),
|
||||
}
|
||||
}
|
||||
"int" => Type::Integer,
|
||||
"map" => Type::Map,
|
||||
"num" => Type::Number,
|
||||
"str" => Type::String,
|
||||
_ => {
|
||||
return Err(Error::UnexpectedSyntaxNode {
|
||||
expected: "any, bool, float, fn, int, list, map, num or str",
|
||||
actual: type_node.kind(),
|
||||
location: type_node.start_position(),
|
||||
relevant_source: source[type_node.byte_range()].to_string(),
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
Ok(r#type)
|
||||
}
|
||||
|
||||
fn run(&self, _source: &str, _context: &Map) -> Result<Value> {
|
||||
Ok(Value::Empty)
|
||||
}
|
||||
|
||||
fn expected_type(&self, _context: &Map) -> Result<Type> {
|
||||
Ok(Type::Empty)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Type {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Type::Any => write!(f, "any"),
|
||||
Type::Boolean => write!(f, "bool"),
|
||||
Type::Empty => write!(f, "empty"),
|
||||
Type::Float => write!(f, "float"),
|
||||
Type::Function {
|
||||
parameter_types,
|
||||
return_type,
|
||||
} => {
|
||||
write!(f, "(")?;
|
||||
|
||||
for parameter_type in parameter_types {
|
||||
write!(f, "{parameter_type}")?;
|
||||
|
||||
if parameter_type != parameter_types.last().unwrap() {
|
||||
write!(f, " ")?;
|
||||
}
|
||||
}
|
||||
|
||||
write!(f, ")")?;
|
||||
write!(f, " -> {return_type}")
|
||||
}
|
||||
Type::Integer => write!(f, "int"),
|
||||
Type::List(item_type) => write!(f, "[{item_type}]"),
|
||||
Type::Map => write!(f, "map"),
|
||||
Type::Number => write!(f, "num"),
|
||||
Type::String => write!(f, "str"),
|
||||
}
|
||||
}
|
||||
}
|
@ -31,8 +31,8 @@ impl AbstractTree for Use {
|
||||
|
||||
evaluate_with_context(&file_contents, &mut file_context)?;
|
||||
|
||||
for (key, value) in file_context.variables()?.iter() {
|
||||
context.variables_mut()?.insert(key.clone(), value.clone());
|
||||
for (key, (value, r#type)) in file_context.variables()?.iter() {
|
||||
context.set(key.clone(), value.clone(), Some(r#type.clone()))?;
|
||||
}
|
||||
|
||||
Ok(Value::Map(file_context))
|
||||
|
@ -145,13 +145,10 @@ impl AbstractTree for ValueNode {
|
||||
let map = Map::new();
|
||||
|
||||
{
|
||||
let mut variables = map.variables_mut()?;
|
||||
|
||||
for (key, statement) in key_statement_pairs {
|
||||
let value = statement.run(source, context)?;
|
||||
let value_type = value.r#type();
|
||||
|
||||
variables.insert(key.clone(), (value, value_type));
|
||||
map.set(key.clone(), value, None)?;
|
||||
}
|
||||
}
|
||||
|
||||
@ -252,15 +249,9 @@ mod tests {
|
||||
fn evaluate_map() {
|
||||
let map = Map::new();
|
||||
|
||||
{
|
||||
let mut variables = map.variables_mut().unwrap();
|
||||
|
||||
variables.insert("x".to_string(), (Value::Integer(1), Type::Integer));
|
||||
variables.insert(
|
||||
"foo".to_string(),
|
||||
(Value::String("bar".to_string()), Type::String),
|
||||
);
|
||||
}
|
||||
map.set("x".to_string(), Value::Integer(1), None).unwrap();
|
||||
map.set("foo".to_string(), Value::String("bar".to_string()), None)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(evaluate("{ x = 1, foo = 'bar' }"), Ok(Value::Map(map)));
|
||||
}
|
||||
|
@ -24,24 +24,14 @@ impl BuiltInFunction for Read {
|
||||
let entry = entry?;
|
||||
let file_data = Map::new();
|
||||
|
||||
{
|
||||
let mut file_data_variables = file_data.variables_mut()?;
|
||||
let name = entry.file_name().to_string_lossy().to_string();
|
||||
let metadata = entry.metadata()?;
|
||||
let created = metadata.created()?.elapsed()?.as_secs() as i64;
|
||||
let modified = metadata.modified()?.elapsed()?.as_secs() as i64;
|
||||
|
||||
file_data_variables
|
||||
.insert("name".to_string(), (Value::String(name), Type::String));
|
||||
file_data_variables.insert(
|
||||
"created".to_string(),
|
||||
(Value::Integer(created), Type::Integer),
|
||||
);
|
||||
file_data_variables.insert(
|
||||
"modified".to_string(),
|
||||
(Value::Integer(modified), Type::Integer),
|
||||
);
|
||||
}
|
||||
file_data.set("name".to_string(), Value::String(name), None)?;
|
||||
file_data.set("created".to_string(), Value::Integer(created), None)?;
|
||||
file_data.set("modified".to_string(), Value::Integer(modified), None)?;
|
||||
|
||||
files.items_mut().push(Value::Map(file_data));
|
||||
}
|
||||
|
@ -31,13 +31,9 @@ pub fn evaluate(source: &str) -> Result<Value> {
|
||||
/// # use dust_lang::*;
|
||||
/// let mut context = Map::new();
|
||||
///
|
||||
/// {
|
||||
/// let mut variables = context.variables_mut().unwrap();
|
||||
///
|
||||
/// variables.insert("one".into(), (1.into(), Type::Integer));
|
||||
/// variables.insert("two".into(), (2.into(), Type::Integer));
|
||||
/// variables.insert("three".into(), (3.into(), Type::Integer));
|
||||
/// }
|
||||
/// context.set("one".into(), 1.into(), None);
|
||||
/// context.set("two".into(), 2.into(), None);
|
||||
/// context.set("three".into(), 3.into(), None);
|
||||
///
|
||||
/// let dust_code = "four = 4 one + two + three + four";
|
||||
///
|
||||
|
14
src/main.rs
14
src/main.rs
@ -12,7 +12,7 @@ use tree_sitter::Parser as TSParser;
|
||||
|
||||
use std::{borrow::Cow, fs::read_to_string};
|
||||
|
||||
use dust_lang::{evaluate_with_context, language, Interpreter, Map, Type, Value};
|
||||
use dust_lang::{evaluate_with_context, language, Interpreter, Map, Value};
|
||||
|
||||
/// Command-line arguments to be parsed.
|
||||
#[derive(Parser, Debug)]
|
||||
@ -61,18 +61,16 @@ fn main() {
|
||||
|
||||
if let Some(input) = args.input {
|
||||
context
|
||||
.variables_mut()
|
||||
.unwrap()
|
||||
.insert("input".to_string(), (Value::String(input), Type::String));
|
||||
.set("input".to_string(), Value::String(input), None)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
if let Some(path) = args.input_path {
|
||||
let file_contents = read_to_string(path).unwrap();
|
||||
|
||||
context.variables_mut().unwrap().insert(
|
||||
"input".to_string(),
|
||||
(Value::String(file_contents), Type::String),
|
||||
);
|
||||
context
|
||||
.set("input".to_string(), Value::String(file_contents), None)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
let mut parser = TSParser::new();
|
||||
|
@ -82,9 +82,7 @@ impl Function {
|
||||
|
||||
let key = identifier.inner().clone();
|
||||
|
||||
function_context
|
||||
.variables_mut()?
|
||||
.insert(key, (value, value_type));
|
||||
function_context.set(key, value, Some(value_type))?;
|
||||
}
|
||||
|
||||
let return_value = self.body.run(source, &function_context)?;
|
||||
|
@ -3,7 +3,7 @@ use std::{
|
||||
cmp::Ordering,
|
||||
collections::BTreeMap,
|
||||
fmt::{self, Display, Formatter},
|
||||
sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard},
|
||||
sync::{Arc, RwLock, RwLockReadGuard},
|
||||
};
|
||||
|
||||
use crate::{value::Value, Result, Type};
|
||||
@ -59,10 +59,6 @@ impl Map {
|
||||
|
||||
Ok(previous)
|
||||
}
|
||||
|
||||
pub fn variables_mut(&self) -> Result<RwLockWriteGuard<BTreeMap<String, (Value, Type)>>> {
|
||||
Ok(self.variables.write()?)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Map {
|
||||
|
@ -781,11 +781,8 @@ impl<'de> Visitor<'de> for ValueVisitor {
|
||||
let map = Map::new();
|
||||
|
||||
{
|
||||
let mut variables = map.variables_mut().unwrap();
|
||||
|
||||
while let Some((key, value)) = access.next_entry::<String, Value>()? {
|
||||
let r#type = value.r#type();
|
||||
variables.insert(key, (value, r#type));
|
||||
map.set(key, value, None).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user