Expand type checking to map contexts

This commit is contained in:
Jeff 2023-12-09 17:15:41 -05:00
parent 0fb787bb72
commit 833a830b30
11 changed files with 75 additions and 61 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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)?;

View File

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

View File

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