Continue value overhaul
This commit is contained in:
parent
8bff39a7db
commit
8ae453add7
@ -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!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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};
|
||||||
|
@ -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}")?;
|
||||||
@ -388,37 +380,58 @@ impl Display for StructType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[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(()));
|
foo.check(&bar).unwrap();
|
||||||
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();
|
#[test]
|
||||||
|
fn check_type_boolean() {
|
||||||
|
let foo = Type::Boolean;
|
||||||
|
let bar = Type::Boolean;
|
||||||
|
|
||||||
map.insert(Identifier::from("x"), Type::Integer);
|
foo.check(&bar).unwrap();
|
||||||
map.insert(Identifier::from("y"), Type::String);
|
}
|
||||||
map.insert(Identifier::from("z"), Type::Map(map.clone()));
|
|
||||||
|
|
||||||
assert_eq!(Type::Map(map.clone()).check(&Type::Map(map)), Ok(()));
|
#[test]
|
||||||
assert_eq!(Type::Range.check(&Type::Range), Ok(()));
|
fn check_type_byte() {
|
||||||
assert_eq!(Type::String.check(&Type::String), Ok(()));
|
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
@ -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);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user