Expand type checking to map contexts
This commit is contained in:
parent
0fb787bb72
commit
833a830b30
@ -74,20 +74,10 @@ impl AbstractTree for Assignment {
|
|||||||
let identifier_type = identifier.expected_type(context)?;
|
let identifier_type = identifier.expected_type(context)?;
|
||||||
|
|
||||||
if let Type::List(item_type) = type_definition.inner() {
|
if let Type::List(item_type) = type_definition.inner() {
|
||||||
let item_type_definition = TypeDefinition::new(*item_type.clone());
|
println!("{item_type}");
|
||||||
|
|
||||||
item_type_definition.inner().check(
|
item_type.check(&identifier_type, context, identifier_node, source)?;
|
||||||
&identifier_type,
|
item_type.check(&statement_type, context, statement_node, source)?;
|
||||||
context,
|
|
||||||
identifier_node,
|
|
||||||
source,
|
|
||||||
)?;
|
|
||||||
item_type_definition.inner().check(
|
|
||||||
&statement_type,
|
|
||||||
context,
|
|
||||||
statement_node,
|
|
||||||
source,
|
|
||||||
)?;
|
|
||||||
} else {
|
} else {
|
||||||
type_definition.inner().check(
|
type_definition.inner().check(
|
||||||
&identifier_type,
|
&identifier_type,
|
||||||
@ -121,7 +111,7 @@ impl AbstractTree for Assignment {
|
|||||||
|
|
||||||
let new_value = match self.operator {
|
let new_value = match self.operator {
|
||||||
AssignmentOperator::PlusEqual => {
|
AssignmentOperator::PlusEqual => {
|
||||||
if let Some(mut previous_value) = context.variables()?.get(key).cloned() {
|
if let Some((mut previous_value, _)) = context.variables()?.get(key).cloned() {
|
||||||
previous_value += value;
|
previous_value += value;
|
||||||
previous_value
|
previous_value
|
||||||
} else {
|
} else {
|
||||||
@ -129,7 +119,7 @@ impl AbstractTree for Assignment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
AssignmentOperator::MinusEqual => {
|
AssignmentOperator::MinusEqual => {
|
||||||
if let Some(mut previous_value) = context.variables()?.get(key).cloned() {
|
if let Some((mut previous_value, _)) = context.variables()?.get(key).cloned() {
|
||||||
previous_value -= value;
|
previous_value -= value;
|
||||||
previous_value
|
previous_value
|
||||||
} else {
|
} else {
|
||||||
@ -138,8 +128,11 @@ impl AbstractTree for Assignment {
|
|||||||
}
|
}
|
||||||
AssignmentOperator::Equal => value,
|
AssignmentOperator::Equal => value,
|
||||||
};
|
};
|
||||||
|
let new_value_type = new_value.r#type(context)?;
|
||||||
|
|
||||||
context.variables_mut()?.insert(key.clone(), new_value);
|
context
|
||||||
|
.variables_mut()?
|
||||||
|
.insert(key.clone(), (new_value, new_value_type));
|
||||||
|
|
||||||
Ok(Value::Empty)
|
Ok(Value::Empty)
|
||||||
}
|
}
|
||||||
@ -151,7 +144,7 @@ impl AbstractTree for Assignment {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{evaluate, List, Value};
|
use crate::{evaluate, Error, List, Value};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn simple_assignment() {
|
fn simple_assignment() {
|
||||||
@ -180,4 +173,19 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!(Value::List(List::with_items(vec![Value::Integer(1)])), test);
|
assert_eq!(Value::List(List::with_items(vec![Value::Integer(1)])), test);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn list_add_wrong_type() {
|
||||||
|
let test = evaluate(
|
||||||
|
"
|
||||||
|
x <[str]> = []
|
||||||
|
x += 1
|
||||||
|
",
|
||||||
|
);
|
||||||
|
|
||||||
|
if let Err(Error::TypeCheck { .. }) = test {
|
||||||
|
} else {
|
||||||
|
panic!()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,7 @@ impl AbstractTree for For {
|
|||||||
|
|
||||||
iter_context
|
iter_context
|
||||||
.variables_mut()?
|
.variables_mut()?
|
||||||
.insert(key.clone(), value.clone());
|
.insert(key.clone(), (value.clone(), value.r#type(context)?));
|
||||||
|
|
||||||
self.block.run(source, &mut iter_context).map(|_value| ())
|
self.block.run(source, &mut iter_context).map(|_value| ())
|
||||||
})?;
|
})?;
|
||||||
@ -69,7 +69,7 @@ impl AbstractTree for For {
|
|||||||
for value in values.iter() {
|
for value in values.iter() {
|
||||||
loop_context
|
loop_context
|
||||||
.variables_mut()?
|
.variables_mut()?
|
||||||
.insert(key.clone(), value.clone());
|
.insert(key.clone(), (value.clone(), value.r#type(context)?));
|
||||||
|
|
||||||
self.block.run(source, &mut loop_context.clone())?;
|
self.block.run(source, &mut loop_context.clone())?;
|
||||||
}
|
}
|
||||||
|
@ -89,7 +89,7 @@ impl AbstractTree for FunctionCall {
|
|||||||
|
|
||||||
let variables = context.variables()?;
|
let variables = context.variables()?;
|
||||||
|
|
||||||
if let Some(value) = variables.get(key) {
|
if let Some((value, _)) = variables.get(key) {
|
||||||
value.clone()
|
value.clone()
|
||||||
} else {
|
} else {
|
||||||
return Err(Error::FunctionIdentifierNotFound(identifier.clone()));
|
return Err(Error::FunctionIdentifierNotFound(identifier.clone()));
|
||||||
|
@ -34,7 +34,7 @@ impl AbstractTree for Identifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, _source: &str, context: &Map) -> Result<Value> {
|
fn run(&self, _source: &str, context: &Map) -> Result<Value> {
|
||||||
if let Some(value) = context.variables()?.get(&self.0) {
|
if let Some((value, _)) = context.variables()?.get(&self.0) {
|
||||||
Ok(value.clone())
|
Ok(value.clone())
|
||||||
} else {
|
} else {
|
||||||
Err(Error::VariableIdentifierNotFound(self.inner().clone()))
|
Err(Error::VariableIdentifierNotFound(self.inner().clone()))
|
||||||
@ -42,7 +42,7 @@ impl AbstractTree for Identifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, context: &Map) -> Result<Type> {
|
fn expected_type(&self, context: &Map) -> Result<Type> {
|
||||||
if let Some(value) = context.variables()?.get(&self.0) {
|
if let Some((value, _)) = context.variables()?.get(&self.0) {
|
||||||
value.r#type(context)
|
value.r#type(context)
|
||||||
} else {
|
} else {
|
||||||
for built_in_function in BUILT_IN_FUNCTIONS {
|
for built_in_function in BUILT_IN_FUNCTIONS {
|
||||||
|
@ -61,12 +61,18 @@ impl AbstractTree for Index {
|
|||||||
let value = if let Expression::Identifier(identifier) = &self.index {
|
let value = if let Expression::Identifier(identifier) = &self.index {
|
||||||
let key = identifier.inner();
|
let key = identifier.inner();
|
||||||
|
|
||||||
map.variables()?.get(key).cloned().unwrap_or(Value::Empty)
|
map.variables()?
|
||||||
|
.get(key)
|
||||||
|
.map(|(value, _)| value.clone())
|
||||||
|
.unwrap_or_default()
|
||||||
} else {
|
} else {
|
||||||
let value = self.index.run(source, context)?;
|
let value = self.index.run(source, context)?;
|
||||||
let key = value.as_string()?;
|
let key = value.as_string()?;
|
||||||
|
|
||||||
map.variables()?.get(key).cloned().unwrap_or(Value::Empty)
|
map.variables()?
|
||||||
|
.get(key)
|
||||||
|
.map(|(value, _)| value.clone())
|
||||||
|
.unwrap_or_default()
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(value)
|
Ok(value)
|
||||||
|
@ -64,7 +64,8 @@ impl AbstractTree for IndexAssignment {
|
|||||||
|
|
||||||
let new_value = match self.operator {
|
let new_value = match self.operator {
|
||||||
AssignmentOperator::PlusEqual => {
|
AssignmentOperator::PlusEqual => {
|
||||||
if let Some(mut previous_value) = index_context.variables()?.get(index_key).cloned()
|
if let Some((mut previous_value, _)) =
|
||||||
|
index_context.variables()?.get(index_key).cloned()
|
||||||
{
|
{
|
||||||
previous_value += value;
|
previous_value += value;
|
||||||
previous_value
|
previous_value
|
||||||
@ -73,7 +74,8 @@ impl AbstractTree for IndexAssignment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
AssignmentOperator::MinusEqual => {
|
AssignmentOperator::MinusEqual => {
|
||||||
if let Some(mut previous_value) = index_context.variables()?.get(index_key).cloned()
|
if let Some((mut previous_value, _)) =
|
||||||
|
index_context.variables()?.get(index_key).cloned()
|
||||||
{
|
{
|
||||||
previous_value -= value;
|
previous_value -= value;
|
||||||
previous_value
|
previous_value
|
||||||
@ -83,10 +85,11 @@ impl AbstractTree for IndexAssignment {
|
|||||||
}
|
}
|
||||||
AssignmentOperator::Equal => value,
|
AssignmentOperator::Equal => value,
|
||||||
};
|
};
|
||||||
|
let new_value_type = new_value.r#type(context)?;
|
||||||
|
|
||||||
index_context
|
index_context
|
||||||
.variables_mut()?
|
.variables_mut()?
|
||||||
.insert(index_key.clone(), new_value);
|
.insert(index_key.clone(), (new_value, new_value_type));
|
||||||
|
|
||||||
Ok(Value::Empty)
|
Ok(Value::Empty)
|
||||||
}
|
}
|
||||||
|
@ -132,8 +132,9 @@ impl AbstractTree for ValueNode {
|
|||||||
|
|
||||||
for (key, statement) in key_statement_pairs {
|
for (key, statement) in key_statement_pairs {
|
||||||
let value = statement.run(source, context)?;
|
let value = statement.run(source, context)?;
|
||||||
|
let value_type = value.r#type(context)?;
|
||||||
|
|
||||||
variables.insert(key.clone(), value);
|
variables.insert(key.clone(), (value, value_type));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -237,8 +238,11 @@ mod tests {
|
|||||||
{
|
{
|
||||||
let mut variables = map.variables_mut().unwrap();
|
let mut variables = map.variables_mut().unwrap();
|
||||||
|
|
||||||
variables.insert("x".to_string(), Value::Integer(1));
|
variables.insert("x".to_string(), (Value::Integer(1), Type::Integer));
|
||||||
variables.insert("foo".to_string(), Value::String("bar".to_string()));
|
variables.insert(
|
||||||
|
"foo".to_string(),
|
||||||
|
(Value::String("bar".to_string()), Type::String),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_eq!(evaluate("{ x = 1, foo = 'bar' }"), Ok(Value::Map(map)));
|
assert_eq!(evaluate("{ x = 1, foo = 'bar' }"), Ok(Value::Map(map)));
|
||||||
|
@ -31,9 +31,16 @@ impl BuiltInFunction for Read {
|
|||||||
let created = metadata.created()?.elapsed()?.as_secs() as i64;
|
let created = metadata.created()?.elapsed()?.as_secs() as i64;
|
||||||
let modified = metadata.modified()?.elapsed()?.as_secs() as i64;
|
let modified = metadata.modified()?.elapsed()?.as_secs() as i64;
|
||||||
|
|
||||||
file_data_variables.insert("name".to_string(), Value::String(name));
|
file_data_variables
|
||||||
file_data_variables.insert("created".to_string(), Value::Integer(created));
|
.insert("name".to_string(), (Value::String(name), Type::String));
|
||||||
file_data_variables.insert("modified".to_string(), Value::Integer(modified));
|
file_data_variables.insert(
|
||||||
|
"created".to_string(),
|
||||||
|
(Value::Integer(created), Type::Integer),
|
||||||
|
);
|
||||||
|
file_data_variables.insert(
|
||||||
|
"modified".to_string(),
|
||||||
|
(Value::Integer(modified), Type::Integer),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
files.items_mut().push(Value::Map(file_data));
|
files.items_mut().push(Value::Map(file_data));
|
||||||
|
@ -76,6 +76,7 @@ impl Function {
|
|||||||
|
|
||||||
for ((identifier, argument_type), expression) in parameter_argument_pairs {
|
for ((identifier, argument_type), expression) in parameter_argument_pairs {
|
||||||
let value = expression.run(source, context)?;
|
let value = expression.run(source, context)?;
|
||||||
|
let value_type = value.r#type(context)?;
|
||||||
|
|
||||||
match argument_type {
|
match argument_type {
|
||||||
Type::Any => {}
|
Type::Any => {}
|
||||||
@ -110,7 +111,9 @@ impl Function {
|
|||||||
|
|
||||||
let key = identifier.inner().clone();
|
let key = identifier.inner().clone();
|
||||||
|
|
||||||
function_context.variables_mut()?.insert(key, value);
|
function_context
|
||||||
|
.variables_mut()?
|
||||||
|
.insert(key, (value, value_type));
|
||||||
}
|
}
|
||||||
|
|
||||||
let return_value = self.body.run(source, &function_context)?;
|
let return_value = self.body.run(source, &function_context)?;
|
||||||
|
@ -6,7 +6,7 @@ use std::{
|
|||||||
sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard},
|
sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{value::Value, List, Result, Table};
|
use crate::{value::Value, Result, Type};
|
||||||
|
|
||||||
/// A collection dust variables comprised of key-value pairs.
|
/// A collection dust variables comprised of key-value pairs.
|
||||||
///
|
///
|
||||||
@ -14,7 +14,7 @@ use crate::{value::Value, List, Result, Table};
|
|||||||
/// to one another.
|
/// to one another.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Map {
|
pub struct Map {
|
||||||
variables: Arc<RwLock<BTreeMap<String, Value>>>,
|
variables: Arc<RwLock<BTreeMap<String, (Value, Type)>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Map {
|
impl Map {
|
||||||
@ -28,8 +28,8 @@ impl Map {
|
|||||||
pub fn clone_from(other: &Self) -> Result<Self> {
|
pub fn clone_from(other: &Self) -> Result<Self> {
|
||||||
let mut new_map = BTreeMap::new();
|
let mut new_map = BTreeMap::new();
|
||||||
|
|
||||||
for (key, value) in other.variables()?.iter() {
|
for (key, (value, r#type)) in other.variables()?.iter() {
|
||||||
new_map.insert(key.clone(), value.clone());
|
new_map.insert(key.clone(), (value.clone(), r#type.clone()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Map {
|
Ok(Map {
|
||||||
@ -37,11 +37,11 @@ impl Map {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn variables(&self) -> Result<RwLockReadGuard<BTreeMap<String, Value>>> {
|
pub fn variables(&self) -> Result<RwLockReadGuard<BTreeMap<String, (Value, Type)>>> {
|
||||||
Ok(self.variables.read()?)
|
Ok(self.variables.read()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn variables_mut(&self) -> Result<RwLockWriteGuard<BTreeMap<String, Value>>> {
|
pub fn variables_mut(&self) -> Result<RwLockWriteGuard<BTreeMap<String, (Value, Type)>>> {
|
||||||
Ok(self.variables.write()?)
|
Ok(self.variables.write()?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -87,30 +87,13 @@ impl Display for Map {
|
|||||||
|
|
||||||
let variables = self.variables.read().unwrap().clone().into_iter();
|
let variables = self.variables.read().unwrap().clone().into_iter();
|
||||||
|
|
||||||
for (key, value) in variables {
|
for (key, (value, _)) in variables {
|
||||||
writeln!(f, " {key} = {value}")?;
|
writeln!(f, " {key} = {value}")?;
|
||||||
}
|
}
|
||||||
write!(f, "}}")
|
write!(f, "}}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&Table> for Result<Map> {
|
|
||||||
fn from(value: &Table) -> Result<Map> {
|
|
||||||
let map = Map::new();
|
|
||||||
|
|
||||||
for (row_index, row) in value.rows().iter().enumerate() {
|
|
||||||
map.variables_mut()?
|
|
||||||
.insert(
|
|
||||||
row_index.to_string(),
|
|
||||||
Value::List(List::with_items(row.clone())),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(map)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Serialize for Map {
|
impl Serialize for Map {
|
||||||
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
|
@ -282,7 +282,7 @@ impl From<Map> for Result<Table> {
|
|||||||
fn from(map: Map) -> Self {
|
fn from(map: Map) -> Self {
|
||||||
let variables = map.variables()?;
|
let variables = map.variables()?;
|
||||||
let keys = variables.keys().cloned().collect();
|
let keys = variables.keys().cloned().collect();
|
||||||
let values = variables.values().cloned().collect();
|
let values = variables.values().map(|(value, _)| value.clone()).collect();
|
||||||
let mut table = Table::new(keys);
|
let mut table = Table::new(keys);
|
||||||
|
|
||||||
table.insert(values)?;
|
table.insert(values)?;
|
||||||
@ -295,7 +295,7 @@ impl From<&Map> for Result<Table> {
|
|||||||
fn from(map: &Map) -> Self {
|
fn from(map: &Map) -> Self {
|
||||||
let variables = map.variables()?;
|
let variables = map.variables()?;
|
||||||
let keys = variables.keys().cloned().collect();
|
let keys = variables.keys().cloned().collect();
|
||||||
let values = variables.values().cloned().collect();
|
let values = variables.values().map(|(value, _)| value.clone()).collect();
|
||||||
let mut table = Table::new(keys);
|
let mut table = Table::new(keys);
|
||||||
|
|
||||||
table.insert(values)?;
|
table.insert(values)?;
|
||||||
@ -308,7 +308,7 @@ impl From<&mut Map> for Result<Table> {
|
|||||||
fn from(map: &mut Map) -> Self {
|
fn from(map: &mut Map) -> Self {
|
||||||
let variables = map.variables()?;
|
let variables = map.variables()?;
|
||||||
let keys = variables.keys().cloned().collect();
|
let keys = variables.keys().cloned().collect();
|
||||||
let values = variables.values().cloned().collect();
|
let values = variables.values().map(|(value, _)| value.clone()).collect();
|
||||||
let mut table = Table::new(keys);
|
let mut table = Table::new(keys);
|
||||||
|
|
||||||
table
|
table
|
||||||
|
Loading…
Reference in New Issue
Block a user