diff --git a/dust-lang/src/analyzer.rs b/dust-lang/src/analyzer.rs index c17e2cb..c41124d 100644 --- a/dust-lang/src/analyzer.rs +++ b/dust-lang/src/analyzer.rs @@ -17,8 +17,8 @@ use crate::{ PrimitiveValueExpression, RangeExpression, Span, Statement, StructDefinition, StructExpression, TupleAccessExpression, }, - core_library, parse, Context, ContextError, DustError, Expression, Identifier, StructType, - Type, + core_library, parse, Context, ContextError, DustError, Expression, Identifier, Rangeable, + RangeableType, StructType, Type, }; /// Analyzes the abstract syntax tree for errors. @@ -255,6 +255,18 @@ impl<'recovered, 'a: 'recovered> Analyzer<'a> { list: list.clone(), }); } + } else if let Type::Range { r#type } = &index_type { + if let RangeableType::Integer = r#type { + // Ok + } else { + return Err(AnalysisError::ExpectedType { + expected: Type::Range { + r#type: RangeableType::Integer, + }, + actual: index_type, + actual_expression: index.clone(), + }); + } } else { return Err(AnalysisError::ExpectedType { expected: Type::Integer, diff --git a/dust-lang/src/core_library.rs b/dust-lang/src/core_library.rs index 8b14ae4..6c771a2 100644 --- a/dust-lang/src/core_library.rs +++ b/dust-lang/src/core_library.rs @@ -16,24 +16,6 @@ pub fn core_library<'a>() -> &'a Context { (0, 0), ), ), - ( - Identifier::new("is_even"), - ( - ContextData::VariableValue(Value::Function(Function::BuiltIn( - BuiltInFunction::IsEven, - ))), - (0, 0), - ), - ), - ( - Identifier::new("is_odd"), - ( - ContextData::VariableValue(Value::Function(Function::BuiltIn( - BuiltInFunction::IsOdd, - ))), - (0, 0), - ), - ), ( Identifier::new("read_line"), ( diff --git a/dust-lang/src/value.rs b/dust-lang/src/value.rs index 11ac735..bf364a4 100644 --- a/dust-lang/src/value.rs +++ b/dust-lang/src/value.rs @@ -234,27 +234,36 @@ impl Value { } pub fn get_field(&self, field: &Identifier) -> Option { - let built_in_function = match field.as_str() { - "to_string" => BuiltInFunction::ToString, - "length" => { - return match self { - Value::List(values) => Some(Value::Integer(values.len() as i64)), - Value::String(string) => Some(Value::Integer(string.len() as i64)), - Value::Map(map) => Some(Value::Integer(map.len() as i64)), - _ => None, - } - } - _ => { - return match self { - Value::Mutable(inner) => inner.read().unwrap().get_field(field), - Value::Struct(Struct::Fields { fields, .. }) => fields.get(field).cloned(), - Value::Map(pairs) => pairs.get(field).cloned(), - _ => None, - }; - } - }; + if let Value::Mutable(locked) = self { + return locked.read().unwrap().get_field(field); + } - Some(Value::Function(Function::BuiltIn(built_in_function))) + match field.as_str() { + "is_even" => match self { + Value::Integer(integer) => Some(Value::Boolean(integer % 2 == 0)), + Value::Float(float) => Some(Value::Boolean(float % 2.0 == 0.0)), + _ => None, + }, + "is_odd" => match self { + Value::Integer(integer) => Some(Value::Boolean(integer % 2 != 0)), + Value::Float(float) => Some(Value::Boolean(float % 2.0 != 0.0)), + _ => None, + }, + "to_string" => Some(Value::Function(Function::BuiltIn( + BuiltInFunction::ToString, + ))), + "length" => match self { + Value::List(values) => Some(Value::Integer(values.len() as i64)), + Value::String(string) => Some(Value::Integer(string.len() as i64)), + Value::Map(map) => Some(Value::Integer(map.len() as i64)), + _ => None, + }, + _ => match self { + Value::Struct(Struct::Fields { fields, .. }) => fields.get(field).cloned(), + Value::Map(pairs) => pairs.get(field).cloned(), + _ => None, + }, + } } pub fn get_index(&self, index: Value) -> Result, ValueError> { diff --git a/dust-lang/src/vm.rs b/dust-lang/src/vm.rs index 6be144d..ca8d206 100644 --- a/dust-lang/src/vm.rs +++ b/dust-lang/src/vm.rs @@ -737,7 +737,7 @@ impl Vm { }); } } else { - return Err(RuntimeError::UndefinedProperty { + return Err(RuntimeError::UndefinedField { value: container_value, value_position: container_position, property: field.inner, @@ -1130,7 +1130,7 @@ pub enum RuntimeError { identifier: Identifier, position: Span, }, - UndefinedProperty { + UndefinedField { value: Value, value_position: Span, property: Identifier, @@ -1175,7 +1175,7 @@ impl RuntimeError { } => (start_position.0, end_position.1), Self::UndefinedType { position, .. } => *position, - Self::UndefinedProperty { + Self::UndefinedField { property_position, .. } => *property_position, } @@ -1326,7 +1326,7 @@ impl Display for RuntimeError { "Identifier \"{identifier}\" is not associated with a value or constructor" ) } - Self::UndefinedProperty { + Self::UndefinedField { value, property, .. } => { write!(f, "Value {} does not have the property {}", value, property) @@ -1672,14 +1672,14 @@ mod tests { #[test] fn is_even() { - let input = "is_even(42)"; + let input = "42.is_even"; assert_eq!(run(input), Ok(Some(Value::Boolean(true)))); } #[test] fn is_odd() { - let input = "is_odd(42)"; + let input = "42.is_odd"; assert_eq!(run(input), Ok(Some(Value::Boolean(false)))); }