1
0
dust/dust-lang/src/type.rs

384 lines
12 KiB
Rust
Raw Normal View History

2024-08-09 02:44:34 +00:00
//! Description of a kind of value.
//!
//! Most types are concrete and specific, the exceptions are the Generic and Any types.
//!
//! Generic types are temporary placeholders that describe a type that will be defined later. The
//! interpreter should use the analysis phase to enforce that all Generic types have a concrete
//! type assigned to them before the program is run.
//!
//! The Any type is used in cases where a value's type does not matter. For example, the standard
//! library's "length" function does not care about the type of item in the list, only the list
//! itself. So the input is defined as `[any]`, i.e. `Type::ListOf(Box::new(Type::Any))`.
2024-06-24 08:02:44 +00:00
use std::{
collections::BTreeMap,
fmt::{self, Display, Formatter},
};
2024-03-07 03:15:35 +00:00
2024-06-04 18:47:15 +00:00
use serde::{Deserialize, Serialize};
2024-03-20 12:36:18 +00:00
2024-08-07 15:38:08 +00:00
use crate::Identifier;
2024-08-04 00:23:52 +00:00
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct TypeConflict {
pub expected: Type,
pub actual: Type,
}
2024-06-04 18:47:15 +00:00
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
2024-07-15 19:49:34 +00:00
/// Description of a kind of value.
///
/// See the [module documentation](index.html) for more information.
pub enum Type {
2024-03-06 17:15:03 +00:00
Any,
Boolean,
Enum {
name: Identifier,
type_parameters: Option<Vec<Type>>,
variants: Vec<(Identifier, Option<Vec<Type>>)>,
},
Float,
2024-03-09 02:26:49 +00:00
Function {
type_parameters: Option<Vec<Type>>,
2024-06-24 02:39:33 +00:00
value_parameters: Option<Vec<(Identifier, Type)>>,
2024-06-22 04:58:30 +00:00
return_type: Option<Box<Type>>,
2024-03-09 02:26:49 +00:00
},
2024-06-19 04:05:58 +00:00
Generic {
identifier: Identifier,
concrete_type: Option<Box<Type>>,
},
Integer,
2024-06-17 14:10:06 +00:00
List {
length: usize,
item_type: Box<Type>,
},
2024-06-24 08:02:44 +00:00
Map(BTreeMap<Identifier, Type>),
Range,
String,
2024-03-19 21:18:36 +00:00
Structure {
name: Identifier,
2024-06-17 14:10:06 +00:00
fields: Vec<(Identifier, Type)>,
2024-03-19 21:18:36 +00:00
},
}
2024-03-06 17:15:03 +00:00
impl Type {
/// Returns a concrete type, either the type itself or the concrete type of a generic type.
pub fn concrete_type(&self) -> &Type {
match self {
Type::Generic {
concrete_type: Some(concrete_type),
..
} => concrete_type.concrete_type(),
_ => self,
}
}
/// Checks that the type is compatible with another type.
2024-03-17 04:49:01 +00:00
pub fn check(&self, other: &Type) -> Result<(), TypeConflict> {
match (self.concrete_type(), other.concrete_type()) {
2024-03-06 17:15:03 +00:00
(Type::Any, _)
| (_, Type::Any)
| (Type::Boolean, Type::Boolean)
| (Type::Float, Type::Float)
| (Type::Integer, Type::Integer)
| (Type::Range, Type::Range)
2024-03-20 05:29:07 +00:00
| (Type::String, Type::String) => return Ok(()),
2024-06-19 04:05:58 +00:00
(
Type::Generic {
concrete_type: left,
..
},
Type::Generic {
concrete_type: right,
..
},
) => match (left, right) {
2024-06-17 21:38:24 +00:00
(Some(left), Some(right)) => {
2024-07-12 14:20:52 +00:00
if left.check(right).is_ok() {
2024-06-17 21:38:24 +00:00
return Ok(());
}
}
(None, None) => {
return Ok(());
}
_ => {}
},
2024-06-19 04:05:58 +00:00
(Type::Generic { concrete_type, .. }, other)
| (other, Type::Generic { concrete_type, .. }) => {
if let Some(concrete_type) = concrete_type {
if other == concrete_type.as_ref() {
return Ok(());
}
}
}
(
2024-03-20 12:36:18 +00:00
Type::Structure {
name: left_name,
fields: left_fields,
},
2024-03-20 12:36:18 +00:00
Type::Structure {
name: right_name,
fields: right_fields,
},
) => {
2024-03-20 12:36:18 +00:00
if left_name == right_name {
for ((left_field_name, left_type), (right_field_name, right_type)) in
left_fields.iter().zip(right_fields.iter())
{
2024-06-17 14:10:06 +00:00
if left_field_name != right_field_name || left_type != right_type {
2024-03-20 12:36:18 +00:00
return Err(TypeConflict {
actual: other.clone(),
expected: self.clone(),
});
}
}
2024-03-20 05:29:07 +00:00
return Ok(());
}
}
2024-06-17 15:02:13 +00:00
(
Type::List {
length: left_length,
item_type: left_type,
},
Type::List {
length: right_length,
item_type: right_type,
},
) => {
if left_length != right_length || left_type != right_type {
return Err(TypeConflict {
actual: other.clone(),
expected: self.clone(),
});
}
return Ok(());
}
2024-03-20 05:29:07 +00:00
(
2024-03-20 12:36:18 +00:00
Type::Function {
2024-06-17 14:10:06 +00:00
type_parameters: left_type_parameters,
value_parameters: left_value_parameters,
2024-03-20 12:36:18 +00:00
return_type: left_return,
2024-03-20 05:29:07 +00:00
},
2024-03-20 12:36:18 +00:00
Type::Function {
2024-06-17 14:10:06 +00:00
type_parameters: right_type_parameters,
value_parameters: right_value_parameters,
2024-03-20 12:36:18 +00:00
return_type: right_return,
2024-03-20 05:29:07 +00:00
},
) => {
2024-06-17 14:10:06 +00:00
if left_return == right_return {
for (left_parameter, right_parameter) in left_type_parameters
.iter()
.zip(right_type_parameters.iter())
2024-03-24 19:47:23 +00:00
{
2024-06-17 14:10:06 +00:00
if left_parameter != right_parameter {
return Err(TypeConflict {
actual: other.clone(),
expected: self.clone(),
});
}
}
2024-06-17 15:02:13 +00:00
2024-06-17 14:10:06 +00:00
for (left_parameter, right_parameter) in left_value_parameters
.iter()
.zip(right_value_parameters.iter())
{
if left_parameter != right_parameter {
2024-03-24 19:47:23 +00:00
return Err(TypeConflict {
actual: other.clone(),
expected: self.clone(),
});
}
}
2024-03-20 05:29:07 +00:00
return Ok(());
}
}
2024-06-24 08:02:44 +00:00
(Type::Map(left), Type::Map(right)) => {
if left == right {
return Ok(());
}
}
2024-03-20 05:29:07 +00:00
_ => {}
2024-03-06 17:15:03 +00:00
}
2024-03-20 05:29:07 +00:00
Err(TypeConflict {
actual: other.clone(),
expected: self.clone(),
})
2024-03-06 17:15:03 +00:00
}
}
2024-03-07 03:15:35 +00:00
impl Display for Type {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
Type::Any => write!(f, "any"),
2024-03-23 21:07:41 +00:00
Type::Boolean => write!(f, "bool"),
Type::Enum { variants, .. } => {
write!(f, "enum ")?;
write!(f, " {{")?;
for (identifier, types) in variants {
writeln!(f, "{identifier}")?;
if let Some(types) = types {
write!(f, "(")?;
for r#type in types {
write!(f, "{}", r#type)?;
}
}
write!(f, ")")?;
}
write!(f, "}}")
}
2024-03-07 03:15:35 +00:00
Type::Float => write!(f, "float"),
2024-06-19 04:05:58 +00:00
Type::Generic { concrete_type, .. } => {
2024-06-26 15:35:39 +00:00
match concrete_type.clone().map(|r#box| *r#box) {
Some(Type::Generic { identifier, .. }) => write!(f, "{identifier}"),
Some(concrete_type) => write!(f, "implied to be {concrete_type}"),
None => write!(f, "unknown"),
2024-06-17 21:38:24 +00:00
}
}
2024-03-23 21:07:41 +00:00
Type::Integer => write!(f, "int"),
2024-06-17 14:10:06 +00:00
Type::List { length, item_type } => write!(f, "[{length}; {}]", item_type),
2024-06-24 08:16:05 +00:00
Type::Map(map) => {
write!(f, "{{ ")?;
2024-06-24 08:02:44 +00:00
2024-07-12 14:20:52 +00:00
for (index, (key, r#type)) in map.iter().enumerate() {
2024-06-24 08:16:05 +00:00
write!(f, "{key}: {type}")?;
if index != map.len() - 1 {
write!(f, ", ")?;
}
2024-06-24 08:02:44 +00:00
}
2024-06-24 08:16:05 +00:00
write!(f, " }}")
2024-06-24 08:02:44 +00:00
}
2024-03-07 03:15:35 +00:00
Type::Range => write!(f, "range"),
2024-03-23 21:07:41 +00:00
Type::String => write!(f, "str"),
2024-03-09 02:26:49 +00:00
Type::Function {
2024-06-17 14:10:06 +00:00
type_parameters,
value_parameters,
2024-03-09 02:26:49 +00:00
return_type,
} => {
2024-06-26 18:44:23 +00:00
write!(f, "fn ")?;
2024-03-09 02:26:49 +00:00
2024-06-17 14:10:06 +00:00
if let Some(type_parameters) = type_parameters {
2024-06-26 18:44:23 +00:00
write!(f, "<")?;
2024-06-17 14:10:06 +00:00
for identifier in type_parameters {
2024-06-26 18:44:23 +00:00
write!(f, "{}, ", identifier)?;
2024-06-17 14:10:06 +00:00
}
2024-06-26 18:44:23 +00:00
write!(f, ">")?;
2024-06-17 14:10:06 +00:00
}
2024-06-26 18:44:23 +00:00
write!(f, "(")?;
2024-06-24 02:39:33 +00:00
if let Some(value_parameters) = value_parameters {
for (identifier, r#type) in value_parameters {
write!(f, "{identifier}: {type}")?;
}
2024-03-09 02:26:49 +00:00
}
2024-06-22 04:58:30 +00:00
write!(f, ")")?;
if let Some(r#type) = return_type {
2024-06-24 02:39:33 +00:00
write!(f, " -> {type}")
2024-06-22 04:58:30 +00:00
} else {
Ok(())
}
2024-03-09 02:26:49 +00:00
}
2024-03-20 12:36:18 +00:00
Type::Structure { name, .. } => write!(f, "{name}"),
2024-03-07 03:15:35 +00:00
}
}
}
2024-03-06 17:15:03 +00:00
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn check_same_types() {
assert_eq!(Type::Any.check(&Type::Any), Ok(()));
assert_eq!(Type::Boolean.check(&Type::Boolean), Ok(()));
assert_eq!(Type::Float.check(&Type::Float), Ok(()));
assert_eq!(Type::Integer.check(&Type::Integer), Ok(()));
assert_eq!(
2024-06-17 14:10:06 +00:00
Type::List {
length: 4,
item_type: Box::new(Type::Boolean),
}
.check(&Type::List {
length: 4,
item_type: Box::new(Type::Boolean),
}),
2024-03-06 17:15:03 +00:00
Ok(())
);
2024-06-17 14:10:06 +00:00
2024-06-24 08:02:44 +00:00
let mut map = BTreeMap::new();
2024-07-04 18:39:45 +00:00
map.insert(Identifier::from("x"), Type::Integer);
map.insert(Identifier::from("y"), Type::String);
map.insert(Identifier::from("z"), Type::Map(map.clone()));
2024-06-24 08:02:44 +00:00
assert_eq!(Type::Map(map.clone()).check(&Type::Map(map)), Ok(()));
2024-03-06 17:15:03 +00:00
assert_eq!(Type::Range.check(&Type::Range), Ok(()));
assert_eq!(Type::String.check(&Type::String), Ok(()));
}
2024-03-06 17:15:03 +00:00
#[test]
fn errors() {
2024-03-19 21:18:36 +00:00
let foo = Type::Integer;
let bar = Type::String;
2024-03-06 17:15:03 +00:00
assert_eq!(
foo.check(&bar),
2024-03-17 04:49:01 +00:00
Err(TypeConflict {
2024-03-06 17:15:03 +00:00
actual: bar.clone(),
expected: foo.clone()
})
);
assert_eq!(
bar.check(&foo),
2024-03-17 04:49:01 +00:00
Err(TypeConflict {
2024-03-06 17:15:03 +00:00
actual: foo.clone(),
expected: bar.clone()
})
);
let types = [
Type::Boolean,
Type::Float,
Type::Integer,
2024-06-17 14:10:06 +00:00
Type::List {
length: 10,
item_type: Box::new(Type::Integer),
},
2024-06-24 08:02:44 +00:00
Type::Map(BTreeMap::new()),
2024-03-06 17:15:03 +00:00
Type::Range,
Type::String,
];
2024-06-22 04:58:30 +00:00
for left in types.clone() {
for right in types.clone() {
if left == right {
continue;
}
2024-03-06 17:15:03 +00:00
2024-06-22 04:58:30 +00:00
assert_eq!(
left.check(&right),
Err(TypeConflict {
actual: right.clone(),
expected: left.clone()
})
);
}
2024-03-06 17:15:03 +00:00
}
}
}