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)?;
|
||||
|
||||
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(
|
||||
&identifier_type,
|
||||
context,
|
||||
identifier_node,
|
||||
source,
|
||||
)?;
|
||||
item_type_definition.inner().check(
|
||||
&statement_type,
|
||||
context,
|
||||
statement_node,
|
||||
source,
|
||||
)?;
|
||||
item_type.check(&identifier_type, context, identifier_node, source)?;
|
||||
item_type.check(&statement_type, context, statement_node, source)?;
|
||||
} else {
|
||||
type_definition.inner().check(
|
||||
&identifier_type,
|
||||
@ -121,7 +111,7 @@ impl AbstractTree for Assignment {
|
||||
|
||||
let new_value = match self.operator {
|
||||
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
|
||||
} else {
|
||||
@ -129,7 +119,7 @@ impl AbstractTree for Assignment {
|
||||
}
|
||||
}
|
||||
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
|
||||
} else {
|
||||
@ -138,8 +128,11 @@ impl AbstractTree for Assignment {
|
||||
}
|
||||
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)
|
||||
}
|
||||
@ -151,7 +144,7 @@ impl AbstractTree for Assignment {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{evaluate, List, Value};
|
||||
use crate::{evaluate, Error, List, Value};
|
||||
|
||||
#[test]
|
||||
fn simple_assignment() {
|
||||
@ -180,4 +173,19 @@ mod tests {
|
||||
|
||||
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
|
||||
.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| ())
|
||||
})?;
|
||||
@ -69,7 +69,7 @@ impl AbstractTree for For {
|
||||
for value in values.iter() {
|
||||
loop_context
|
||||
.variables_mut()?
|
||||
.insert(key.clone(), value.clone());
|
||||
.insert(key.clone(), (value.clone(), value.r#type(context)?));
|
||||
|
||||
self.block.run(source, &mut loop_context.clone())?;
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ impl AbstractTree for FunctionCall {
|
||||
|
||||
let variables = context.variables()?;
|
||||
|
||||
if let Some(value) = variables.get(key) {
|
||||
if let Some((value, _)) = variables.get(key) {
|
||||
value.clone()
|
||||
} else {
|
||||
return Err(Error::FunctionIdentifierNotFound(identifier.clone()));
|
||||
|
@ -34,7 +34,7 @@ impl AbstractTree for Identifier {
|
||||
}
|
||||
|
||||
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())
|
||||
} else {
|
||||
Err(Error::VariableIdentifierNotFound(self.inner().clone()))
|
||||
@ -42,7 +42,7 @@ impl AbstractTree for Identifier {
|
||||
}
|
||||
|
||||
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)
|
||||
} else {
|
||||
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 key = identifier.inner();
|
||||
|
||||
map.variables()?.get(key).cloned().unwrap_or(Value::Empty)
|
||||
map.variables()?
|
||||
.get(key)
|
||||
.map(|(value, _)| value.clone())
|
||||
.unwrap_or_default()
|
||||
} else {
|
||||
let value = self.index.run(source, context)?;
|
||||
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)
|
||||
|
@ -64,7 +64,8 @@ impl AbstractTree for IndexAssignment {
|
||||
|
||||
let new_value = match self.operator {
|
||||
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
|
||||
@ -73,7 +74,8 @@ impl AbstractTree for IndexAssignment {
|
||||
}
|
||||
}
|
||||
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
|
||||
@ -83,10 +85,11 @@ impl AbstractTree for IndexAssignment {
|
||||
}
|
||||
AssignmentOperator::Equal => value,
|
||||
};
|
||||
let new_value_type = new_value.r#type(context)?;
|
||||
|
||||
index_context
|
||||
.variables_mut()?
|
||||
.insert(index_key.clone(), new_value);
|
||||
.insert(index_key.clone(), (new_value, new_value_type));
|
||||
|
||||
Ok(Value::Empty)
|
||||
}
|
||||
|
@ -132,8 +132,9 @@ impl AbstractTree for ValueNode {
|
||||
|
||||
for (key, statement) in key_statement_pairs {
|
||||
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();
|
||||
|
||||
variables.insert("x".to_string(), Value::Integer(1));
|
||||
variables.insert("foo".to_string(), Value::String("bar".to_string()));
|
||||
variables.insert("x".to_string(), (Value::Integer(1), Type::Integer));
|
||||
variables.insert(
|
||||
"foo".to_string(),
|
||||
(Value::String("bar".to_string()), Type::String),
|
||||
);
|
||||
}
|
||||
|
||||
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 modified = metadata.modified()?.elapsed()?.as_secs() as i64;
|
||||
|
||||
file_data_variables.insert("name".to_string(), Value::String(name));
|
||||
file_data_variables.insert("created".to_string(), Value::Integer(created));
|
||||
file_data_variables.insert("modified".to_string(), Value::Integer(modified));
|
||||
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),
|
||||
);
|
||||
}
|
||||
|
||||
files.items_mut().push(Value::Map(file_data));
|
||||
|
@ -76,6 +76,7 @@ impl Function {
|
||||
|
||||
for ((identifier, argument_type), expression) in parameter_argument_pairs {
|
||||
let value = expression.run(source, context)?;
|
||||
let value_type = value.r#type(context)?;
|
||||
|
||||
match argument_type {
|
||||
Type::Any => {}
|
||||
@ -110,7 +111,9 @@ impl Function {
|
||||
|
||||
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)?;
|
||||
|
@ -6,7 +6,7 @@ use std::{
|
||||
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.
|
||||
///
|
||||
@ -14,7 +14,7 @@ use crate::{value::Value, List, Result, Table};
|
||||
/// to one another.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Map {
|
||||
variables: Arc<RwLock<BTreeMap<String, Value>>>,
|
||||
variables: Arc<RwLock<BTreeMap<String, (Value, Type)>>>,
|
||||
}
|
||||
|
||||
impl Map {
|
||||
@ -28,8 +28,8 @@ impl Map {
|
||||
pub fn clone_from(other: &Self) -> Result<Self> {
|
||||
let mut new_map = BTreeMap::new();
|
||||
|
||||
for (key, value) in other.variables()?.iter() {
|
||||
new_map.insert(key.clone(), value.clone());
|
||||
for (key, (value, r#type)) in other.variables()?.iter() {
|
||||
new_map.insert(key.clone(), (value.clone(), r#type.clone()));
|
||||
}
|
||||
|
||||
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()?)
|
||||
}
|
||||
|
||||
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()?)
|
||||
}
|
||||
}
|
||||
@ -87,30 +87,13 @@ impl Display for Map {
|
||||
|
||||
let variables = self.variables.read().unwrap().clone().into_iter();
|
||||
|
||||
for (key, value) in variables {
|
||||
for (key, (value, _)) in variables {
|
||||
writeln!(f, " {key} = {value}")?;
|
||||
}
|
||||
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 {
|
||||
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
|
||||
where
|
||||
|
@ -282,7 +282,7 @@ impl From<Map> for Result<Table> {
|
||||
fn from(map: Map) -> Self {
|
||||
let variables = map.variables()?;
|
||||
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);
|
||||
|
||||
table.insert(values)?;
|
||||
@ -295,7 +295,7 @@ impl From<&Map> for Result<Table> {
|
||||
fn from(map: &Map) -> Self {
|
||||
let variables = map.variables()?;
|
||||
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);
|
||||
|
||||
table.insert(values)?;
|
||||
@ -308,7 +308,7 @@ impl From<&mut Map> for Result<Table> {
|
||||
fn from(map: &mut Map) -> Self {
|
||||
let variables = map.variables()?;
|
||||
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);
|
||||
|
||||
table
|
||||
|
Loading…
Reference in New Issue
Block a user