Expand Value and Expression
This commit is contained in:
parent
8ae453add7
commit
447643f315
@ -10,7 +10,9 @@ use std::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
ast::{AbstractSyntaxTree, LetStatement, Node, OperatorExpression, Statement},
|
||||
ast::{
|
||||
AbstractSyntaxTree, LetStatement, Node, OperatorExpression, Statement, StructDefinition,
|
||||
},
|
||||
parse, Context, DustError, Expression, Identifier, Span, Type,
|
||||
};
|
||||
|
||||
@ -89,8 +91,8 @@ impl<'a> Analyzer<'a> {
|
||||
identifier.position,
|
||||
);
|
||||
} else {
|
||||
return Err(AnalyzerError::UndefinedVariable {
|
||||
identifier: identifier.clone(),
|
||||
return Err(AnalyzerError::ExpectedValue {
|
||||
actual: statement.clone(),
|
||||
});
|
||||
}
|
||||
|
||||
@ -106,8 +108,8 @@ impl<'a> Analyzer<'a> {
|
||||
identifier.position,
|
||||
);
|
||||
} else {
|
||||
return Err(AnalyzerError::UndefinedVariable {
|
||||
identifier: identifier.clone(),
|
||||
return Err(AnalyzerError::ExpectedValue {
|
||||
actual: statement.clone(),
|
||||
});
|
||||
}
|
||||
|
||||
@ -124,7 +126,9 @@ impl<'a> Analyzer<'a> {
|
||||
value,
|
||||
} => todo!(),
|
||||
},
|
||||
Statement::StructDefinition(_) => {}
|
||||
Statement::StructDefinition(_) => {
|
||||
let StructDefinition { identifier, fields } = statement;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -332,12 +332,12 @@ impl Expression {
|
||||
}
|
||||
|
||||
Some(Type::Struct(StructType::Fields {
|
||||
identifier: name.inner.clone(),
|
||||
name: name.inner.clone(),
|
||||
fields: field_types,
|
||||
}))
|
||||
}
|
||||
StructExpression::Unit { name } => Some(Type::Struct(StructType::Unit {
|
||||
identifier: name.inner.clone(),
|
||||
name: name.inner.clone(),
|
||||
})),
|
||||
},
|
||||
Expression::TupleAccess(tuple_access_expression) => {
|
||||
|
@ -78,7 +78,7 @@ impl BuiltInFunction {
|
||||
if let Some(value_arguments) = value_arguments {
|
||||
if value_arguments.len() == 1 {
|
||||
if let Some(integer) = value_arguments[0].as_integer() {
|
||||
Ok(Some(Value::boolean(integer % 2 == 0)))
|
||||
Ok(Some(Value::Boolean(integer % 2 == 0)))
|
||||
} else {
|
||||
Err(BuiltInFunctionError::ExpectedInteger)
|
||||
}
|
||||
@ -93,7 +93,7 @@ impl BuiltInFunction {
|
||||
if let Some(value_arguments) = value_arguments {
|
||||
if value_arguments.len() == 1 {
|
||||
if let Some(integer) = value_arguments[0].as_integer() {
|
||||
Ok(Some(Value::boolean(integer % 2 != 0)))
|
||||
Ok(Some(Value::Boolean(integer % 2 != 0)))
|
||||
} else {
|
||||
Err(BuiltInFunctionError::ExpectedInteger)
|
||||
}
|
||||
@ -107,8 +107,8 @@ impl BuiltInFunction {
|
||||
BuiltInFunction::Length => {
|
||||
if let Some(value_arguments) = value_arguments {
|
||||
if value_arguments.len() == 1 {
|
||||
if let Some(list) = value_arguments[0].as_list() {
|
||||
Ok(Some(Value::integer(list.len() as i64)))
|
||||
if let Value::List(list) = &value_arguments[0] {
|
||||
Ok(Some(Value::Integer(list.len() as i64)))
|
||||
} else {
|
||||
Err(BuiltInFunctionError::ExpectedInteger)
|
||||
}
|
||||
|
@ -332,14 +332,14 @@ impl Display for FunctionType {
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub enum StructType {
|
||||
Unit {
|
||||
identifier: Identifier,
|
||||
name: Identifier,
|
||||
},
|
||||
Tuple {
|
||||
identifier: Identifier,
|
||||
name: Identifier,
|
||||
fields: Vec<Type>,
|
||||
},
|
||||
Fields {
|
||||
identifier: Identifier,
|
||||
name: Identifier,
|
||||
fields: Vec<(Identifier, Type)>,
|
||||
},
|
||||
}
|
||||
@ -362,7 +362,9 @@ impl Display for StructType {
|
||||
write!(f, ")")
|
||||
}
|
||||
StructType::Fields {
|
||||
identifier, fields, ..
|
||||
name: identifier,
|
||||
fields,
|
||||
..
|
||||
} => {
|
||||
write!(f, "{identifier} {{ ")?;
|
||||
|
||||
|
@ -1,17 +1,15 @@
|
||||
//! Dust value representation
|
||||
use std::{
|
||||
cmp::Ordering,
|
||||
collections::BTreeMap,
|
||||
error::Error,
|
||||
fmt::{self, Display, Formatter},
|
||||
ops::{Range, RangeInclusive},
|
||||
ptr,
|
||||
sync::{Arc, RwLock, RwLockWriteGuard},
|
||||
sync::{Arc, RwLock},
|
||||
};
|
||||
|
||||
use serde::{
|
||||
de::{self, MapAccess, SeqAccess, Visitor},
|
||||
ser::{SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant, SerializeTuple},
|
||||
de::{self, MapAccess, Visitor},
|
||||
ser::{SerializeStruct, SerializeStructVariant},
|
||||
Deserialize, Deserializer, Serialize, Serializer,
|
||||
};
|
||||
|
||||
@ -58,7 +56,7 @@ pub enum Value {
|
||||
Character(char),
|
||||
Enum { name: Identifier, r#type: EnumType },
|
||||
Float(f64),
|
||||
Function(Arc<Function>),
|
||||
Function(Function),
|
||||
Integer(i64),
|
||||
List(Vec<Value>),
|
||||
Mutable(Arc<RwLock<Value>>),
|
||||
@ -70,22 +68,93 @@ pub enum Value {
|
||||
}
|
||||
|
||||
impl Value {
|
||||
pub fn mutable(value: Value) -> Value {
|
||||
Value::Mutable(Arc::new(RwLock::new(value)))
|
||||
}
|
||||
|
||||
pub fn byte_range(start: u8, end: u8) -> Value {
|
||||
Value::Range(Rangeable::Byte(start)..Rangeable::Byte(end))
|
||||
}
|
||||
|
||||
pub fn byte_range_inclusive(start: u8, end: u8) -> Value {
|
||||
Value::RangeInclusive(Rangeable::Byte(start)..=Rangeable::Byte(end))
|
||||
}
|
||||
|
||||
pub fn character_range(start: char, end: char) -> Value {
|
||||
Value::Range(Rangeable::Character(start)..Rangeable::Character(end))
|
||||
}
|
||||
|
||||
pub fn character_range_inclusive(start: char, end: char) -> Value {
|
||||
Value::RangeInclusive(Rangeable::Character(start)..=Rangeable::Character(end))
|
||||
}
|
||||
|
||||
pub fn float_range(start: f64, end: f64) -> Value {
|
||||
Value::Range(Rangeable::Float(start)..Rangeable::Float(end))
|
||||
}
|
||||
|
||||
pub fn float_range_inclusive(start: f64, end: f64) -> Value {
|
||||
Value::RangeInclusive(Rangeable::Float(start)..=Rangeable::Float(end))
|
||||
}
|
||||
|
||||
pub fn integer_range(start: i64, end: i64) -> Value {
|
||||
Value::Range(Rangeable::Integer(start)..Rangeable::Integer(end))
|
||||
}
|
||||
|
||||
pub fn integer_range_inclusive(start: i64, end: i64) -> Value {
|
||||
Value::RangeInclusive(Rangeable::Integer(start)..=Rangeable::Integer(end))
|
||||
}
|
||||
|
||||
pub fn string<T: ToString>(to_string: T) -> Value {
|
||||
Value::String(to_string.to_string())
|
||||
}
|
||||
|
||||
pub fn as_boolean(&self) -> Option<bool> {
|
||||
match self {
|
||||
Value::Boolean(value) => Some(*value),
|
||||
Value::Mutable(locked) => locked.read().unwrap().as_boolean(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_byte(&self) -> Option<u8> {
|
||||
match self {
|
||||
Value::Byte(value) => Some(*value),
|
||||
Value::Mutable(locked) => locked.read().unwrap().as_byte(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_character(&self) -> Option<char> {
|
||||
match self {
|
||||
Value::Character(value) => Some(*value),
|
||||
Value::Mutable(locked) => locked.read().unwrap().as_character(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_float(&self) -> Option<f64> {
|
||||
match self {
|
||||
Value::Float(value) => Some(*value),
|
||||
Value::Mutable(locked) => locked.read().unwrap().as_float(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_integer(&self) -> Option<i64> {
|
||||
match self {
|
||||
Value::Integer(value) => Some(*value),
|
||||
Value::Mutable(locked) => locked.read().unwrap().as_integer(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_mutable(&self) -> Result<&Arc<RwLock<Value>>, ValueError> {
|
||||
match self {
|
||||
Value::Mutable(inner) => Ok(inner),
|
||||
_ => Err(ValueError::CannotMutate(self.clone())),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_mutable(self) -> Value {
|
||||
match self {
|
||||
Value::Mutable(_) => self,
|
||||
@ -97,13 +166,6 @@ impl Value {
|
||||
matches!(self, Value::Mutable(_))
|
||||
}
|
||||
|
||||
pub fn as_mutable(&self) -> Result<&Arc<RwLock<Value>>, ValueError> {
|
||||
match self {
|
||||
Value::Mutable(inner) => Ok(inner),
|
||||
_ => Err(ValueError::CannotMutate(self.clone())),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mutate(&self, other: Value) -> Result<(), ValueError> {
|
||||
match self {
|
||||
Value::Mutable(inner) => *inner.write().unwrap() = other,
|
||||
@ -135,9 +197,9 @@ impl Value {
|
||||
Value::RangeInclusive(_) => Type::Range,
|
||||
Value::String(_) => Type::String,
|
||||
Value::Struct(r#struct) => match r#struct {
|
||||
Struct::Unit { r#type } => r#type.clone(),
|
||||
Struct::Tuple { r#type, .. } => r#type.clone(),
|
||||
Struct::Fields { r#type, .. } => r#type.clone(),
|
||||
Struct::Unit { r#type } => Type::Struct(r#type.clone()),
|
||||
Struct::Tuple { r#type, .. } => Type::Struct(r#type.clone()),
|
||||
Struct::Fields { r#type, .. } => Type::Struct(r#type.clone()),
|
||||
},
|
||||
Value::Tuple(values) => {
|
||||
let item_types = values.iter().map(Value::r#type).collect();
|
||||
@ -149,16 +211,24 @@ impl Value {
|
||||
|
||||
pub fn get_field(&self, field: &Identifier) -> Option<Value> {
|
||||
match self {
|
||||
Value::Struct(Struct::Fields { fields, .. }) => {
|
||||
fields.iter().find_map(|(identifier, value)| {
|
||||
Value::Mutable(inner) => inner.read().unwrap().get_field(field),
|
||||
Value::Struct(Struct::Fields {
|
||||
fields,
|
||||
r#type:
|
||||
StructType::Fields {
|
||||
fields: field_types,
|
||||
..
|
||||
},
|
||||
}) => field_types
|
||||
.iter()
|
||||
.zip(fields.iter())
|
||||
.find_map(|((identifier, _), value)| {
|
||||
if identifier == field {
|
||||
Some(value.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
Value::Mutable(inner) => inner.clone().read().unwrap().get_field(field),
|
||||
}),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@ -174,7 +244,9 @@ impl Value {
|
||||
pub fn add(&self, other: &Value) -> Result<Value, ValueError> {
|
||||
match (self, other) {
|
||||
(Value::Float(left), Value::Float(right)) => Ok(Value::Float(left + right)),
|
||||
(Value::Integer(left), Value::Integer(right)) => Ok(Value::Integer(left + right)),
|
||||
(Value::Integer(left), Value::Integer(right)) => {
|
||||
Ok(Value::Integer(left.saturating_add(*right)))
|
||||
}
|
||||
(Value::String(left), Value::String(right)) => {
|
||||
Ok(Value::String(format!("{}{}", left, right)))
|
||||
}
|
||||
@ -231,7 +303,9 @@ impl Value {
|
||||
pub fn subtract(&self, other: &Value) -> Result<Value, ValueError> {
|
||||
match (self, other) {
|
||||
(Value::Float(left), Value::Float(right)) => Ok(Value::Float(left - right)),
|
||||
(Value::Integer(left), Value::Integer(right)) => Ok(Value::Integer(left - right)),
|
||||
(Value::Integer(left), Value::Integer(right)) => {
|
||||
Ok(Value::Integer(left.saturating_sub(*right)))
|
||||
}
|
||||
(Value::Mutable(left), Value::Mutable(right)) => {
|
||||
let left = left.read().unwrap();
|
||||
let right = right.read().unwrap();
|
||||
@ -277,7 +351,9 @@ impl Value {
|
||||
pub fn multiply(&self, other: &Value) -> Result<Value, ValueError> {
|
||||
match (self, other) {
|
||||
(Value::Float(left), Value::Float(right)) => Ok(Value::Float(left * right)),
|
||||
(Value::Integer(left), Value::Integer(right)) => Ok(Value::Integer(left * right)),
|
||||
(Value::Integer(left), Value::Integer(right)) => {
|
||||
Ok(Value::Integer(left.saturating_mul(*right)))
|
||||
}
|
||||
(Value::Mutable(left), Value::Mutable(right)) => {
|
||||
let left = left.read().unwrap();
|
||||
let right = right.read().unwrap();
|
||||
@ -324,7 +400,7 @@ impl Value {
|
||||
match (self, other) {
|
||||
(Value::Float(left), Value::Float(right)) => Ok(Value::Float(left / right)),
|
||||
(Value::Integer(left), Value::Integer(right)) => {
|
||||
Ok(Value::Float((*left as f64) / (*right as f64)))
|
||||
Ok(Value::Integer(left.saturating_div(*right)))
|
||||
}
|
||||
(Value::Mutable(left), Value::Mutable(right)) => {
|
||||
let left = left.read().unwrap();
|
||||
@ -472,12 +548,28 @@ impl Value {
|
||||
match (self, other) {
|
||||
(Value::Float(left), Value::Float(right)) => Ok(Value::Boolean(left < right)),
|
||||
(Value::Integer(left), Value::Integer(right)) => Ok(Value::Boolean(left < right)),
|
||||
(Value::Float(left), Value::Integer(right)) => {
|
||||
Ok(Value::Boolean(*left < *right as f64))
|
||||
}
|
||||
(Value::Integer(left), Value::Float(right)) => {
|
||||
Ok(Value::Boolean((*left as f64) < *right))
|
||||
}
|
||||
(Value::Mutable(left), Value::Mutable(right)) => {
|
||||
let left = left.read().unwrap();
|
||||
let right = right.read().unwrap();
|
||||
|
||||
left.less_than(&right)
|
||||
}
|
||||
(Value::Mutable(left), right) => {
|
||||
let left = left.read().unwrap();
|
||||
|
||||
left.less_than(right)
|
||||
}
|
||||
(left, Value::Mutable(right)) => {
|
||||
let right = right.read().unwrap();
|
||||
|
||||
left.less_than(&right)
|
||||
}
|
||||
_ => Err(ValueError::CannotLessThan(self.clone(), other.clone())),
|
||||
}
|
||||
}
|
||||
@ -486,12 +578,28 @@ impl Value {
|
||||
match (self, other) {
|
||||
(Value::Float(left), Value::Float(right)) => Ok(Value::Boolean(left <= right)),
|
||||
(Value::Integer(left), Value::Integer(right)) => Ok(Value::Boolean(left <= right)),
|
||||
(Value::Float(left), Value::Integer(right)) => {
|
||||
Ok(Value::Boolean(*left <= *right as f64))
|
||||
}
|
||||
(Value::Integer(left), Value::Float(right)) => {
|
||||
Ok(Value::Boolean(*left as f64 <= *right))
|
||||
}
|
||||
(Value::Mutable(left), Value::Mutable(right)) => {
|
||||
let left = left.read().unwrap();
|
||||
let right = right.read().unwrap();
|
||||
|
||||
left.less_than_or_equal(&right)
|
||||
}
|
||||
(Value::Mutable(left), right) => {
|
||||
let left = left.read().unwrap();
|
||||
|
||||
left.less_than_or_equal(right)
|
||||
}
|
||||
(left, Value::Mutable(right)) => {
|
||||
let right = right.read().unwrap();
|
||||
|
||||
left.less_than_or_equal(&right)
|
||||
}
|
||||
_ => Err(ValueError::CannotLessThanOrEqual(
|
||||
self.clone(),
|
||||
other.clone(),
|
||||
@ -503,12 +611,28 @@ impl Value {
|
||||
match (self, other) {
|
||||
(Value::Float(left), Value::Float(right)) => Ok(Value::Boolean(left > right)),
|
||||
(Value::Integer(left), Value::Integer(right)) => Ok(Value::Boolean(left > right)),
|
||||
(Value::Float(left), Value::Integer(right)) => {
|
||||
Ok(Value::Boolean(*left > *right as f64))
|
||||
}
|
||||
(Value::Integer(left), Value::Float(right)) => {
|
||||
Ok(Value::Boolean(*left as f64 > *right))
|
||||
}
|
||||
(Value::Mutable(left), Value::Mutable(right)) => {
|
||||
let left = left.read().unwrap();
|
||||
let right = right.read().unwrap();
|
||||
|
||||
left.greater_than(&right)
|
||||
}
|
||||
(Value::Mutable(left), right) => {
|
||||
let left = left.read().unwrap();
|
||||
|
||||
left.greater_than(right)
|
||||
}
|
||||
(left, Value::Mutable(right)) => {
|
||||
let right = right.read().unwrap();
|
||||
|
||||
left.greater_than(&right)
|
||||
}
|
||||
_ => Err(ValueError::CannotGreaterThan(self.clone(), other.clone())),
|
||||
}
|
||||
}
|
||||
@ -517,12 +641,28 @@ impl Value {
|
||||
match (self, other) {
|
||||
(Value::Float(left), Value::Float(right)) => Ok(Value::Boolean(left >= right)),
|
||||
(Value::Integer(left), Value::Integer(right)) => Ok(Value::Boolean(left >= right)),
|
||||
(Value::Float(left), Value::Integer(right)) => {
|
||||
Ok(Value::Boolean(*left >= *right as f64))
|
||||
}
|
||||
(Value::Integer(left), Value::Float(right)) => {
|
||||
Ok(Value::Boolean(*left as f64 >= *right))
|
||||
}
|
||||
(Value::Mutable(left), Value::Mutable(right)) => {
|
||||
let left = left.read().unwrap();
|
||||
let right = right.read().unwrap();
|
||||
|
||||
left.greater_than_or_equal(&right)
|
||||
}
|
||||
(Value::Mutable(left), right) => {
|
||||
let left = left.read().unwrap();
|
||||
|
||||
left.greater_than_or_equal(right)
|
||||
}
|
||||
(left, Value::Mutable(right)) => {
|
||||
let right = right.read().unwrap();
|
||||
|
||||
left.greater_than_or_equal(&right)
|
||||
}
|
||||
_ => Err(ValueError::CannotGreaterThanOrEqual(
|
||||
self.clone(),
|
||||
other.clone(),
|
||||
@ -531,15 +671,15 @@ impl Value {
|
||||
}
|
||||
|
||||
pub fn and(&self, other: &Value) -> Result<Value, ValueError> {
|
||||
match (self, other) {
|
||||
(Value::Boolean(left), Value::Boolean(right)) => Ok(Value::Boolean(*left && *right)),
|
||||
match (self.as_boolean(), other.as_boolean()) {
|
||||
(Some(left), Some(right)) => Ok(Value::Boolean(left && right)),
|
||||
_ => Err(ValueError::CannotAnd(self.clone(), other.clone())),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn or(&self, other: &Value) -> Result<Value, ValueError> {
|
||||
match (self, other) {
|
||||
(Value::Boolean(left), Value::Boolean(right)) => Ok(Value::Boolean(*left || *right)),
|
||||
match (self.as_boolean(), other.as_boolean()) {
|
||||
(Some(left), Some(right)) => Ok(Value::Boolean(left || right)),
|
||||
_ => Err(ValueError::CannotOr(self.clone(), other.clone())),
|
||||
}
|
||||
}
|
||||
@ -918,15 +1058,15 @@ impl<'de> Deserialize<'de> for Function {
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub enum Struct {
|
||||
Unit {
|
||||
r#type: Type,
|
||||
r#type: StructType,
|
||||
},
|
||||
Tuple {
|
||||
r#type: Type,
|
||||
r#type: StructType,
|
||||
fields: Vec<Value>,
|
||||
},
|
||||
Fields {
|
||||
r#type: Type,
|
||||
fields: Vec<(Identifier, Value)>,
|
||||
r#type: StructType,
|
||||
fields: Vec<Value>,
|
||||
},
|
||||
}
|
||||
|
||||
@ -947,24 +1087,34 @@ impl Display for Struct {
|
||||
|
||||
write!(f, ")")
|
||||
}
|
||||
Struct::Fields { fields, .. } => {
|
||||
Struct::Fields {
|
||||
fields,
|
||||
r#type:
|
||||
StructType::Fields {
|
||||
fields: field_types,
|
||||
..
|
||||
},
|
||||
} => {
|
||||
write!(f, "{{ ")?;
|
||||
|
||||
for (index, (identifier, r#type)) in fields.iter().enumerate() {
|
||||
for (index, ((identifier, _), value)) in
|
||||
field_types.iter().zip(fields.iter()).enumerate()
|
||||
{
|
||||
if index > 0 {
|
||||
write!(f, ", ")?;
|
||||
}
|
||||
|
||||
write!(f, "{}: {}", identifier, r#type)?;
|
||||
write!(f, "{}: {}", identifier, value)?;
|
||||
}
|
||||
|
||||
write!(f, " }}")
|
||||
}
|
||||
_ => Ok(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
enum Rangeable {
|
||||
Byte(u8),
|
||||
Character(char),
|
||||
@ -985,6 +1135,12 @@ impl Display for Rangeable {
|
||||
|
||||
impl Eq for Rangeable {}
|
||||
|
||||
impl PartialOrd for Rangeable {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Rangeable {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
match (self, other) {
|
||||
|
@ -16,10 +16,10 @@ use crate::{
|
||||
AbstractSyntaxTree, BlockExpression, CallExpression, ComparisonOperator, ElseExpression,
|
||||
FieldAccessExpression, IfExpression, LetStatement, ListExpression, ListIndexExpression,
|
||||
LiteralExpression, LogicOperator, LoopExpression, MathOperator, Node, OperatorExpression,
|
||||
RangeExpression, Statement,
|
||||
RangeExpression, Statement, StructDefinition,
|
||||
},
|
||||
parse, Analyzer, BuiltInFunctionError, Context, DustError, Expression, Identifier, ParseError,
|
||||
Span, Value, ValueError,
|
||||
Span, StructType, Type, Value, ValueError,
|
||||
};
|
||||
|
||||
/// Run the source code and return the result.
|
||||
@ -30,7 +30,7 @@ use crate::{
|
||||
/// # use dust_lang::value::Value;
|
||||
/// let result = run("40 + 2");
|
||||
///
|
||||
/// assert_eq!(result, Ok(Some(Value::integer(42))));
|
||||
/// assert_eq!(result, Ok(Some(Value::Integer(42))));
|
||||
/// ```
|
||||
pub fn run(source: &str) -> Result<Option<Value>, DustError> {
|
||||
let context = Context::new();
|
||||
@ -45,12 +45,12 @@ pub fn run(source: &str) -> Result<Option<Value>, DustError> {
|
||||
/// # use dust_lang::{Context, Identifier, Value, run_with_context};
|
||||
/// let context = Context::new();
|
||||
///
|
||||
/// context.set_value(Identifier::new("foo"), Value::integer(40));
|
||||
/// context.set_value(Identifier::new("foo"), Value::Integer(40));
|
||||
/// context.update_last_position(&Identifier::new("foo"), (100, 100));
|
||||
///
|
||||
/// let result = run_with_context("foo + 2", context);
|
||||
///
|
||||
/// assert_eq!(result, Ok(Some(Value::integer(42))));
|
||||
/// assert_eq!(result, Ok(Some(Value::Integer(42))));
|
||||
/// ```
|
||||
pub fn run_with_context(source: &str, context: Context) -> Result<Option<Value>, DustError> {
|
||||
let abstract_syntax_tree = parse(source)?;
|
||||
@ -119,7 +119,20 @@ impl Vm {
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
Statement::StructDefinition(_) => todo!(),
|
||||
Statement::StructDefinition(struct_definition) => {
|
||||
let (name, struct_type) = match struct_definition.inner {
|
||||
StructDefinition::Unit { name } => {
|
||||
(name.inner.clone(), StructType::Unit { name: name.inner })
|
||||
}
|
||||
StructDefinition::Tuple { name, items } => todo!(),
|
||||
StructDefinition::Fields { name, fields } => todo!(),
|
||||
};
|
||||
|
||||
self.context
|
||||
.set_type(name, Type::Struct(struct_type), struct_definition.position);
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
};
|
||||
|
||||
if collect_garbage {
|
||||
@ -203,20 +216,65 @@ impl Vm {
|
||||
Expression::Operator(operator_expression) => {
|
||||
self.run_operator(*operator_expression.inner, collect_garbage)
|
||||
}
|
||||
Expression::Range(range_expression) => match range_expression.inner.as_ref() {
|
||||
Expression::Range(range_expression) => match *range_expression.inner {
|
||||
RangeExpression::Exclusive { start, end } => {
|
||||
let start_position = start.position();
|
||||
let start = self
|
||||
.run_expression(*start.inner, collect_garbage)?
|
||||
.run_expression(start, collect_garbage)?
|
||||
.expect_value(start_position)?;
|
||||
let end_position = end.position();
|
||||
let end = self
|
||||
.run_expression(*end.inner, collect_garbage)?
|
||||
.run_expression(end, collect_garbage)?
|
||||
.expect_value(end_position)?;
|
||||
|
||||
Ok(Evaluation::Return(Some(Value::range(start..end))))
|
||||
match (start, end) {
|
||||
(Value::Byte(start), Value::Byte(end)) => {
|
||||
Ok(Evaluation::Return(Some(Value::byte_range(start, end))))
|
||||
}
|
||||
(Value::Character(start), Value::Character(end)) => {
|
||||
Ok(Evaluation::Return(Some(Value::character_range(start, end))))
|
||||
}
|
||||
(Value::Float(start), Value::Float(end)) => {
|
||||
Ok(Evaluation::Return(Some(Value::float_range(start, end))))
|
||||
}
|
||||
(Value::Integer(start), Value::Integer(end)) => {
|
||||
Ok(Evaluation::Return(Some(Value::integer_range(start, end))))
|
||||
}
|
||||
_ => Err(VmError::InvalidRange {
|
||||
start_position,
|
||||
end_position,
|
||||
}),
|
||||
}
|
||||
}
|
||||
RangeExpression::Inclusive { start, end } => {
|
||||
let start_position = start.position();
|
||||
let start = self
|
||||
.run_expression(start, collect_garbage)?
|
||||
.expect_value(start_position)?;
|
||||
let end_position = end.position();
|
||||
let end = self
|
||||
.run_expression(end, collect_garbage)?
|
||||
.expect_value(end_position)?;
|
||||
|
||||
match (start, end) {
|
||||
(Value::Byte(start), Value::Byte(end)) => Ok(Evaluation::Return(Some(
|
||||
Value::byte_range_inclusive(start, end),
|
||||
))),
|
||||
(Value::Character(start), Value::Character(end)) => Ok(Evaluation::Return(
|
||||
Some(Value::character_range_inclusive(start, end)),
|
||||
)),
|
||||
(Value::Float(start), Value::Float(end)) => Ok(Evaluation::Return(Some(
|
||||
Value::float_range_inclusive(start, end),
|
||||
))),
|
||||
(Value::Integer(start), Value::Integer(end)) => Ok(Evaluation::Return(
|
||||
Some(Value::integer_range_inclusive(start, end)),
|
||||
)),
|
||||
_ => Err(VmError::InvalidRange {
|
||||
start_position,
|
||||
end_position,
|
||||
}),
|
||||
}
|
||||
}
|
||||
RangeExpression::Inclusive { start, end } => todo!(),
|
||||
},
|
||||
Expression::Struct(_) => todo!(),
|
||||
Expression::TupleAccess(_) => todo!(),
|
||||
@ -341,7 +399,7 @@ impl Vm {
|
||||
let integer = value
|
||||
.as_integer()
|
||||
.ok_or(VmError::ExpectedBoolean { position })?;
|
||||
let negated = Value::integer(-integer);
|
||||
let negated = Value::Integer(-integer);
|
||||
|
||||
Ok(Evaluation::Return(Some(negated)))
|
||||
}
|
||||
@ -353,7 +411,7 @@ impl Vm {
|
||||
let boolean = value
|
||||
.as_boolean()
|
||||
.ok_or(VmError::ExpectedBoolean { position })?;
|
||||
let not = Value::boolean(!boolean);
|
||||
let not = Value::Boolean(!boolean);
|
||||
|
||||
Ok(Evaluation::Return(Some(not)))
|
||||
}
|
||||
@ -442,11 +500,10 @@ impl Vm {
|
||||
|
||||
fn run_literal(&self, literal: LiteralExpression) -> Result<Evaluation, VmError> {
|
||||
let value = match literal {
|
||||
LiteralExpression::Boolean(boolean) => Value::boolean(boolean),
|
||||
LiteralExpression::Float(float) => Value::float(float),
|
||||
LiteralExpression::Integer(integer) => Value::integer(integer),
|
||||
LiteralExpression::String(string) => Value::string(string),
|
||||
LiteralExpression::Value(value) => value,
|
||||
LiteralExpression::Boolean(boolean) => Value::Boolean(boolean),
|
||||
LiteralExpression::Float(float) => Value::Float(float),
|
||||
LiteralExpression::Integer(integer) => Value::Integer(integer),
|
||||
LiteralExpression::String(string) => Value::String(string),
|
||||
};
|
||||
|
||||
Ok(Evaluation::Return(Some(value)))
|
||||
@ -499,7 +556,7 @@ impl Vm {
|
||||
});
|
||||
};
|
||||
|
||||
let function = if let Some(function) = invoker_value.as_function() {
|
||||
let function = if let Value::Function(function) = invoker_value {
|
||||
function
|
||||
} else {
|
||||
return Err(VmError::ExpectedFunction {
|
||||
@ -569,7 +626,7 @@ impl Vm {
|
||||
.run_expression(repeat_operand, collect_garbage)?
|
||||
.expect_value(position)?;
|
||||
|
||||
Ok(Evaluation::Return(Some(Value::list(vec![
|
||||
Ok(Evaluation::Return(Some(Value::List(vec![
|
||||
value;
|
||||
length as usize
|
||||
]))))
|
||||
@ -586,7 +643,7 @@ impl Vm {
|
||||
values.push(value);
|
||||
}
|
||||
|
||||
Ok(Evaluation::Return(Some(Value::list(values))))
|
||||
Ok(Evaluation::Return(Some(Value::List(values))))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -769,6 +826,10 @@ pub enum VmError {
|
||||
ExpectedValue {
|
||||
position: Span,
|
||||
},
|
||||
InvalidRange {
|
||||
start_position: Span,
|
||||
end_position: Span,
|
||||
},
|
||||
UndefinedVariable {
|
||||
identifier: Identifier,
|
||||
position: Span,
|
||||
@ -803,6 +864,11 @@ impl VmError {
|
||||
Self::ExpectedFunction { position, .. } => *position,
|
||||
Self::ExpectedList { position } => *position,
|
||||
Self::ExpectedValue { position } => *position,
|
||||
Self::InvalidRange {
|
||||
start_position,
|
||||
end_position,
|
||||
..
|
||||
} => (start_position.0, end_position.1),
|
||||
Self::UndefinedVariable { position, .. } => *position,
|
||||
Self::UndefinedProperty {
|
||||
property_position, ..
|
||||
@ -891,6 +957,16 @@ impl Display for VmError {
|
||||
Self::ExpectedValue { position } => {
|
||||
write!(f, "Expected a value at position: {:?}", position)
|
||||
}
|
||||
Self::InvalidRange {
|
||||
start_position,
|
||||
end_position,
|
||||
} => {
|
||||
write!(
|
||||
f,
|
||||
"Invalid range with start position: {:?} and end position: {:?}",
|
||||
start_position, end_position
|
||||
)
|
||||
}
|
||||
Self::UndefinedVariable {
|
||||
identifier,
|
||||
position,
|
||||
@ -912,7 +988,7 @@ impl Display for VmError {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::Struct;
|
||||
use crate::{Struct, StructType, Type};
|
||||
|
||||
use super::*;
|
||||
|
||||
@ -920,7 +996,7 @@ mod tests {
|
||||
fn async_block() {
|
||||
let input = "let mut x = 1; async { x += 1; x -= 1; } x";
|
||||
|
||||
assert!(run(input).unwrap().unwrap().as_integer().is_some());
|
||||
assert_eq!(run(input), Ok(Some(Value::Integer(1))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -929,12 +1005,15 @@ mod tests {
|
||||
|
||||
assert_eq!(
|
||||
run(input),
|
||||
Ok(Some(Value::r#struct(Struct::Fields {
|
||||
Ok(Some(Value::Struct(Struct::Fields {
|
||||
r#type: StructType::Fields {
|
||||
name: Identifier::new("Foo"),
|
||||
fields: vec![
|
||||
(Identifier::new("bar"), Value::integer(42)),
|
||||
(Identifier::new("baz"), Value::float(4.0))
|
||||
(Identifier::new("bar"), Type::Integer),
|
||||
(Identifier::new("baz"), Type::Float)
|
||||
]
|
||||
},
|
||||
fields: vec![Value::Integer(42), Value::Float(4.0)]
|
||||
})))
|
||||
);
|
||||
}
|
||||
@ -949,9 +1028,12 @@ mod tests {
|
||||
|
||||
assert_eq!(
|
||||
run(input),
|
||||
Ok(Some(Value::r#struct(Struct::Tuple {
|
||||
Ok(Some(Value::Struct(Struct::Tuple {
|
||||
r#type: StructType::Tuple {
|
||||
name: Identifier::new("Foo"),
|
||||
fields: vec![Value::integer(42)]
|
||||
fields: vec![Type::Integer]
|
||||
},
|
||||
fields: vec![Value::Integer(42)]
|
||||
})))
|
||||
)
|
||||
}
|
||||
@ -962,9 +1044,11 @@ mod tests {
|
||||
|
||||
assert_eq!(
|
||||
run(input),
|
||||
Ok(Some(Value::r#struct(Struct::Tuple {
|
||||
name: Identifier::new("Foo"),
|
||||
fields: vec![Value::integer(42)]
|
||||
Ok(Some(Value::Struct(Struct::Tuple {
|
||||
r#type: StructType::Unit {
|
||||
name: Identifier::new("Foo")
|
||||
},
|
||||
fields: vec![Value::Integer(42)]
|
||||
})))
|
||||
);
|
||||
}
|
||||
@ -979,8 +1063,10 @@ mod tests {
|
||||
|
||||
assert_eq!(
|
||||
run(input),
|
||||
Ok(Some(Value::r#struct(Struct::Unit {
|
||||
Ok(Some(Value::Struct(Struct::Unit {
|
||||
r#type: StructType::Unit {
|
||||
name: Identifier::new("Foo")
|
||||
}
|
||||
})))
|
||||
)
|
||||
}
|
||||
@ -991,8 +1077,10 @@ mod tests {
|
||||
|
||||
assert_eq!(
|
||||
run(input),
|
||||
Ok(Some(Value::r#struct(Struct::Unit {
|
||||
Ok(Some(Value::Struct(Struct::Unit {
|
||||
r#type: StructType::Unit {
|
||||
name: Identifier::new("Foo")
|
||||
}
|
||||
})))
|
||||
);
|
||||
}
|
||||
@ -1001,7 +1089,7 @@ mod tests {
|
||||
fn list_index_nested() {
|
||||
let input = "[[1, 2], [42, 4], [5, 6]][1][0]";
|
||||
|
||||
assert_eq!(run(input), Ok(Some(Value::integer(42))));
|
||||
assert_eq!(run(input), Ok(Some(Value::Integer(42))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -1010,9 +1098,9 @@ mod tests {
|
||||
|
||||
assert_eq!(
|
||||
run(input),
|
||||
Ok(Some(Value::list(vec![
|
||||
Value::integer(2),
|
||||
Value::integer(3)
|
||||
Ok(Some(Value::List(vec![
|
||||
Value::Integer(2),
|
||||
Value::Integer(3)
|
||||
])))
|
||||
);
|
||||
}
|
||||
@ -1021,35 +1109,35 @@ mod tests {
|
||||
fn range() {
|
||||
let input = "1..5";
|
||||
|
||||
assert_eq!(run(input), Ok(Some(Value::range(1..5))));
|
||||
assert_eq!(run(input), Ok(Some(Value::integer_range(1, 5))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn negate_expression() {
|
||||
let input = "let x = -42; -x";
|
||||
|
||||
assert_eq!(run(input), Ok(Some(Value::integer(42))));
|
||||
assert_eq!(run(input), Ok(Some(Value::Integer(42))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_expression() {
|
||||
let input = "!(1 == 2 || 3 == 4 || 5 == 6)";
|
||||
|
||||
assert_eq!(run(input), Ok(Some(Value::boolean(true))));
|
||||
assert_eq!(run(input), Ok(Some(Value::Boolean(true))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn list_index() {
|
||||
let input = "[1, 42, 3][1]";
|
||||
|
||||
assert_eq!(run(input), Ok(Some(Value::integer(42))));
|
||||
assert_eq!(run(input), Ok(Some(Value::Integer(42))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn map_property_access() {
|
||||
let input = "{ a = 42 }.a";
|
||||
|
||||
assert_eq!(run(input), Ok(Some(Value::integer(42))));
|
||||
assert_eq!(run(input), Ok(Some(Value::Integer(42))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -1063,7 +1151,7 @@ mod tests {
|
||||
fn to_string() {
|
||||
let input = "to_string(42)";
|
||||
|
||||
assert_eq!(run(input), Ok(Some(Value::string("42".to_string()))));
|
||||
assert_eq!(run(input), Ok(Some(Value::string("42"))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -1077,7 +1165,7 @@ mod tests {
|
||||
fn if_else() {
|
||||
let input = "if false { 1 } else { 2 }";
|
||||
|
||||
assert_eq!(run(input), Ok(Some(Value::integer(2))));
|
||||
assert_eq!(run(input), Ok(Some(Value::Integer(2))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -1091,155 +1179,153 @@ mod tests {
|
||||
fn if_else_if_else() {
|
||||
let input = "if false { 1 } else if false { 2 } else { 3 }";
|
||||
|
||||
assert_eq!(run(input), Ok(Some(Value::integer(3))));
|
||||
assert_eq!(run(input), Ok(Some(Value::Integer(3))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn while_loop() {
|
||||
let input = "let mut x = 0; while x < 5 { x += 1; } x";
|
||||
|
||||
assert_eq!(run(input), Ok(Some(Value::integer(5))));
|
||||
assert_eq!(run(input), Ok(Some(Value::Integer(5))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn subtract_assign() {
|
||||
let input = "let mut x = 1; x -= 1; x";
|
||||
|
||||
assert_eq!(run(input), Ok(Some(Value::integer(0))));
|
||||
assert_eq!(run(input), Ok(Some(Value::mutable(Value::Integer(0)))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn add_assign() {
|
||||
env_logger::builder().is_test(true).try_init().ok();
|
||||
|
||||
let input = "let mut x = 1; x += 1; x";
|
||||
|
||||
assert_eq!(run(input), Ok(Some(Value::integer(2))));
|
||||
assert_eq!(run(input), Ok(Some(Value::mutable(Value::Integer(2)))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn and() {
|
||||
let input = "true && true";
|
||||
|
||||
assert_eq!(run(input), Ok(Some(Value::boolean(true))));
|
||||
assert_eq!(run(input), Ok(Some(Value::Boolean(true))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn or() {
|
||||
let input = "true || false";
|
||||
|
||||
assert_eq!(run(input), Ok(Some(Value::boolean(true))));
|
||||
assert_eq!(run(input), Ok(Some(Value::Boolean(true))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn integer_equal() {
|
||||
let input = "42 == 42";
|
||||
|
||||
assert_eq!(run(input), Ok(Some(Value::boolean(true))));
|
||||
assert_eq!(run(input), Ok(Some(Value::Boolean(true))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn modulo() {
|
||||
let input = "42 % 2";
|
||||
|
||||
assert_eq!(run(input), Ok(Some(Value::integer(0))));
|
||||
assert_eq!(run(input), Ok(Some(Value::Integer(0))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn divide() {
|
||||
let input = "42 / 2";
|
||||
|
||||
assert_eq!(run(input), Ok(Some(Value::integer(21))));
|
||||
assert_eq!(run(input), Ok(Some(Value::Integer(21))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn less_than() {
|
||||
let input = "2 < 3";
|
||||
|
||||
assert_eq!(run(input), Ok(Some(Value::boolean(true))));
|
||||
assert_eq!(run(input), Ok(Some(Value::Boolean(true))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn less_than_or_equal() {
|
||||
let input = "42 <= 42";
|
||||
|
||||
assert_eq!(run(input), Ok(Some(Value::boolean(true))));
|
||||
assert_eq!(run(input), Ok(Some(Value::Boolean(true))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn greater_than() {
|
||||
let input = "2 > 3";
|
||||
|
||||
assert_eq!(run(input), Ok(Some(Value::boolean(false))));
|
||||
assert_eq!(run(input), Ok(Some(Value::Boolean(false))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn greater_than_or_equal() {
|
||||
let input = "42 >= 42";
|
||||
|
||||
assert_eq!(run(input), Ok(Some(Value::boolean(true))));
|
||||
assert_eq!(run(input), Ok(Some(Value::Boolean(true))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn integer_saturating_add() {
|
||||
let input = "9223372036854775807 + 1";
|
||||
|
||||
assert_eq!(run(input), Ok(Some(Value::integer(i64::MAX))));
|
||||
assert_eq!(run(input), Ok(Some(Value::Integer(i64::MAX))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn integer_saturating_sub() {
|
||||
let input = "-9223372036854775808 - 1";
|
||||
|
||||
assert_eq!(run(input), Ok(Some(Value::integer(i64::MIN))));
|
||||
assert_eq!(run(input), Ok(Some(Value::Integer(i64::MIN))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiply() {
|
||||
let input = "2 * 3";
|
||||
|
||||
assert_eq!(run(input), Ok(Some(Value::integer(6))));
|
||||
assert_eq!(run(input), Ok(Some(Value::Integer(6))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn boolean() {
|
||||
let input = "true";
|
||||
|
||||
assert_eq!(run(input), Ok(Some(Value::boolean(true))));
|
||||
assert_eq!(run(input), Ok(Some(Value::Boolean(true))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_even() {
|
||||
let input = "is_even(42)";
|
||||
|
||||
assert_eq!(run(input), Ok(Some(Value::boolean(true))));
|
||||
assert_eq!(run(input), Ok(Some(Value::Boolean(true))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_odd() {
|
||||
let input = "is_odd(42)";
|
||||
|
||||
assert_eq!(run(input), Ok(Some(Value::boolean(false))));
|
||||
assert_eq!(run(input), Ok(Some(Value::Boolean(false))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn length() {
|
||||
let input = "length([1, 2, 3])";
|
||||
|
||||
assert_eq!(run(input), Ok(Some(Value::integer(3))));
|
||||
assert_eq!(run(input), Ok(Some(Value::Integer(3))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn add() {
|
||||
let input = "1 + 2";
|
||||
|
||||
assert_eq!(run(input), Ok(Some(Value::integer(3))));
|
||||
assert_eq!(run(input), Ok(Some(Value::Integer(3))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn add_multiple() {
|
||||
let input = "1 + 2 + 3";
|
||||
|
||||
assert_eq!(run(input), Ok(Some(Value::integer(6))));
|
||||
assert_eq!(run(input), Ok(Some(Value::Integer(6))));
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user