diff --git a/src/abstract_tree/assignment.rs b/src/abstract_tree/assignment.rs index a08575a..178a5a2 100644 --- a/src/abstract_tree/assignment.rs +++ b/src/abstract_tree/assignment.rs @@ -14,7 +14,6 @@ pub struct Assignment { type_specification: Option, operator: AssignmentOperator, statement: Statement, - syntax_position: SourcePosition, } diff --git a/src/abstract_tree/enum_defintion.rs b/src/abstract_tree/enum_defintion.rs index b49f88e..45b21d9 100644 --- a/src/abstract_tree/enum_defintion.rs +++ b/src/abstract_tree/enum_defintion.rs @@ -27,7 +27,7 @@ impl EnumDefinition { } } - pub fn instantiate(&self, variant: String, content: Value) -> EnumInstance { + pub fn instantiate(&self, variant: String, content: Option) -> EnumInstance { EnumInstance::new(self.identifier.inner().clone(), variant, content) } diff --git a/src/abstract_tree/match.rs b/src/abstract_tree/match.rs index 81902ab..0c95cf7 100644 --- a/src/abstract_tree/match.rs +++ b/src/abstract_tree/match.rs @@ -89,9 +89,11 @@ impl AbstractTree for Match { { let statement_context = Context::with_variables_from(context)?; - if let Some(identifier) = enum_pattern.inner_identifier() { + if let (Some(identifier), Some(value)) = + (enum_pattern.inner_identifier(), enum_instance.value()) + { statement_context - .set_value(identifier.inner().clone(), enum_instance.value().clone())?; + .set_value(identifier.inner().clone(), value.as_ref().clone())?; } return statement.run(source, &statement_context); diff --git a/src/abstract_tree/type.rs b/src/abstract_tree/type.rs index 053d6c9..5058e59 100644 --- a/src/abstract_tree/type.rs +++ b/src/abstract_tree/type.rs @@ -3,6 +3,7 @@ use std::fmt::{self, Display, Formatter}; use serde::{Deserialize, Serialize}; use crate::{ + built_in_types::BuiltInType, error::{RuntimeError, SyntaxError, ValidationError}, AbstractTree, Context, Format, Identifier, SyntaxNode, Value, }; @@ -13,6 +14,10 @@ pub enum Type { Boolean, Collection, Custom(Identifier), + CustomWithArgument { + name: Identifier, + argument: Box, + }, Float, Function { parameter_types: Vec, @@ -21,14 +26,17 @@ pub enum Type { Integer, List(Box), Map, - None, Number, String, Range, - Option(Box), + None, } impl Type { + pub fn option(inner_type: Option) -> Self { + BuiltInType::Option.get(inner_type).clone() + } + pub fn list(item_type: Type) -> Self { Type::List(Box::new(item_type)) } @@ -40,10 +48,6 @@ impl Type { } } - pub fn option(optional_type: Type) -> Self { - Type::Option(Box::new(optional_type)) - } - /// Returns a boolean indicating whether is type is accepting of the other. /// /// The types do not need to match exactly. For example, the Any variant matches all of the @@ -70,17 +74,22 @@ impl Type { | (Type::Number, Type::Float) | (Type::Integer, Type::Number) | (Type::Float, Type::Number) - | (Type::None, Type::None) | (Type::String, Type::String) => true, (Type::Custom(left), Type::Custom(right)) => left == right, - (Type::Option(_), Type::None) => true, - (Type::Option(left), Type::Option(right)) => { - if let Type::Any = left.as_ref() { - true - } else if left == right { - true - } else { + ( + Type::CustomWithArgument { + name: left_name, + argument: left_argument, + }, + Type::CustomWithArgument { + name: right_name, + argument: right_argument, + }, + ) => { + if left_name != right_name { false + } else { + left_argument == right_argument } } (Type::List(self_item_type), Type::List(other_item_type)) => { @@ -136,7 +145,21 @@ impl AbstractTree for Type { let type_node = node.child(0).unwrap(); let r#type = match type_node.kind() { - "identifier" => Type::Custom(Identifier::from_syntax(type_node, _source, _context)?), + "identifier" => { + if node.child_count() == 1 { + Type::Custom(Identifier::from_syntax(type_node, _source, _context)?) + } else { + let name = Identifier::from_syntax(type_node, _source, _context)?; + + let argument_node = node.child(2).unwrap(); + let argument = Type::from_syntax(argument_node, _source, _context)?; + + Type::CustomWithArgument { + name, + argument: Box::new(argument), + } + } + } "[" => { let item_type_node = node.child(1).unwrap(); let item_type = Type::from_syntax(item_type_node, _source, _context)?; @@ -165,7 +188,7 @@ impl AbstractTree for Type { let return_type = if final_node.is_named() { Type::from_syntax(final_node, _source, _context)? } else { - Type::None + Type::option(None) }; Type::Function { @@ -178,16 +201,9 @@ impl AbstractTree for Type { "num" => Type::Number, "none" => Type::None, "str" => Type::String, - "option" => { - let inner_type_node = node.child(2).unwrap(); - let inner_type = Type::from_syntax(inner_type_node, _source, _context)?; - - Type::Option(Box::new(inner_type)) - } _ => { return Err(SyntaxError::UnexpectedSyntaxNode { - expected: "any, bool, float, int, num, str, option, custom type, (, [ or {" - .to_string(), + expected: "any, bool, float, int, num, str, custom type, (, [ or {".to_string(), actual: type_node.kind().to_string(), location: type_node.start_position(), relevant_source: _source[type_node.byte_range()].to_string(), @@ -217,8 +233,11 @@ impl Format for Type { Type::Any => output.push_str("any"), Type::Boolean => output.push_str("bool"), Type::Collection => output.push_str("collection"), - Type::Custom(_) => todo!(), + Type::CustomWithArgument { + name: _, + argument: _, + } => todo!(), Type::Float => output.push_str("float"), Type::Function { parameter_types, @@ -246,14 +265,9 @@ impl Format for Type { Type::Map => { output.push_str("map"); } - Type::None => output.push_str("none"), + Type::None => output.push_str("Option::None"), Type::Number => output.push_str("num"), Type::String => output.push_str("str"), - Type::Option(optional_type) => { - output.push_str("option("); - optional_type.format(output, indent_level); - output.push(')'); - } Type::Range => todo!(), } } @@ -266,6 +280,9 @@ impl Display for Type { Type::Boolean => write!(f, "bool"), Type::Collection => write!(f, "collection"), Type::Custom(identifier) => write!(f, "{identifier}"), + Type::CustomWithArgument { name, argument } => { + write!(f, "{name}<{argument}>") + } Type::Float => write!(f, "float"), Type::Function { parameter_types, @@ -290,9 +307,6 @@ impl Display for Type { Type::Number => write!(f, "num"), Type::None => write!(f, "none"), Type::String => write!(f, "str"), - Type::Option(inner_type) => { - write!(f, "option({})", inner_type) - } Type::Range => todo!(), } } diff --git a/src/abstract_tree/value_node.rs b/src/abstract_tree/value_node.rs index 3da7b0b..de0312a 100644 --- a/src/abstract_tree/value_node.rs +++ b/src/abstract_tree/value_node.rs @@ -17,7 +17,6 @@ pub enum ValueNode { Integer(String), String(String), List(Vec), - Option(Option>), Map(MapNode), Range(RangeInclusive), Struct { @@ -68,18 +67,6 @@ impl AbstractTree for ValueNode { "map" => { ValueNode::Map(MapNode::from_syntax(child, source, context)?) } - "option" => { - let first_grandchild = child.child(0).unwrap(); - - if first_grandchild.kind() == "none" { - ValueNode::Option(None) - } else { - let expression_node = child.child(2).unwrap(); - let expression = Expression::from_syntax(expression_node, source, context)?; - - ValueNode::Option(Some(Box::new(expression))) - } - } "range" => { let mut split = source[child.byte_range()].split(".."); let start = split.next().unwrap().parse().unwrap(); @@ -158,19 +145,21 @@ impl AbstractTree for ValueNode { Type::List(Box::new(Type::Any)) } } - ValueNode::Option(option) => { - if let Some(expression) = option { - Type::Option(Box::new(expression.expected_type(context)?)) - } else { - Type::None - } - } ValueNode::Map(_) => Type::Map, ValueNode::Struct { name, .. } => { Type::Custom(name.clone()) } ValueNode::Range(_) => Type::Range, - ValueNode::Enum { name, .. } => Type::Custom(name.clone()), + ValueNode::Enum { name, variant: _, expression } => { + if let Some(expression) = expression { + Type::CustomWithArgument { + name: name.clone(), + argument: Box::new(expression.expected_type(context)?) + } + } else { + Type::Custom(name.clone()) + } + }, }; Ok(r#type) @@ -212,15 +201,6 @@ impl AbstractTree for ValueNode { Value::List(List::with_items(values)) } - ValueNode::Option(option) => { - let option_value = if let Some(expression) = option { - Some(Box::new(expression.run(source, context)?)) - } else { - None - }; - - Value::Option(option_value) - } ValueNode::Map(map_node) => map_node.run(source, context)?, ValueNode::Range(range) => Value::Range(range.clone()), ValueNode::Struct { name, properties } => { @@ -247,7 +227,7 @@ impl AbstractTree for ValueNode { }; let instance = if let Some(definition) = context.get_definition(name.inner())? { if let TypeDefinition::Enum(enum_defintion) = definition { - enum_defintion.instantiate(variant.inner().clone(), value) + enum_defintion.instantiate(variant.inner().clone(), Some(value)) } else { return Err(RuntimeError::ValidationFailure( ValidationError::ExpectedEnumDefintion { @@ -290,15 +270,6 @@ impl Format for ValueNode { output.push(']'); } - ValueNode::Option(option) => { - if let Some(expression) = option { - output.push_str("some("); - expression.format(output, indent_level); - output.push(')'); - } else { - output.push_str("none"); - } - } ValueNode::Map(map_node) => map_node.format(output, indent_level), ValueNode::Struct { name, properties } => { name.format(output, indent_level); @@ -325,8 +296,6 @@ impl Ord for ValueNode { (ValueNode::String(_), _) => Ordering::Greater, (ValueNode::List(left), ValueNode::List(right)) => left.cmp(right), (ValueNode::List(_), _) => Ordering::Greater, - (ValueNode::Option(left), ValueNode::Option(right)) => left.cmp(right), - (ValueNode::Option(_), _) => Ordering::Greater, (ValueNode::Map(left), ValueNode::Map(right)) => left.cmp(right), (ValueNode::Map(_), _) => Ordering::Greater, (ValueNode::Struct{ name: left_name, properties: left_properties }, ValueNode::Struct {name: right_name, properties: right_properties} ) => { diff --git a/src/built_in_functions/mod.rs b/src/built_in_functions/mod.rs index 9832a4b..6462ad6 100644 --- a/src/built_in_functions/mod.rs +++ b/src/built_in_functions/mod.rs @@ -103,13 +103,13 @@ impl Callable for BuiltInFunction { Value::Enum(EnumInstance::new( "Result".to_string(), "Ok".to_string(), - Value::none(), + Some(Value::none()), )) } else { Value::Enum(EnumInstance::new( "Result".to_string(), "Error".to_string(), - Value::none(), + Some(Value::none()), )) }; diff --git a/src/built_in_functions/str.rs b/src/built_in_functions/str.rs index af4204a..9ef4eed 100644 --- a/src/built_in_functions/str.rs +++ b/src/built_in_functions/str.rs @@ -1,7 +1,7 @@ use enum_iterator::Sequence; use serde::{Deserialize, Serialize}; -use crate::{error::RuntimeError, Context, List, Type, Value}; +use crate::{error::RuntimeError, Context, EnumInstance, List, Type, Value}; use super::Callable; @@ -122,7 +122,7 @@ impl Callable for StrFunction { } StrFunction::Find => Type::function( vec![Type::String, Type::String], - Type::option(Type::Integer), + Type::option(Some(Type::Integer)), ), StrFunction::Insert => Type::function( vec![Type::String, Type::Integer, Type::String], @@ -137,7 +137,7 @@ impl Callable for StrFunction { StrFunction::Parse => Type::function(vec![Type::String], Type::Any), StrFunction::Remove => Type::function( vec![Type::String, Type::Integer], - Type::option(Type::String), + Type::option(Some(Type::String)), ), StrFunction::ReplaceRange => Type::function( vec![Type::String, Type::list(Type::Integer), Type::String], @@ -175,9 +175,10 @@ impl Callable for StrFunction { StrFunction::StartsWith => { Type::function(vec![Type::String, Type::String], Type::Boolean) } - StrFunction::StripPrefix => { - Type::function(vec![Type::String, Type::String], Type::option(Type::String)) - } + StrFunction::StripPrefix => Type::function( + vec![Type::String, Type::String], + Type::option(Some(Type::String)), + ), StrFunction::ToLowercase => Type::function(vec![Type::String], Type::String), StrFunction::ToUppercase => Type::function(vec![Type::String], Type::String), StrFunction::Truncate => { @@ -233,9 +234,21 @@ impl Callable for StrFunction { let pattern = pattern_string.as_str(); let find = string .find(pattern) - .map(|index| Box::new(Value::Integer(index as i64))); + .map(|index| Value::Integer(index as i64)); - Value::Option(find) + if let Some(index) = find { + Value::Enum(EnumInstance::new( + "Option".to_string(), + "Some".to_string(), + Some(index), + )) + } else { + Value::Enum(EnumInstance::new( + "Option".to_string(), + "None".to_string(), + Some(Value::none()), + )) + } } StrFunction::IsAscii => { RuntimeError::expect_argument_amount(self.name(), 1, arguments.len())?; @@ -292,9 +305,9 @@ impl Callable for StrFunction { let string = arguments.first().unwrap().as_string()?; if let Ok(integer) = string.parse::() { - Value::option(Some(Value::Integer(integer))) + Value::Integer(integer) } else if let Ok(float) = string.parse::() { - Value::option(Some(Value::Float(float))) + Value::Float(float) } else { Value::none() } @@ -413,7 +426,11 @@ impl Callable for StrFunction { ])) }); - Value::option(sections) + if let Some(sections) = sections { + Value::some(sections) + } else { + Value::none() + } } StrFunction::SplitTerminator => { RuntimeError::expect_argument_amount(self.name(), 2, arguments.len())?; @@ -458,7 +475,15 @@ impl Callable for StrFunction { .strip_prefix(prefix) .map(|remainder| Value::string(remainder.to_string())); - Value::option(stripped) + if let Some(value) = stripped { + Value::Enum(EnumInstance::new( + "Option".to_string(), + "Some".to_string(), + Some(value), + )) + } else { + Value::none() + } } StrFunction::ToLowercase => { RuntimeError::expect_argument_amount(self.name(), 1, arguments.len())?; diff --git a/src/built_in_types.rs b/src/built_in_types.rs new file mode 100644 index 0000000..a12ae3d --- /dev/null +++ b/src/built_in_types.rs @@ -0,0 +1,36 @@ +use std::sync::OnceLock; + +use enum_iterator::Sequence; +use serde::{Deserialize, Serialize}; + +use crate::{Identifier, Type}; + +static OPTION: OnceLock = OnceLock::new(); + +#[derive(Sequence, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] +pub enum BuiltInType { + Option, +} + +impl BuiltInType { + pub fn name(&self) -> &'static str { + match self { + BuiltInType::Option => todo!(), + } + } + + pub fn get(&self, inner_type: Option) -> &Type { + match self { + BuiltInType::Option => OPTION.get_or_init(|| { + if let Some(inner_type) = inner_type { + Type::CustomWithArgument { + name: Identifier::new("Option"), + argument: Box::new(inner_type), + } + } else { + Type::Custom(Identifier::new("Option")) + } + }), + } + } +} diff --git a/src/built_in_values.rs b/src/built_in_values.rs index e6c477b..f502601 100644 --- a/src/built_in_values.rs +++ b/src/built_in_values.rs @@ -6,7 +6,8 @@ use serde::{Deserialize, Serialize}; use crate::{ built_in_functions::{fs::fs_functions, json::json_functions, str::string_functions, Callable}, error::{RuntimeError, SyntaxError, ValidationError}, - AbstractTree, BuiltInFunction, Context, Format, Function, List, Map, SyntaxNode, Type, Value, + AbstractTree, BuiltInFunction, Context, EnumInstance, Format, Function, Identifier, List, Map, + SyntaxNode, Type, Value, }; static ARGS: OnceLock = OnceLock::new(); @@ -14,6 +15,7 @@ static FS: OnceLock = OnceLock::new(); static JSON: OnceLock = OnceLock::new(); static RANDOM: OnceLock = OnceLock::new(); static STRING: OnceLock = OnceLock::new(); +static NONE: OnceLock = OnceLock::new(); /// Returns the entire built-in value API. pub fn all_built_in_values() -> impl Iterator { @@ -38,6 +40,9 @@ pub enum BuiltInValue { /// Get the length of a collection. Length, + /// The absence of a value. + None, + /// Print a value to stdout. Output, @@ -57,6 +62,7 @@ impl BuiltInValue { BuiltInValue::Fs => "fs", BuiltInValue::Json => "json", BuiltInValue::Length => BuiltInFunction::Length.name(), + BuiltInValue::None => "None", BuiltInValue::Output => "output", BuiltInValue::Random => "random", BuiltInValue::Str => "str", @@ -73,6 +79,7 @@ impl BuiltInValue { BuiltInValue::Fs => "File and directory tools.", BuiltInValue::Json => "JSON formatting tools.", BuiltInValue::Length => BuiltInFunction::Length.description(), + BuiltInValue::None => "The absence of a value.", BuiltInValue::Output => "output", BuiltInValue::Random => "random", BuiltInValue::Str => "string", @@ -89,6 +96,7 @@ impl BuiltInValue { BuiltInValue::Fs => Type::Map, BuiltInValue::Json => Type::Map, BuiltInValue::Length => BuiltInFunction::Length.r#type(), + BuiltInValue::None => Type::Custom(Identifier::new("Option")), BuiltInValue::Output => BuiltInFunction::Output.r#type(), BuiltInValue::Random => Type::Map, BuiltInValue::Str => Type::Map, @@ -134,6 +142,13 @@ impl BuiltInValue { Value::Map(Map::with_values(json_context)) }), BuiltInValue::Length => &Value::Function(Function::BuiltIn(BuiltInFunction::Length)), + BuiltInValue::None => NONE.get_or_init(|| { + Value::Enum(EnumInstance::new( + "Option".to_string(), + "None".to_string(), + None, + )) + }), BuiltInValue::Output => &Value::Function(Function::BuiltIn(BuiltInFunction::Output)), BuiltInValue::Random => RANDOM.get_or_init(|| { let mut random_context = BTreeMap::new(); diff --git a/src/lib.rs b/src/lib.rs index 3bd66cd..d7d7bb6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,6 +18,7 @@ pub use tree_sitter::Node as SyntaxNode; pub mod abstract_tree; pub mod built_in_functions; pub mod built_in_type_definitions; +pub mod built_in_types; pub mod built_in_values; pub mod context; pub mod error; diff --git a/src/value/enum_instance.rs b/src/value/enum_instance.rs index 020e7bd..df3d089 100644 --- a/src/value/enum_instance.rs +++ b/src/value/enum_instance.rs @@ -1,20 +1,22 @@ use std::fmt::{self, Display, Formatter}; +use serde::{Deserialize, Serialize}; + use crate::Value; -#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord)] +#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub struct EnumInstance { name: String, variant_name: String, - value: Box, + value: Option>, } impl EnumInstance { - pub fn new(name: String, variant_name: String, value: Value) -> Self { + pub fn new(name: String, variant_name: String, value: Option) -> Self { Self { name, variant_name, - value: Box::new(value), + value: value.map(|value| Box::new(value)), } } @@ -26,13 +28,13 @@ impl EnumInstance { &self.variant_name } - pub fn value(&self) -> &Value { + pub fn value(&self) -> &Option> { &self.value } } impl Display for EnumInstance { fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "{}::{}({})", self.name, self.variant_name, self.value) + write!(f, "{}::{}({:?})", self.name, self.variant_name, self.value) } } diff --git a/src/value/mod.rs b/src/value/mod.rs index 1030dff..c7bfb1a 100644 --- a/src/value/mod.rs +++ b/src/value/mod.rs @@ -1,5 +1,7 @@ //! Types that represent runtime values. -use crate::{error::RuntimeError, Identifier, Type, TypeSpecification}; +use crate::{ + built_in_values::BuiltInValue, error::RuntimeError, Identifier, Type, TypeSpecification, +}; use serde::{ de::{MapAccess, SeqAccess, Visitor}, @@ -42,18 +44,23 @@ pub enum Value { Integer(i64), Boolean(bool), Range(RangeInclusive), - Option(Option>), Struct(StructInstance), Enum(EnumInstance), } -impl Default for Value { - fn default() -> Self { - Value::none() - } -} - impl Value { + pub fn none() -> Self { + BuiltInValue::None.get().clone() + } + + pub fn some(value: Value) -> Value { + Value::Enum(EnumInstance::new( + "Option".to_string(), + "Some".to_string(), + Some(value), + )) + } + pub fn string>(string: T) -> Self { Value::String(string.into()) } @@ -102,31 +109,12 @@ impl Value { Value::Float(_) => Type::Float, Value::Integer(_) => Type::Integer, Value::Boolean(_) => Type::Boolean, - Value::Option(option) => { - if let Some(value) = option { - Type::Option(Box::new(value.r#type())) - } else { - Type::None - } - } Value::Range(_) => todo!(), Value::Struct(_) => todo!(), Value::Enum(_) => todo!(), } } - pub fn none() -> Self { - Value::Option(None) - } - - pub fn some(value: Value) -> Self { - Value::Option(Some(Box::new(value))) - } - - pub fn option(option: Option) -> Self { - Value::Option(option.map(Box::new)) - } - pub fn is_string(&self) -> bool { matches!(self, Value::String(_)) } @@ -151,14 +139,6 @@ impl Value { matches!(self, Value::List(_)) } - pub fn is_option(&self) -> bool { - matches!(self, Value::Option(_)) - } - - pub fn is_none(&self) -> bool { - matches!(self, Value::Option(None)) - } - pub fn is_map(&self) -> bool { matches!(self, Value::Map(_)) } @@ -167,6 +147,10 @@ impl Value { matches!(self, Value::Function(_)) } + pub fn is_none(&self) -> bool { + self == &Value::none() + } + /// Borrows the value stored in `self` as `&String`, or returns `Err` if `self` is not a `Value::String`. pub fn as_string(&self) -> Result<&String, RuntimeError> { match self { @@ -259,39 +243,17 @@ impl Value { }), } } +} - /// Returns `Option`, or returns `Err` if `self` is not a `Value::Option`. - pub fn as_option(&self) -> Result<&Option>, RuntimeError> { - match self { - Value::Option(option) => Ok(option), - value => Err(RuntimeError::ExpectedOption { - actual: value.clone(), - }), - } - } - - /// Returns `()`, or returns `Err` if `self` is not a `Value::none()`. - pub fn as_none(&self) -> Result<(), RuntimeError> { - match self { - Value::Option(option) => { - if option.is_none() { - Ok(()) - } else { - Err(RuntimeError::ExpectedNone { - actual: self.clone(), - }) - } - } - value => Err(RuntimeError::ExpectedNone { - actual: value.clone(), - }), - } +impl Default for Value { + fn default() -> Self { + Value::none() } } impl Default for &Value { fn default() -> Self { - &Value::Option(None) + BuiltInValue::None.get() } } @@ -445,7 +407,6 @@ impl PartialEq for Value { (Value::List(left), Value::List(right)) => left == right, (Value::Map(left), Value::Map(right)) => left == right, (Value::Function(left), Value::Function(right)) => left == right, - (Value::Option(left), Value::Option(right)) => left == right, (Value::Range(left), Value::Range(right)) => left == right, (Value::Struct(left), Value::Struct(right)) => left == right, (Value::Enum(left), Value::Enum(right)) => left == right, @@ -495,9 +456,7 @@ impl Ord for Value { left_len.cmp(&right_len) } - (Value::Range(_), _) => Ordering::Greater, - (Value::Option(left), Value::Option(right)) => left.cmp(right), - (Value::Option(_), _) => Ordering::Less, + (Value::Range(_), _) => Ordering::Less, } } } @@ -522,7 +481,6 @@ impl Serialize for Value { list.end() } - Value::Option(inner) => inner.serialize(serializer), Value::Map(map) => { let entries = map.inner(); let mut map = serializer.serialize_map(Some(entries.len()))?; @@ -548,13 +506,6 @@ impl Display for Value { Value::Float(float) => write!(f, "{float}"), Value::Integer(int) => write!(f, "{int}"), Value::Boolean(boolean) => write!(f, "{boolean}"), - Value::Option(option) => { - if let Some(value) = option { - write!(f, "some({})", value) - } else { - write!(f, "none") - } - } Value::List(list) => write!(f, "{list}"), Value::Map(map) => write!(f, "{map}"), Value::Function(function) => write!(f, "{function}"), @@ -839,9 +790,7 @@ impl<'de> Visitor<'de> for ValueVisitor { where D: serde::Deserializer<'de>, { - Ok(Value::Option(Some(Box::new(Value::deserialize( - deserializer, - )?)))) + Ok(Value::Enum(EnumInstance::deserialize(deserializer)?)) } fn visit_unit(self) -> std::result::Result diff --git a/tests/built_in_string_functions.rs b/tests/built_in_string_functions.rs index 095e396..dc8109c 100644 --- a/tests/built_in_string_functions.rs +++ b/tests/built_in_string_functions.rs @@ -29,11 +29,11 @@ fn ends_with() { fn find() { let result = interpret("str:find('abc', 'a')"); - assert_eq!(result, Ok(Value::Option(Some(Box::new(Value::Integer(0)))))); + assert_eq!(result, Ok(Value::some(Value::Integer(0)))); let result = interpret("str:find('foobar', 'b')"); - assert_eq!(result, Ok(Value::Option(Some(Box::new(Value::Integer(3)))))); + assert_eq!(result, Ok(Value::some(Value::Integer(3)))); } #[test] diff --git a/tests/built_in_type_definitions.rs b/tests/built_in_type_definitions.rs index 0edebc9..c4c7f62 100644 --- a/tests/built_in_type_definitions.rs +++ b/tests/built_in_type_definitions.rs @@ -7,7 +7,7 @@ fn option() { Ok(Value::Enum(EnumInstance::new( "Option".to_string(), "None".to_string(), - Value::none() + Some(Value::none()), ))) ); assert_eq!( @@ -21,7 +21,7 @@ fn option() { Ok(Value::Enum(EnumInstance::new( "Option".to_string(), "Some".to_string(), - Value::Integer(1), + Some(Value::Integer(1)), ))) ); } @@ -33,7 +33,7 @@ fn result() { Ok(Value::Enum(EnumInstance::new( "Result".to_string(), "Ok".to_string(), - Value::Integer(1) + Some(Value::Integer(1)), ))) ); assert_eq!( @@ -46,7 +46,7 @@ fn result() { Ok(Value::Enum(EnumInstance::new( "Result".to_string(), "Error".to_string(), - Value::String("uh-oh!".to_string()) + Some(Value::String("uh-oh!".to_string())), ))) ); } diff --git a/tests/built_in_values.rs b/tests/built_in_values.rs index 9da65b2..54a87b0 100644 --- a/tests/built_in_values.rs +++ b/tests/built_in_values.rs @@ -18,7 +18,7 @@ fn assert_equal() { Ok(Value::Enum(EnumInstance::new( "Result".to_string(), "Ok".to_string(), - Value::none() + Some(Value::none()), ))) ); assert_eq!( @@ -26,7 +26,7 @@ fn assert_equal() { Ok(Value::Enum(EnumInstance::new( "Result".to_string(), "Error".to_string(), - Value::none() + Some(Value::none()), ))) ); } diff --git a/tests/enums.rs b/tests/enums.rs index 7b7b800..29e149e 100644 --- a/tests/enums.rs +++ b/tests/enums.rs @@ -18,7 +18,7 @@ fn simple_enum() { Ok(Value::Enum(EnumInstance::new( "Foobar".to_string(), "Foo".to_string(), - Value::none() + Some(Value::none()) ))) ); } @@ -45,11 +45,11 @@ fn nested_enum() { Ok(Value::Enum(EnumInstance::new( "Foobar".to_string(), "Bar".to_string(), - Value::Enum(EnumInstance::new( + Some(Value::Enum(EnumInstance::new( "Fizzbuzz".to_string(), "Fizz".to_string(), - Value::none() - )) + Some(Value::none()) + ))) ))) ); } diff --git a/tests/functions.rs b/tests/functions.rs index acb656f..4df92cc 100644 --- a/tests/functions.rs +++ b/tests/functions.rs @@ -43,7 +43,7 @@ fn callback() { #[test] fn built_in_function_call() { - assert_eq!(interpret("output('Hiya')"), Ok(Value::Option(None))); + assert_eq!(interpret("output('Hiya')"), Ok(Value::none())); } #[test] diff --git a/tests/value.rs b/tests/value.rs index 5789a9b..626731e 100644 --- a/tests/value.rs +++ b/tests/value.rs @@ -2,8 +2,8 @@ use dust_lang::*; #[test] fn empty() { - assert_eq!(interpret("x = 9"), Ok(Value::Option(None))); - assert_eq!(interpret("x = 1 + 1"), Ok(Value::Option(None))); + assert_eq!(interpret("x = 9"), Ok(Value::none())); + assert_eq!(interpret("x = 1 + 1"), Ok(Value::none())); } #[test] diff --git a/tests/while.rs b/tests/while.rs index 380f666..08d8032 100644 --- a/tests/while.rs +++ b/tests/while.rs @@ -2,7 +2,7 @@ use dust_lang::*; #[test] fn while_loop() { - assert_eq!(interpret("while false { 'foo' }"), Ok(Value::Option(None))) + assert_eq!(interpret("while false { 'foo' }"), Ok(Value::none())) } #[test] diff --git a/tree-sitter-dust/grammar.js b/tree-sitter-dust/grammar.js index 928beb9..3d0dc84 100644 --- a/tree-sitter-dust/grammar.js +++ b/tree-sitter-dust/grammar.js @@ -380,12 +380,6 @@ module.exports = grammar({ ')', optional(seq('->', $.type)), ), - seq( - 'option', - '(', - $.type, - ')', - ), ), ),