Continue value overhaul

This commit is contained in:
Jeff 2024-08-16 17:07:49 -04:00
parent 8bff39a7db
commit 8ae453add7
5 changed files with 745 additions and 1500 deletions

View File

@ -5,7 +5,7 @@ use std::{
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{Context, Identifier, Span, StructType, Type, Value}; use crate::{Context, FunctionType, Identifier, Span, StructType, Type, Value};
use super::{Node, Statement}; use super::{Node, Statement};
@ -236,7 +236,7 @@ impl Expression {
let invoker_type = invoker.return_type(context)?; let invoker_type = invoker.return_type(context)?;
if let Type::Function { return_type, .. } = invoker_type { if let Type::Function(FunctionType { return_type, .. }) = invoker_type {
return_type.map(|r#type| *r#type) return_type.map(|r#type| *r#type)
} else if let Type::Struct(_) = invoker_type { } else if let Type::Struct(_) = invoker_type {
Some(invoker_type) Some(invoker_type)
@ -276,7 +276,7 @@ impl Expression {
} }
ListExpression::Ordered(expressions) => { ListExpression::Ordered(expressions) => {
if expressions.is_empty() { if expressions.is_empty() {
return Some(Type::EmptyList); return Some(Type::ListEmpty);
} }
let item_type = expressions.last().unwrap().return_type(context)?; let item_type = expressions.last().unwrap().return_type(context)?;
@ -304,7 +304,6 @@ impl Expression {
LiteralExpression::Float(_) => Some(Type::Float), LiteralExpression::Float(_) => Some(Type::Float),
LiteralExpression::Integer(_) => Some(Type::Integer), LiteralExpression::Integer(_) => Some(Type::Integer),
LiteralExpression::String(_) => Some(Type::String), LiteralExpression::String(_) => Some(Type::String),
LiteralExpression::Value(value) => Some(value.r#type()),
}, },
Expression::Loop(loop_expression) => match loop_expression.inner.as_ref() { Expression::Loop(loop_expression) => match loop_expression.inner.as_ref() {
LoopExpression::For { block, .. } => block.inner.return_type(context), LoopExpression::For { block, .. } => block.inner.return_type(context),
@ -326,19 +325,19 @@ impl Expression {
StructExpression::Fields { name, fields } => { StructExpression::Fields { name, fields } => {
let mut field_types = Vec::with_capacity(fields.len()); let mut field_types = Vec::with_capacity(fields.len());
for (name, expression) in fields { for (field_name, expression) in fields {
let r#type = expression.return_type(context)?; let r#type = expression.return_type(context)?;
field_types.push((name.inner.clone(), r#type)); field_types.push((field_name.inner.clone(), r#type));
} }
Some(Type::Struct(StructType::Fields { Some(Type::Struct(StructType::Fields {
name: name.inner.clone(), identifier: name.inner.clone(),
fields: field_types, fields: field_types,
})) }))
} }
StructExpression::Unit { name } => Some(Type::Struct(StructType::Unit { StructExpression::Unit { name } => Some(Type::Struct(StructType::Unit {
name: name.inner.clone(), identifier: name.inner.clone(),
})), })),
}, },
Expression::TupleAccess(tuple_access_expression) => { Expression::TupleAccess(tuple_access_expression) => {
@ -502,7 +501,6 @@ pub enum LiteralExpression {
Float(f64), Float(f64),
Integer(i64), Integer(i64),
String(String), String(String),
Value(Value),
} }
impl Display for LiteralExpression { impl Display for LiteralExpression {
@ -512,7 +510,6 @@ impl Display for LiteralExpression {
LiteralExpression::Float(float) => write!(f, "{}", float), LiteralExpression::Float(float) => write!(f, "{}", float),
LiteralExpression::Integer(integer) => write!(f, "{}", integer), LiteralExpression::Integer(integer) => write!(f, "{}", integer),
LiteralExpression::String(string) => write!(f, "{}", string), LiteralExpression::String(string) => write!(f, "{}", string),
LiteralExpression::Value(value) => write!(f, "{}", value),
} }
} }
} }
@ -538,7 +535,6 @@ impl Ord for LiteralExpression {
left.cmp(right) left.cmp(right)
} }
(LiteralExpression::String(left), LiteralExpression::String(right)) => left.cmp(right), (LiteralExpression::String(left), LiteralExpression::String(right)) => left.cmp(right),
(LiteralExpression::Value(left), LiteralExpression::Value(right)) => left.cmp(right),
_ => unreachable!(), _ => unreachable!(),
} }
} }

View File

@ -36,7 +36,7 @@ pub use dust_error::DustError;
pub use identifier::Identifier; pub use identifier::Identifier;
pub use lexer::{lex, LexError, Lexer}; pub use lexer::{lex, LexError, Lexer};
pub use parser::{parse, ParseError, Parser}; pub use parser::{parse, ParseError, Parser};
pub use r#type::{StructType, Type}; pub use r#type::{EnumType, FunctionType, StructType, Type};
pub use token::{Token, TokenKind, TokenOwned}; pub use token::{Token, TokenKind, TokenOwned};
pub use value::{Struct, Value, ValueError}; pub use value::{Struct, Value, ValueError};
pub use vm::{run, run_with_context, Vm, VmError}; pub use vm::{run, run_with_context, Vm, VmError};

View File

@ -10,19 +10,13 @@
//! library's "length" function does not care about the type of item in the list, only the list //! 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))`. //! itself. So the input is defined as `[any]`, i.e. `Type::ListOf(Box::new(Type::Any))`.
use std::{ use std::{
collections::BTreeMap,
fmt::{self, Display, Formatter}, fmt::{self, Display, Formatter},
sync::Arc,
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::Identifier; use crate::{value::Function, Identifier};
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct TypeConflict {
pub expected: Type,
pub actual: Type,
}
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
/// Description of a kind of value. /// Description of a kind of value.
@ -31,18 +25,11 @@ pub struct TypeConflict {
pub enum Type { pub enum Type {
Any, Any,
Boolean, Boolean,
EmptyList, Byte,
Enum { Character,
name: Identifier, Enum(EnumType),
type_parameters: Option<Vec<Type>>,
variants: Vec<(Identifier, Option<Vec<Type>>)>,
},
Float, Float,
Function { Function(FunctionType),
type_parameters: Option<Vec<Type>>,
value_parameters: Option<Vec<(Identifier, Type)>>,
return_type: Option<Box<Type>>,
},
Generic { Generic {
identifier: Identifier, identifier: Identifier,
concrete_type: Option<Box<Type>>, concrete_type: Option<Box<Type>>,
@ -52,14 +39,15 @@ pub enum Type {
item_type: Box<Type>, item_type: Box<Type>,
length: usize, length: usize,
}, },
ListEmpty,
ListOf { ListOf {
item_type: Box<Type>, item_type: Box<Type>,
}, },
Map(BTreeMap<Identifier, Type>),
Number, Number,
Range, Range,
String, String,
Struct(StructType), Struct(StructType),
Tuple(Vec<Type>),
} }
impl Type { impl Type {
@ -189,17 +177,26 @@ impl Type {
} }
} }
( (
Type::Function { Type::Function(FunctionType {
name: left_name,
type_parameters: left_type_parameters, type_parameters: left_type_parameters,
value_parameters: left_value_parameters, value_parameters: left_value_parameters,
return_type: left_return, return_type: left_return,
}, }),
Type::Function { Type::Function(FunctionType {
name: right_name,
type_parameters: right_type_parameters, type_parameters: right_type_parameters,
value_parameters: right_value_parameters, value_parameters: right_value_parameters,
return_type: right_return, return_type: right_return,
}, }),
) => { ) => {
if left_name != right_name {
return Err(TypeConflict {
actual: other.clone(),
expected: self.clone(),
});
}
if left_return == right_return { if left_return == right_return {
for (left_parameter, right_parameter) in left_type_parameters for (left_parameter, right_parameter) in left_type_parameters
.iter() .iter()
@ -228,11 +225,6 @@ impl Type {
return Ok(()); return Ok(());
} }
} }
(Type::Map(left), Type::Map(right)) => {
if left == right {
return Ok(());
}
}
(Type::Number, Type::Number | Type::Integer | Type::Float) (Type::Number, Type::Number | Type::Integer | Type::Float)
| (Type::Integer | Type::Float, Type::Number) => { | (Type::Integer | Type::Float, Type::Number) => {
return Ok(()); return Ok(());
@ -252,29 +244,11 @@ impl Display for Type {
match self { match self {
Type::Any => write!(f, "any"), Type::Any => write!(f, "any"),
Type::Boolean => write!(f, "bool"), Type::Boolean => write!(f, "bool"),
Type::EmptyList => write!(f, "[]"), Type::Byte => write!(f, "byte"),
Type::Enum { variants, .. } => { Type::Character => write!(f, "char"),
write!(f, "enum ")?; Type::Enum(enum_type) => write!(f, "{enum_type}"),
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, "}}")
}
Type::Float => write!(f, "float"), Type::Float => write!(f, "float"),
Type::Function(function_type) => write!(f, "{function_type}"),
Type::Generic { concrete_type, .. } => { Type::Generic { concrete_type, .. } => {
match concrete_type.clone().map(|r#box| *r#box) { match concrete_type.clone().map(|r#box| *r#box) {
Some(Type::Generic { identifier, .. }) => write!(f, "{identifier}"), Some(Type::Generic { identifier, .. }) => write!(f, "{identifier}"),
@ -284,82 +258,14 @@ impl Display for Type {
} }
Type::Integer => write!(f, "int"), Type::Integer => write!(f, "int"),
Type::List { item_type, length } => write!(f, "[{item_type}; {length}]"), Type::List { item_type, length } => write!(f, "[{item_type}; {length}]"),
Type::ListEmpty => write!(f, "[]"),
Type::ListOf { item_type } => write!(f, "[{item_type}]"), Type::ListOf { item_type } => write!(f, "[{item_type}]"),
Type::Map(map) => {
write!(f, "{{ ")?;
for (index, (key, r#type)) in map.iter().enumerate() {
write!(f, "{key}: {type}")?;
if index != map.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, " }}")
}
Type::Number => write!(f, "num"), Type::Number => write!(f, "num"),
Type::Range => write!(f, "range"), Type::Range => write!(f, "range"),
Type::String => write!(f, "str"), Type::String => write!(f, "str"),
Type::Function {
type_parameters,
value_parameters,
return_type,
} => {
write!(f, "fn ")?;
if let Some(type_parameters) = type_parameters {
write!(f, "<")?;
for identifier in type_parameters {
write!(f, "{}, ", identifier)?;
}
write!(f, ">")?;
}
write!(f, "(")?;
if let Some(value_parameters) = value_parameters {
for (identifier, r#type) in value_parameters {
write!(f, "{identifier}: {type}")?;
}
}
write!(f, ")")?;
if let Some(r#type) = return_type {
write!(f, " -> {type}")
} else {
Ok(())
}
}
Type::Struct(struct_type) => write!(f, "{struct_type}"), Type::Struct(struct_type) => write!(f, "{struct_type}"),
} Type::Tuple(fields) => {
} write!(f, "(")?;
}
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum StructType {
Unit {
name: Identifier,
},
Tuple {
name: Identifier,
fields: Vec<Type>,
},
Fields {
name: Identifier,
fields: Vec<(Identifier, Type)>,
},
}
impl Display for StructType {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
StructType::Unit { name } => write!(f, "struct {name}"),
StructType::Tuple { name, fields } => {
write!(f, "struct {name}(")?;
for (index, r#type) in fields.iter().enumerate() { for (index, r#type) in fields.iter().enumerate() {
write!(f, "{type}")?; write!(f, "{type}")?;
@ -371,8 +277,94 @@ impl Display for StructType {
write!(f, ")") write!(f, ")")
} }
StructType::Fields { name, fields } => { }
write!(f, "struct {name} {{")?; }
}
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct FunctionType {
pub name: Identifier,
pub type_parameters: Option<Vec<Type>>,
pub value_parameters: Option<Vec<(Identifier, Type)>>,
pub return_type: Option<Box<Type>>,
}
impl Display for FunctionType {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "fn ")?;
if let Some(type_parameters) = &self.type_parameters {
write!(f, "<")?;
for (index, type_parameter) in type_parameters.iter().enumerate() {
write!(f, "{type_parameter}")?;
if index != type_parameters.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, ">")?;
}
write!(f, "(")?;
if let Some(value_parameters) = &self.value_parameters {
for (index, (identifier, r#type)) in value_parameters.iter().enumerate() {
write!(f, "{identifier}: {type}")?;
if index != value_parameters.len() - 1 {
write!(f, ", ")?;
}
}
}
write!(f, ")")?;
if let Some(return_type) = &self.return_type {
write!(f, " -> {return_type}")?;
}
Ok(())
}
}
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum StructType {
Unit {
identifier: Identifier,
},
Tuple {
identifier: Identifier,
fields: Vec<Type>,
},
Fields {
identifier: Identifier,
fields: Vec<(Identifier, Type)>,
},
}
impl Display for StructType {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
StructType::Unit { .. } => write!(f, "()"),
StructType::Tuple { fields, .. } => {
write!(f, "(")?;
for (index, r#type) in fields.iter().enumerate() {
write!(f, "{type}")?;
if index != fields.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, ")")
}
StructType::Fields {
identifier, fields, ..
} => {
write!(f, "{identifier} {{ ")?;
for (index, (identifier, r#type)) in fields.iter().enumerate() { for (index, (identifier, r#type)) in fields.iter().enumerate() {
write!(f, "{identifier}: {type}")?; write!(f, "{identifier}: {type}")?;
@ -382,43 +374,64 @@ impl Display for StructType {
} }
} }
write!(f, "}}") write!(f, " }}")
} }
} }
} }
} }
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct EnumType {
name: Identifier,
variants: Vec<StructType>,
}
impl Display for EnumType {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "{}", self.name)
}
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct TypeConflict {
pub expected: Type,
pub actual: Type,
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
#[test] #[test]
fn check_same_types() { fn check_type_any() {
assert_eq!(Type::Any.check(&Type::Any), Ok(())); let foo = Type::Any;
assert_eq!(Type::Boolean.check(&Type::Boolean), Ok(())); let bar = Type::Any;
assert_eq!(Type::Float.check(&Type::Float), Ok(()));
assert_eq!(Type::Integer.check(&Type::Integer), Ok(()));
assert_eq!(
Type::List {
item_type: Box::new(Type::Boolean),
length: 42
}
.check(&Type::List {
item_type: Box::new(Type::Boolean),
length: 42
}),
Ok(())
);
let mut map = BTreeMap::new(); foo.check(&bar).unwrap();
}
map.insert(Identifier::from("x"), Type::Integer); #[test]
map.insert(Identifier::from("y"), Type::String); fn check_type_boolean() {
map.insert(Identifier::from("z"), Type::Map(map.clone())); let foo = Type::Boolean;
let bar = Type::Boolean;
assert_eq!(Type::Map(map.clone()).check(&Type::Map(map)), Ok(())); foo.check(&bar).unwrap();
assert_eq!(Type::Range.check(&Type::Range), Ok(())); }
assert_eq!(Type::String.check(&Type::String), Ok(()));
#[test]
fn check_type_byte() {
let foo = Type::Byte;
let bar = Type::Byte;
foo.check(&bar).unwrap();
}
#[test]
fn check_type_character() {
let foo = Type::Character;
let bar = Type::Character;
foo.check(&bar).unwrap();
} }
#[test] #[test]
@ -449,7 +462,6 @@ mod tests {
item_type: Box::new(Type::Integer), item_type: Box::new(Type::Integer),
length: 42, length: 42,
}, },
Type::Map(BTreeMap::new()),
Type::Range, Type::Range,
Type::String, Type::String,
]; ];

File diff suppressed because it is too large Load Diff

View File

@ -6,7 +6,6 @@
//! - `Vm` struct that can be used to run an abstract syntax tree //! - `Vm` struct that can be used to run an abstract syntax tree
use std::{ use std::{
fmt::{self, Display, Formatter}, fmt::{self, Display, Formatter},
ops::Range,
sync::{Arc, Mutex}, sync::{Arc, Mutex},
}; };
@ -151,14 +150,10 @@ impl Vm {
} }
LetStatement::LetMut { identifier, value } => { LetStatement::LetMut { identifier, value } => {
let value_position = value.position(); let value_position = value.position();
let value = self let mutable_value = self
.run_expression(value, collect_garbage)? .run_expression(value, collect_garbage)?
.expect_value(value_position)?; .expect_value(value_position)?
let mutable_value = value.to_mut().map_err(|error| VmError::ValueError { .into_mutable();
error,
left_position: identifier.position,
right_position: value_position,
})?;
self.context.set_value(identifier.inner, mutable_value); self.context.set_value(identifier.inner, mutable_value);